aboutsummaryrefslogtreecommitdiff
path: root/kernel/drivers/tty/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/tty/tty.c')
-rw-r--r--kernel/drivers/tty/tty.c135
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;
+ }
+}