diff options
Diffstat (limited to 'kernel/serial.c')
| -rw-r--r-- | kernel/serial.c | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/kernel/serial.c b/kernel/serial.c index 86bbd87..d96359b 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -1,5 +1,9 @@ +#include <asm/interrupt.h> #include <asm/io.h> #include <kernel/con.h> +#include <kernel/sched.h> +#include <sys/types.h> +#include <unistd.h> /* 115200 baud */ #define DIVISOR 1 @@ -18,10 +22,16 @@ #define rswait()\ while((inb(RSLINES) & 0x20) == 0); +extern void rs_isr(void); + +static char rxbuf[256]; +static unsigned rxread, rxwrite; +static struct task_struct *waiting_task; + int rsputs(char *s) { while(*s) { rswait(); - if(*s == '\n') { + if(*s == '\n' || *s == '\r') { outb(RSDATA, '\n'); rswait(); outb(RSDATA, '\r'); @@ -50,9 +60,55 @@ void serial_init(void) { /* restore access to the divisor */ outb(RSLINEC, inb(RSLINEC) & 0x7F); /* configure port parameters */ + outb(RSFIFOC, 0x06); outb(RSLINEC, 0x03); - outb(RSINTEN, 0x00); + outb(RSMODEMC, 0x0B); + outb(RSINTEN, 0x01); + inb(RSDATA); + /* register the interrupt handler */ + register_isr(0x24, 0, &rs_isr); + irq_enable(0x10); rsputs("[kernel] Serial monitor initialized!\n\r"); printk("[rs] Serial port COM0 initialized!\n"); + + rxread = 0; + rxwrite = 1; + waiting_task = NULL; +} + +ssize_t rsread(void *buf, size_t len) { + ssize_t n = len; + char *b = buf; + + if(len == 0) + return 0; + + while(n--) { + if(rxread == rxwrite) { + /* put the current task to sleep */ + waiting_task = ctask; + ctask->state = TSTATE_UNINTERRUPTIBLE; + reschedule(); + } + + *b++ = rxbuf[rxread]; + rxread = rxread + 1 % sizeof(rxbuf); + } + + return len; +} + +void rs_handler(void) { + if((inb(RSLINES) & 1) == 0) + return; + if(rxwrite == (rxread - 1 % sizeof(rxbuf))) + return; + rxbuf[rxwrite] = inb(RSDATA); + rxwrite = rxwrite + 1 % sizeof(rxbuf); + + if(waiting_task != NULL) { + waiting_task->state = TSTATE_RUNNING; + waiting_task = NULL; + } } |
