diff options
Diffstat (limited to 'kernel/drivers/tty/tty.c')
-rw-r--r-- | kernel/drivers/tty/tty.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/kernel/drivers/tty/tty.c b/kernel/drivers/tty/tty.c new file mode 100644 index 0000000..a08df13 --- /dev/null +++ b/kernel/drivers/tty/tty.c @@ -0,0 +1,135 @@ +#include "drivers/tty/tty.h" +#include "drivers/chardev.h" +#include "drivers/dev.h" +#include "drivers/keyboard.h" +#include "kernel.h" +#include "mm/kmalloc.h" +#include "util/debug.h" +#include <errno.h> + +#ifndef NTERMS +#define NTERMS 3 +#endif + +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); + +chardev_ops_t tty_cdev_ops = {.read = tty_read, + .write = tty_write, + .mmap = NULL, + .fill_pframe = NULL, + .flush_pframe = NULL}; + +tty_t *ttys[NTERMS] = {NULL}; + +size_t active_tty; + +static void tty_receive_char_multiplexer(uint8_t c); + +void tty_init() +{ + for (unsigned i = 0; i < NTERMS; i++) + { + tty_t *tty = ttys[i] = kmalloc(sizeof(tty_t)); + vterminal_init(&tty->tty_vterminal); + ldisc_init(&tty->tty_ldisc); + + tty->tty_cdev.cd_id = MKDEVID(TTY_MAJOR, i); + list_link_init(&tty->tty_cdev.cd_link); + tty->tty_cdev.cd_ops = &tty_cdev_ops; + + kmutex_init(&tty->tty_write_mutex); + kmutex_init(&tty->tty_read_mutex); + + long ret = chardev_register(&tty->tty_cdev); + KASSERT(!ret); + } + active_tty = 0; + vterminal_make_active(&ttys[active_tty]->tty_vterminal); + KASSERT(ttys[active_tty]); + + keyboard_init(tty_receive_char_multiplexer); +} + +/** + * Reads from the tty to the buffer. + * + * You should first lock the read mutex of the tty. You should + * then wait until there is something in the line discipline's buffer and only + * read from the ldisc's buffer if there are new characters. + * + * To prevent being preempted, you should set IPL using INTR_KEYBOARD + * correctly and revert it once you are done. + * + * @param cdev the character device that represents tty + * @param pos the position to start reading from; should be ignored + * @param buf the buffer to read into + * @param count the maximum number of bytes to read + * @return the number of bytes actually read into the buffer + */ +ssize_t tty_read(chardev_t *cdev, size_t pos, void *buf, size_t count) +{ + NOT_YET_IMPLEMENTED("DRIVERS: ***none***"); + return -1; +} + +/** + * Writes to the tty from the buffer. + * + * You should first lock the write mutex of the tty. Then you can use + * `vterminal_write` to write to the terminal. Don't forget to use IPL to + * guard this from preemption! + * + * @param cdev the character device that represents tty + * @param pos the position to start reading from; should be ignored + * @param buf the buffer to read from + * @param count the maximum number of bytes to write to the terminal + * @return the number of bytes actually written + */ +ssize_t tty_write(chardev_t *cdev, size_t pos, const void *buf, size_t count) +{ + NOT_YET_IMPLEMENTED("DRIVERS: ***none***"); + return -1; +} + +static void tty_receive_char_multiplexer(uint8_t c) +{ + tty_t *tty = ttys[active_tty]; + + if (c >= F1 && c <= F12) + { + if (c - F1 < NTERMS) + { + /* TODO: this is totally unsafe... Fix it */ + active_tty = (unsigned)c - F1; + tty = ttys[active_tty]; + vterminal_make_active(&tty->tty_vterminal); + } + return; + } + if (c == CR) + c = LF; + else if (c == DEL) + c = BS; + + vterminal_t *vt = &tty->tty_vterminal; + switch ((unsigned)c) + { + case SCROLL_DOWN: + case SCROLL_UP: + // vterminal_scroll(vt, c == SCROLL_DOWN ? 1 : -1); + break; + case SCROLL_DOWN_PAGE: + case SCROLL_UP_PAGE: + // vterminal_scroll(vt, c == SCROLL_DOWN_PAGE ? vt->vt_height : + // -vt->vt_height); + break; + case ESC: + // vterminal_scroll_to_bottom(vt); + break; + default: + ldisc_key_pressed(&tty->tty_ldisc, c); + // vterminal_key_pressed(vt); + break; + } +} |