aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/isa/i8042.c2
-rw-r--r--sys/include/sys/termios.h1
-rw-r--r--sys/include/sys/tty.h6
-rw-r--r--sys/kern/kern_syslog.c2
-rw-r--r--sys/kern/kern_tty.c109
5 files changed, 84 insertions, 36 deletions
diff --git a/sys/arch/amd64/isa/i8042.c b/sys/arch/amd64/isa/i8042.c
index 0f160d3..41b74ef 100644
--- a/sys/arch/amd64/isa/i8042.c
+++ b/sys/arch/amd64/isa/i8042.c
@@ -234,7 +234,7 @@ kb_isr(void *sf)
while (__TEST(inb(I8042_STATUS), I8042_OBUF_FULL)) {
data = inb(I8042_DATA);
if (scancode_to_chr(data, &c) == 0) {
- tty_putc(&g_root_tty, c);
+ tty_putc(&g_root_tty, c, TTY_SOURCE_DEV);
}
}
spinlock_release(&data_lock);
diff --git a/sys/include/sys/termios.h b/sys/include/sys/termios.h
index 963c885..1fda67e 100644
--- a/sys/include/sys/termios.h
+++ b/sys/include/sys/termios.h
@@ -50,6 +50,7 @@
* Local flags
*/
#define ICANON 0x00000001U
+#define ECHO 0x00000002U
typedef uint32_t tcflag_t;
typedef uint32_t speed_t;
diff --git a/sys/include/sys/tty.h b/sys/include/sys/tty.h
index c53ea73..342a1a7 100644
--- a/sys/include/sys/tty.h
+++ b/sys/include/sys/tty.h
@@ -38,6 +38,9 @@
#define TTY_RING_SIZE 32
+#define TTY_SOURCE_RAW 0x0001U /* Raw text */
+#define TTY_SOURCE_DEV 0x0002U /* Input from device (e.g keyboard) */
+
struct tty_ring {
char data[TTY_RING_SIZE]; /* Ring data */
off_t enq_index; /* Enqueue index */
@@ -48,6 +51,7 @@ struct tty {
dev_t id;
struct vcons_screen *scr; /* Console screen */
struct tty_ring ring; /* Input ring */
+ struct tty_ring outring; /* Output ring */
struct spinlock rlock; /* Ring lock */
struct termios termios; /* Termios structure */
struct device *dev; /* Device pointer */
@@ -56,7 +60,7 @@ struct tty {
extern struct tty g_root_tty;
dev_t tty_attach(struct tty *tty);
-int tty_putc(struct tty *tty, int c);
+int tty_putc(struct tty *tty, int c, int flags);
int tty_putstr(struct tty *tty, const char *s, size_t count);
ssize_t tty_flush(struct tty *tty);
diff --git a/sys/kern/kern_syslog.c b/sys/kern/kern_syslog.c
index 3ff4e8c..88ae8bc 100644
--- a/sys/kern/kern_syslog.c
+++ b/sys/kern/kern_syslog.c
@@ -45,7 +45,7 @@ syslog_write(const char *s, size_t len)
#if defined(__SERIAL_DEBUG)
serial_dbgch(*tmp_s);
#endif /* defined(__SERIAL_DEBUG) */
- tty_putc(&g_root_tty, *tmp_s++);
+ tty_putc(&g_root_tty, *tmp_s++, TTY_SOURCE_RAW);
}
tty_flush(&g_root_tty);
diff --git a/sys/kern/kern_tty.c b/sys/kern/kern_tty.c
index 8446e2b..cb3e30a 100644
--- a/sys/kern/kern_tty.c
+++ b/sys/kern/kern_tty.c
@@ -32,6 +32,7 @@
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/ascii.h>
+#include <dev/vcons/vcons_io.h>
#include <fs/devfs.h>
#include <string.h>
@@ -41,6 +42,9 @@ struct tty g_root_tty = {
.ring = {
.enq_index = 0,
.deq_index = 0,
+ },
+ .termios = {
+ .c_lflag = ICANON | ECHO
}
};
@@ -52,6 +56,35 @@ tty_alloc_id(void)
return id++;
}
+static inline bool
+tty_is_special(char c)
+{
+ return c < 0x1F;
+}
+
+static inline void
+tty_reset_ring(struct tty_ring *ring)
+{
+ ring->enq_index = 0;
+ ring->deq_index = 0;
+}
+
+static void
+tty_process(struct tty *tty, char c, bool echo)
+{
+ const struct termios *termios;
+ bool canon, special;
+
+ termios = &tty->termios;
+ canon = __TEST(termios->c_lflag, ICANON);
+ special = tty_is_special(c);
+
+ if (canon && special)
+ vcons_process_output(tty->scr, c);
+ if (echo && !special)
+ vcons_putch(tty->scr, c);
+}
+
/*
* Flushes the TTY ring buffer.
*
@@ -63,31 +96,30 @@ static ssize_t
__tty_flush(struct tty *tty)
{
struct tty_ring *ring = &tty->ring;
- const struct termios *termios;
+ struct tty_ring *outring = &tty->outring;
size_t count = 0;
char tmp;
- termios = &tty->termios;
-
/* Do we have any data left? */
if (ring->deq_index >= ring->enq_index)
return -EAGAIN;
/*
- * Flush the ring to the console if we are in
- * canonical mode. Otherwise, just throw away
- * the bytes.
+ * Flush the input ring to the output ring
+ * to allow user programs to fetch from it
+ * with /dev/ttyN.
*/
- if (__TEST(termios->c_lflag, ICANON)) {
- while (ring->deq_index < ring->enq_index) {
- tmp = ring->data[ring->deq_index++];
- vcons_putch(tty->scr, tmp);
- ++count;
- }
+ while (ring->deq_index < ring->enq_index) {
+ tmp = ring->data[ring->deq_index++];
+ outring->data[outring->enq_index++] = tmp;
+
+ if (outring->enq_index > TTY_RING_SIZE)
+ tty_reset_ring(outring);
+
+ ++count;
}
- ring->enq_index = 0;
- ring->deq_index = 0;
+ tty_reset_ring(ring);
return count;
}
@@ -98,11 +130,15 @@ __tty_flush(struct tty *tty)
static int
tty_dev_read(struct device *dev, struct sio_txn *sio)
{
- struct tty_ring *ring = &g_root_tty.ring;
- size_t len;
+ struct tty_ring *ring = &g_root_tty.outring;
+ size_t len, max_len;
spinlock_acquire(&g_root_tty.rlock);
- len = (ring->enq_index - ring->deq_index);
+ max_len = (ring->enq_index - ring->deq_index);
+ len = sio->len;
+
+ if (len > max_len)
+ len = max_len;
/*
* Transfer data from the TTY ring with SIO and
@@ -112,8 +148,7 @@ tty_dev_read(struct device *dev, struct sio_txn *sio)
* TTY, add support for multiple TTYs.
*/
memcpy(sio->buf, ring->data, len);
- __tty_flush(&g_root_tty);
-
+ tty_reset_ring(ring);
spinlock_release(&g_root_tty.rlock);
return len;
}
@@ -139,30 +174,30 @@ tty_flush(struct tty *tty)
* @c: Character to write.
*/
int
-tty_putc(struct tty *tty, int c)
+tty_putc(struct tty *tty, int c, int flags)
{
struct tty_ring *ring;
const struct termios *termios;
- bool canon;
+ bool canon, echo;
ring = &tty->ring;
termios = &tty->termios;
+
canon = __TEST(termios->c_lflag, ICANON);
+ echo = __TEST(termios->c_lflag, ECHO);
spinlock_acquire(&tty->rlock);
ring->data[ring->enq_index++] = c;
/*
- * If we aren't in canonical mode, just write directly to
- * the console.
- *
- * XXX: Won't need to worry about extra bytes being printed
- * as __tty_flush() won't flush them to the console
- * when we aren't in canonical mode.
+ * Process the characters for both device input
+ * and raw input. Device input will only be echoed
+ * if the ECHO bit is set within c_lflag
*/
- if (!canon) {
- vcons_putch(tty->scr, c);
- }
+ if (__TEST(flags, TTY_SOURCE_DEV) && echo)
+ tty_process(tty, c, echo);
+ if (__TEST(flags, TTY_SOURCE_RAW))
+ tty_process(tty, c, true);
/*
* If we are in canonical mode and we have a linefeed ('\n')
@@ -172,11 +207,19 @@ tty_putc(struct tty *tty, int c)
__tty_flush(tty);
}
- /* Flush if the buffer is full */
- if (ring->enq_index >= TTY_RING_SIZE) {
+ /*
+ * Just flush the ring if we aren't in canonical
+ * mode.
+ */
+ if (!canon) {
__tty_flush(tty);
}
+ /* Reset the ring if it is full */
+ if (ring->enq_index >= TTY_RING_SIZE) {
+ tty_reset_ring(ring);
+ }
+
spinlock_release(&tty->rlock);
return 0;
}
@@ -192,7 +235,7 @@ int
tty_putstr(struct tty *tty, const char *s, size_t count)
{
for (size_t i = 0; i < count; ++i) {
- tty_putc(tty, *s++);
+ tty_putc(tty, *s++, TTY_SOURCE_RAW);
}
return 0;