aboutsummaryrefslogtreecommitdiff
path: root/kernel/drivers/tty
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2024-03-02 23:05:26 +0000
committersotech117 <michael_foiani@brown.edu>2024-03-02 23:05:26 +0000
commit8c2e0ce946012a4275e8dfa9d8dfd1d5a68d6e3e (patch)
tree1877a33c6488a5b16fb7962e1ffb0f72f13a5052 /kernel/drivers/tty
parent9c90e73fda0d5df2e1f11b32d459d3bb07a63192 (diff)
decent coding session
Diffstat (limited to 'kernel/drivers/tty')
-rw-r--r--kernel/drivers/tty/ldisc.c165
-rw-r--r--kernel/drivers/tty/tty.c48
2 files changed, 201 insertions, 12 deletions
diff --git a/kernel/drivers/tty/ldisc.c b/kernel/drivers/tty/ldisc.c
index eaf0440..dd67706 100644
--- a/kernel/drivers/tty/ldisc.c
+++ b/kernel/drivers/tty/ldisc.c
@@ -16,7 +16,19 @@
*/
void ldisc_init(ldisc_t *ldisc)
{
- NOT_YET_IMPLEMENTED("DRIVERS: ldisc_init");
+ // NOT_YET_IMPLEMENTED("DRIVERS: ldisc_init");
+
+ // reset static buffer
+ memset(ldisc->ldisc_buffer, 0, LDISC_BUFFER_SIZE);
+
+ // init the queue
+ sched_queue_init(&ldisc->ldisc_read_queue);
+
+ // fill in other fields
+ ldisc->ldisc_head = 0;
+ ldisc->ldisc_tail = 0;
+ ldisc->ldisc_cooked = 0;
+ ldisc->ldisc_full = 0; // 0 not full
}
/**
@@ -33,8 +45,31 @@ void ldisc_init(ldisc_t *ldisc)
*/
long ldisc_wait_read(ldisc_t *ldisc)
{
- NOT_YET_IMPLEMENTED("DRIVERS: ldisc_wait_read");
- return -1;
+ // NOT_YET_IMPLEMENTED("DRIVERS: ldisc_wait_read");
+
+ // if it's full, return 0
+ if (ldisc->ldisc_full)
+ {
+ return 0;
+ }
+
+ // while there are no need chars to be read, sleep
+ // TODO: check if this is the right condition
+ while (
+ (ldisc->ldisc_head == ldisc->ldisc_tail)
+ ||
+ (ldisc->ldisc_head == ldisc->ldisc_cooked)
+ )
+ {
+ long ret = sched_cancellable_sleep_on(&ldisc->ldisc_read_queue);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ }
+
+ // if we are here, it means we have new chars to read
+ return 0;
}
/**
@@ -54,8 +89,51 @@ long ldisc_wait_read(ldisc_t *ldisc)
*/
size_t ldisc_read(ldisc_t *ldisc, char *buf, size_t count)
{
- NOT_YET_IMPLEMENTED("DRIVERS: ldisc_read");
- return 0;
+ // NOT_YET_IMPLEMENTED("DRIVERS: ldisc_read");
+
+ // read from ldisc buffer to buf
+ size_t i = 0;
+ while (i < count)
+ {
+ // if we have new chars to read
+ if (ldisc->ldisc_head != ldisc->ldisc_tail)
+ {
+ // if we encounter a new line symbol
+ if (ldisc->ldisc_buffer[ldisc->ldisc_head] == '\n')
+ {
+ buf[i] = ldisc->ldisc_buffer[ldisc->ldisc_head];
+ ldisc->ldisc_head = (ldisc->ldisc_head + 1) % LDISC_BUFFER_SIZE;
+ i++;
+ break;
+ }
+ // if we encounter an EOT
+ else if (ldisc->ldisc_buffer[ldisc->ldisc_head] == EOT)
+ {
+ break;
+ }
+ // if we encounter an ETX
+ else if (ldisc->ldisc_buffer[ldisc->ldisc_head] == ETX)
+ {
+ // clear uncooked portion of the line
+ ldisc->ldisc_head = ldisc->ldisc_cooked;
+ break;
+ }
+ // if we encounter a normal char
+ else
+ {
+ buf[i] = ldisc->ldisc_buffer[ldisc->ldisc_head];
+ ldisc->ldisc_head = (ldisc->ldisc_head + 1) % LDISC_BUFFER_SIZE;
+ i++;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // return the number of bytes read
+ return i;
}
/**
@@ -103,7 +181,66 @@ size_t ldisc_read(ldisc_t *ldisc, char *buf, size_t count)
*/
void ldisc_key_pressed(ldisc_t *ldisc, char c)
{
- NOT_YET_IMPLEMENTED("DRIVERS: ldisc_key_pressed");
+ // NOT_YET_IMPLEMENTED("DRIVERS: ldisc_key_pressed");
+
+ // if the buffer is full, ignore the incoming char
+ if (ldisc->ldisc_full)
+ {
+ return;
+ }
+
+ switch (c)
+ {
+ case '\b':
+ // if there is a character to remove
+ if (ldisc->ldisc_head != ldisc->ldisc_tail)
+ {
+ // remove the last char
+ ldisc->ldisc_head = (ldisc->ldisc_head - 1 + LDISC_BUFFER_SIZE) % LDISC_BUFFER_SIZE;
+ // emit a `\b` to the vterminal
+ vterminal_write(ldisc_to_tty(ldisc), "\b", 1);
+ }
+ break;
+
+ case '\n':
+ // emit a `\n` to the vterminal
+ vterminal_write(ldisc_to_tty(ldisc), "\n", 1);
+
+ // add the new char to the buffer
+ ldisc->ldisc_buffer[ldisc->ldisc_tail] = c;
+ ldisc->ldisc_tail = (ldisc->ldisc_tail + 1) % LDISC_BUFFER_SIZE;
+ // set the buffer to full
+ ldisc->ldisc_full = 1;
+
+ // wake up the thread that is sleeping on the wait queue of the line discipline
+ sched_wakeup_on(&ldisc->ldisc_read_queue, 0);
+ break;
+
+ case EOT:
+ // add the new char to the buffer
+ ldisc->ldisc_buffer[ldisc->ldisc_tail] = c;
+ ldisc->ldisc_tail = (ldisc->ldisc_tail + 1) % LDISC_BUFFER_SIZE;
+ // set the buffer to full
+ ldisc->ldisc_full = 1;
+
+ // cook the buffer
+ ldisc->ldisc_cooked = ldisc->ldisc_tail;
+
+ // wake up the thread that is sleeping on the wait queue of the line discipline
+ sched_wakeup_on(&ldisc->ldisc_read_queue, 0);
+ break;
+
+ case ETX:
+ // clear uncooked portion of the line
+ ldisc->ldisc_head = ldisc->ldisc_cooked;
+ break;
+
+ default:
+ // if none applies, fallback to vterminal_key_pressed
+ vterminal_key_pressed(ldisc_to_tty(ldisc));
+
+ break;
+ }
}
/**
@@ -115,6 +252,18 @@ void ldisc_key_pressed(ldisc_t *ldisc, char c)
*/
size_t ldisc_get_current_line_raw(ldisc_t *ldisc, char *s)
{
- NOT_YET_IMPLEMENTED("DRIVERS: ldisc_get_current_line_raw");
- return 0;
+ // NOT_YET_IMPLEMENTED("DRIVERS: ldisc_get_current_line_raw");
+
+ // copy the raw part of the line discipline buffer into the buffer provided
+ size_t i = 0;
+ size_t j = ldisc->ldisc_cooked;
+ while (j != ldisc->ldisc_head)
+ {
+ s[i] = ldisc->ldisc_buffer[j];
+ j = (j + 1) % LDISC_BUFFER_SIZE;
+ i++;
+ }
+
+ // return the number of bytes copied
+ return i;
}
diff --git a/kernel/drivers/tty/tty.c b/kernel/drivers/tty/tty.c
index 3694877..c47a582 100644
--- a/kernel/drivers/tty/tty.c
+++ b/kernel/drivers/tty/tty.c
@@ -69,8 +69,29 @@ void tty_init()
*/
ssize_t tty_read(chardev_t *cdev, size_t pos, void *buf, size_t count)
{
- NOT_YET_IMPLEMENTED("DRIVERS: tty_read");
- return -1;
+ // NOT_YET_IMPLEMENTED("DRIVERS: tty_read");
+
+ // get the mapped tty
+ tty_t *tty = cd_to_tty(cdev);
+
+ // set the IPL to INTR_KEYBOARD
+ uint8_t prev_ipl = intr_setipl(INTR_KEYBOARD);
+
+ // lock the read mutex of the tty
+ kmutex_lock(&tty->tty_read_mutex);
+
+ // wait until there is something in the line discipline's buffer
+ ldisc_wait_read(&tty->tty_ldisc);
+
+ // read from the ldisc's buffer if there are new characters
+ ssize_t bytes_read = ldisc_read(&tty->tty_ldisc, buf, count);
+ // unlock the read mutex of the tty
+ kmutex_unlock(&tty->tty_read_mutex);
+
+ // revert the IPL
+ intr_setipl(prev_ipl);
+
+ return bytes_read;
}
/**
@@ -88,8 +109,27 @@ ssize_t tty_read(chardev_t *cdev, size_t pos, void *buf, size_t count)
*/
ssize_t tty_write(chardev_t *cdev, size_t pos, const void *buf, size_t count)
{
- NOT_YET_IMPLEMENTED("DRIVERS: tty_write");
- return -1;
+ // NOT_YET_IMPLEMENTED("DRIVERS: tty_write");
+
+ // get the mapped tty
+ tty_t *tty = cd_to_tty(cdev);
+
+ // set the IPL to INTR_KEYBOARD
+ uint8_t prev_ipl = intr_setipl(INTR_KEYBOARD);
+
+ // lock the write mutex of the tty
+ kmutex_lock(&tty->tty_write_mutex);
+
+ // write to the terminal
+ size_t bytes_written = vterminal_write(&tty->tty_vterminal, buf, count);
+
+ // unlock the write mutex of the tty
+ kmutex_unlock(&tty->tty_write_mutex);
+ // revert the IPL
+ intr_setipl(prev_ipl);
+
+
+ return bytes_written;
}
static void tty_receive_char_multiplexer(uint8_t c)