diff options
| author | Jake Mannens <jake72360@gmail.com> | 2018-08-26 13:29:33 +1000 |
|---|---|---|
| committer | Jake Mannens <jake72360@gmail.com> | 2018-08-26 13:29:33 +1000 |
| commit | 307eaac66d378c1f6150519123ec1204277464d9 (patch) | |
| tree | 8c6dc79c5c16bf776bd57ca78a439701cc10412e /kernel/tty.c | |
| parent | dafb5464fe8b9a3f8ff41de233f9ff6cd21162ea (diff) | |
Updated the style of the code in lib/string.c to conform to the rest of
the project.
Added the system call 'sys_panic' as well as the corresponding library
function panic() whose prototype is defined in unistd.h. This is to
allow userspace programs to deliberately crash the kernel for the
purpose of debugging.
Added the element 'write' as a function pointer in the tty_struct
structure. The purpose of this function pointer is to provide a means
for the TTY subsystem to notify the device driver of any newly added
data to the write queue.
Added the tty_write() function to the TTY subsystem. This function will
copy data provided by the user into the specified TTY device's write
queue, blocking if the queue's buffer is full. tty_write() will then
call the driver's write() function to notify it of new data.
Added the rsint_tx() function to the serial driver to handle transmit
interrupts by re-supplying the UART's transmit FIFO.
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(); } |
