diff options
Diffstat (limited to 'kernel/tty.c')
| -rw-r--r-- | kernel/tty.c | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/kernel/tty.c b/kernel/tty.c index 1946110..75c3701 100644 --- a/kernel/tty.c +++ b/kernel/tty.c @@ -16,11 +16,8 @@ static struct tty_struct *ttys[] = { &tty_rs }; -/* check if the buffer's empty and if so, go to sleep */ +/* check if a buffer's empty and if so, go to sleep */ static int sleep_while_empty(struct tty_queue *q) { - if(q->pread != q->pwrite) - return 0; - cli(); while(1) { if(q->pread == q->pwrite) @@ -37,6 +34,24 @@ static int sleep_while_empty(struct tty_queue *q) { } } +/* check if a buffer's full and if so, go to sleep */ +static int sleep_while_full(struct tty_queue *q) { + cli(); + while(1) { + if(q->pwrite == (q->pread - 1 % sizeof(q->buf))) + interruptible_sleep_on(&q->waiting); + + /* check again to see if anything was removed, or we were interrupted */ + if(q->pwrite == (q->pread - 1 % sizeof(q->buf))) { + sti(); + return -1; + } + + sti(); + return 0; + } +} + ssize_t tty_read(unsigned tty, void *buf, size_t len) { size_t i; char *b = buf; @@ -61,9 +76,45 @@ ssize_t tty_read(unsigned tty, void *buf, size_t len) { } *b++ = q->buf[q->pread]; - q->pread = q->pread + 1 % TTY_BUF_SIZE; + q->pread = (q->pread + 1) % TTY_BUF_SIZE; + } + + return len; +} + +ssize_t tty_write(unsigned tty, void *buf, size_t len) { + size_t i; + char *b = buf; + struct tty_queue *q = &ttys[tty]->wqueue; + + if(tty > NRTTY || ttys[tty] == NULL) + return -1; + + if(len == 0) + return 0; + + if(len > SSIZE_MAX) + len = SSIZE_MAX; + + for(i = 0; i < len; i++) { + /* check if the buffer's full and if so, go to sleep */ + if(sleep_while_full(q) < 0) { + if(i == 0) + return -EINTR; + + return i; + } + + q->buf[q->pwrite] = *b++; + q->pwrite = (q->pwrite + 1) % TTY_BUF_SIZE; } + /* tell the driver that new data is available */ + cli(); + if(ttys[tty]->write) + ttys[tty]->write(); + sti(); + return len; } @@ -77,9 +128,6 @@ void tty_init(void) { memset(&ttys[i]->rqueue, 0, sizeof(struct tty_queue)); memset(&ttys[i]->wqueue, 0, sizeof(struct tty_queue)); - ttys[i]->rqueue.pwrite = 1; - ttys[i]->wqueue.pwrite = 1; - if(ttys[i]->init) ttys[i]->init(); } |
