diff options
Diffstat (limited to 'kernel/drivers/tty')
| -rw-r--r-- | kernel/drivers/tty/ldisc.c | 209 | ||||
| -rw-r--r-- | kernel/drivers/tty/tty.c | 52 |
2 files changed, 249 insertions, 12 deletions
diff --git a/kernel/drivers/tty/ldisc.c b/kernel/drivers/tty/ldisc.c index eaf0440..9b77433 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,23 @@ 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"); + + // 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 + ) + { + 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 +81,57 @@ 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"); + + dbg(DBG_DISK, "ldisc_read: count = %d\n", count); + + // read from ldisc buffer to buf + size_t i = 0; + int break_loop = 0; + while (i < count && !break_loop) + { + // if we have no new chars to read, break loop + if (ldisc->ldisc_head == ldisc->ldisc_tail) + { + break_loop = 1; + continue; + } + + + char c = ldisc->ldisc_buffer[ldisc->ldisc_tail]; + dbg(DBG_DISK, "ldisc_read: %c\n", c); + switch (c) + { + + case EOT: + buf[i] = c; + ldisc->ldisc_tail = (ldisc->ldisc_tail + 1) % LDISC_BUFFER_SIZE; + break_loop = 1; + break; + + // case ETX: + // ldisc->ldisc_tail = ldisc->ldisc_cooked; + // break; + + case '\n': + buf[i] = c; + ldisc->ldisc_tail = (ldisc->ldisc_tail + 1) % LDISC_BUFFER_SIZE; + i++; + break_loop = 1; + break; + + default: + buf[i] = c; + ldisc->ldisc_tail = (ldisc->ldisc_tail + 1) % LDISC_BUFFER_SIZE; + i++; + break; + } + + dbg(DBG_DISK, "ldisc_read: i = %d\n", i); + } + + // return the number of bytes read + return i; } /** @@ -103,7 +179,112 @@ 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"); + + 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)->tty_vterminal, "\b", 1); + + + if (ldisc->ldisc_full) + { + ldisc->ldisc_full = 0; + } + } + break; + + case '\n': + + // add the new char to the buffer + ldisc->ldisc_buffer[ldisc->ldisc_head] = c; + + if (!ldisc->ldisc_full) + { + ldisc->ldisc_head = (ldisc->ldisc_head + 1) % LDISC_BUFFER_SIZE; + } + + // cook the buffer + ldisc->ldisc_cooked = ldisc->ldisc_head; + + sched_wakeup_on(&ldisc->ldisc_read_queue, 0); + + // emit a `\n` to the vterminal + vterminal_write(&ldisc_to_tty(ldisc)->tty_vterminal, "\n", 1); + + if (ldisc->ldisc_full) + { + ldisc->ldisc_full = 0; + } + break; + + case EOT: + // add the new char to the buffer + dbg(DBG_DISK, "EOT\n"); + ldisc->ldisc_buffer[ldisc->ldisc_head] = c; + if (!ldisc->ldisc_full) + { + ldisc->ldisc_head = (ldisc->ldisc_head + 1) % LDISC_BUFFER_SIZE; + } + + // cook the buffer + ldisc->ldisc_cooked = ldisc->ldisc_head; + + // wake up the thread that is sleeping on the wait queue of the line discipline + sched_wakeup_on(&ldisc->ldisc_read_queue, 0); + + vterminal_write(&ldisc_to_tty(ldisc)->tty_vterminal, "\n", 1); + + if (ldisc->ldisc_full) + { + ldisc->ldisc_full = 0; + } + break; + + case ETX: + // clear uncooked portion of the line + dbg(DBG_DISK, "ETX\n"); + ldisc->ldisc_head = (ldisc->ldisc_cooked + 1) % LDISC_BUFFER_SIZE; + ldisc->ldisc_cooked = ldisc->ldisc_head; + + // wake up the thread that is sleeping on the wait queue of the line discipline + sched_wakeup_on(&ldisc->ldisc_read_queue, 0); + + // emit a `\n` to the vterminal + vterminal_write(&ldisc_to_tty(ldisc)->tty_vterminal, "\n", 1); + break; + + default: + // if the buffer is full, ignore the incoming char + // if (ldisc->ldisc_full) + // { + // return; + // } + + // if none applies, fallback to vterminal_key_pressed + // vterminal_write(ldisc_to_tty(ldisc), &c, 1); + + // update the buffer if it's not full + if (!ldisc->ldisc_full) + { + ldisc->ldisc_buffer[ldisc->ldisc_head] = c; + ldisc->ldisc_head = (ldisc->ldisc_head + 1) % LDISC_BUFFER_SIZE; + if (ldisc->ldisc_head + 1 == ldisc->ldisc_tail) + { + ldisc->ldisc_full = 1; + } + vterminal_key_pressed(&ldisc_to_tty(ldisc)->tty_vterminal); + } + + break; + } } /** @@ -115,6 +296,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..e3c77be 100644 --- a/kernel/drivers/tty/tty.c +++ b/kernel/drivers/tty/tty.c @@ -69,8 +69,33 @@ 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); + + dbg(DBG_DISK, "tty_read: before wait_read\n"); + + // wait until there is something in the line discipline's buffer + ldisc_wait_read(&tty->tty_ldisc); + + dbg(DBG_DISK, "tty_read: after wait_read\n"); + + // 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 +113,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) |
