diff options
| -rw-r--r-- | include/kernel/serial.h | 5 | ||||
| -rw-r--r-- | include/kernel/tty.h | 26 | ||||
| -rw-r--r-- | include/limits.h | 8 | ||||
| -rw-r--r-- | kernel/boot.s | 4 | ||||
| -rw-r--r-- | kernel/serial.c | 58 | ||||
| -rw-r--r-- | kernel/sys.c | 10 | ||||
| -rw-r--r-- | kernel/tty.c | 86 |
7 files changed, 142 insertions, 55 deletions
diff --git a/include/kernel/serial.h b/include/kernel/serial.h index dbfa7f2..6ac5d65 100644 --- a/include/kernel/serial.h +++ b/include/kernel/serial.h @@ -1,10 +1,15 @@ #ifndef _SERIAL_H #define _SERIAL_H +#include <kernel/tty.h> #include <sys/types.h> +extern struct tty_struct tty_rs; + int rsputs(char*); ssize_t rsread(void*, size_t); +void serial_init(void); + #endif diff --git a/include/kernel/tty.h b/include/kernel/tty.h new file mode 100644 index 0000000..b3f3012 --- /dev/null +++ b/include/kernel/tty.h @@ -0,0 +1,26 @@ +#ifndef _TTY_H +#define _TTY_H + +#include <kernel/sched.h> +#include <sys/types.h> + +#define TTY_BUF_SIZE 1024 + +struct tty_queue { + unsigned pread; + unsigned pwrite; + struct task_struct *waiting; + char buf[TTY_BUF_SIZE]; +}; + +struct tty_struct { + void (*init) (void); + struct tty_queue rqueue; + struct tty_queue wqueue; +}; + +ssize_t tty_read(unsigned, void*, size_t); + +void tty_init(void); + +#endif diff --git a/include/limits.h b/include/limits.h new file mode 100644 index 0000000..c2c9cc5 --- /dev/null +++ b/include/limits.h @@ -0,0 +1,8 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#include <sys/types.h> + +#define SSIZE_MAX ((size_t) ~((size_t) 1 << (sizeof(size_t) * 8 - 1))) + +#endif diff --git a/kernel/boot.s b/kernel/boot.s index d609611..ac7e0e3 100644 --- a/kernel/boot.s +++ b/kernel/boot.s @@ -8,10 +8,10 @@ extern hd_init extern kmain extern paging_init extern printk -extern serial_init extern syscall_init extern timer_init extern traps_init +extern tty_init %define NRTASKS 64 @@ -42,7 +42,7 @@ kboot: call printk add esp, 4 ; initialize secondary subsystems - call serial_init + call tty_init call hd_init ; last minute setup, then transfer to kmain call timer_init 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 <errno.h> #include <kernel/con.h> #include <kernel/sched.h> +#include <kernel/serial.h> +#include <kernel/tty.h> #include <sys/types.h> #include <unistd.h> @@ -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); } diff --git a/kernel/sys.c b/kernel/sys.c index cfe9483..6127f58 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2,6 +2,7 @@ #include <kernel/con.h> #include <kernel/sched.h> #include <kernel/serial.h> +#include <kernel/tty.h> #include <signal.h> #include <stdint.h> #include <stdio.h> @@ -80,14 +81,7 @@ int sys_ctty(int ctty) { } ssize_t sys_read(void *buf, size_t len) { - switch(ctask->ctty) { - case 1: - return rsread(buf, len); - break; - default: - return -EBADF; - break; - } + return tty_read(ctask->ctty, buf, len); } int sys_dummy(void) { diff --git a/kernel/tty.c b/kernel/tty.c new file mode 100644 index 0000000..1946110 --- /dev/null +++ b/kernel/tty.c @@ -0,0 +1,86 @@ +#include <asm/interrupt.h> +#include <errno.h> +#include <kernel/sched.h> +#include <kernel/serial.h> +#include <kernel/tty.h> +#include <limits.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#define NRTTY \ + (sizeof(ttys) / sizeof(struct tty_struct*)) + +static struct tty_struct *ttys[] = { + NULL, + &tty_rs +}; + +/* check if the 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) + interruptible_sleep_on(&q->waiting); + + /* check again to see if anything was read, or we were interrupted */ + if(q->pread == q->pwrite) { + sti(); + return -1; + } + + sti(); + return 0; + } +} + +ssize_t tty_read(unsigned tty, void *buf, size_t len) { + size_t i; + char *b = buf; + struct tty_queue *q = &ttys[tty]->rqueue; + + 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 empty and if so, go to sleep */ + if(sleep_while_empty(q) < 0) { + if(i == 0) + return -EINTR; + + return i; + } + + *b++ = q->buf[q->pread]; + q->pread = q->pread + 1 % TTY_BUF_SIZE; + } + + return len; +} + +void tty_init(void) { + int i; + + for(i = 0; i < NRTTY; i++) { + if(!ttys[i]) + continue; + + 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(); + } +} |
