From dafb5464fe8b9a3f8ff41de233f9ff6cd21162ea Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Wed, 22 Aug 2018 06:00:39 +1000 Subject: Added the header file limits.h which contains one definition for SSIZE_MAX which is needed to limit the number of bytes read() will transfer. Laid the foundation for a TTY subsystem. This works by taking the previously used buffer and r/w pointers concept and implements it as a 'tty_queue' struct. The struct 'tty_struct' is used to represent a TTY device. This struct currently contains three elements; a read queue for data flowing from the device to the user, a write queue for data flowing from the user to the device and a function pointer to an init function. The latter element will reduce complexity by allowing the TTY subsystem to initialize each TTY device driver (when it's ready), rather than each driver having to be initialized during bootup. Each TTY device is implemented as a pointer to a tty_struct. The structures are defined separately by each driver as well as tracked and maintained by pointers in the table 'ttys' in tty.c. Modified the RS232 serial driver to make use of the new TTY subsystem for transferring data to the user. Currently, write calls are still handled manually through the rsputs() function though this will change in future. Modified the read() system call to direct read calls to the TTY subsystem which will further direct the call to the appropriate TTY device driver. The serial driver's interrupt routine now uses the wake_up() function to wake processes blocking for serial data. This is to ensure the scheduler is notified of the wakeup. This function is the preferred method for waking processes since accessing the task state field directly may not be possible in the future and is discouraged. The reason for this is that the scheduler's behaviour may change to require being notified of task wakeup events in the future. --- kernel/serial.c | 58 +++++++++++++-------------------------------------------- 1 file changed, 13 insertions(+), 45 deletions(-) (limited to 'kernel/serial.c') diff --git a/kernel/serial.c b/kernel/serial.c index f5610f5..39c5ee0 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -25,11 +27,11 @@ extern void rs_isr(void); -static char present; +struct tty_struct tty_rs = { + .init = &serial_init +}; -static char rxbuf[256]; -static unsigned rxread, rxwrite; -static struct task_struct *waiting_task; +static char present; int rsputs(char *s) { if(!present) @@ -80,53 +82,19 @@ void serial_init(void) { rsputs("[kernel] Serial monitor initialized!\n\r"); printk("[rs] Serial port COM0 initialized!\n"); - rxread = 0; - rxwrite = 1; - waiting_task = NULL; present = 1; } -ssize_t rsread(void *buf, size_t len) { - ssize_t n = len; - char *b = buf; - - if(!present) - return -ENXIO; - - if(len == 0) - return 0; - - while(n--) { - /* check if the buffer's empty and if so, go to sleep */ - cli(); - if(rxread == rxwrite) - interruptible_sleep_on(&waiting_task); - - /* check again to see if anything was read, or we were interrupted */ - if(rxread == rxwrite) { - sti(); - return -EINTR; - } - - sti(); - - *b++ = rxbuf[rxread]; - rxread = rxread + 1 % sizeof(rxbuf); - } - - return len; -} - void rs_handler(void) { + struct tty_queue *q = &tty_rs.rqueue; + if((inb(RSLINES) & 1) == 0) return; - if(rxwrite == (rxread - 1 % sizeof(rxbuf))) + if(q->pwrite == (q->pread - 1 % sizeof(q->buf))) return; - rxbuf[rxwrite] = inb(RSDATA); - rxwrite = rxwrite + 1 % sizeof(rxbuf); - if(waiting_task != NULL) { - waiting_task->state = TSTATE_RUNNING; - waiting_task = NULL; - } + q->buf[q->pwrite] = inb(RSDATA); + q->pwrite = q->pwrite + 1 % sizeof(q->buf); + + wake_up(&q->waiting); } -- cgit v1.3