diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/rs.s | 34 | ||||
| -rw-r--r-- | kernel/serial.c | 39 | ||||
| -rw-r--r-- | kernel/sys.c | 9 | ||||
| -rw-r--r-- | kernel/tty.c | 64 |
4 files changed, 132 insertions, 14 deletions
diff --git a/kernel/rs.s b/kernel/rs.s index 9f3d4a6..69d31ae 100644 --- a/kernel/rs.s +++ b/kernel/rs.s @@ -1,7 +1,20 @@ global rs_isr -extern rs_handler +extern rsint_rx +extern rsint_tx extern rsputs +%define RSBASE 0x3F8 + +%define RSDATA RSBASE +%define RSINTEN (RSBASE + 1) +%define RSFIFOC (RSBASE + 2) +%define RSINTID (RSBASE + 2) +%define RSLINEC (RSBASE + 3) +%define RSMODEMC (RSBASE + 4) +%define RSLINES (RSBASE + 5) +%define RSMODEMS (RSBASE + 6) +%define RSSCRATCH (RSBASE + 7) + rs_isr: pusha mov ax, ds @@ -12,7 +25,24 @@ rs_isr: mov fs, ax mov gs, ax - call rs_handler + mov dx, RSINTID + in al, dx + test al, 1 + jnz .skip + and al, 0x0E + cmp al, 0x04 + je .rx + cmp al, 0x0C + je .rx + cmp al, 0x02 + je .tx + jmp .skip +.tx: + call rsint_tx + jmp .skip +.rx: + call rsint_rx +.skip: mov al, 0x20 out 0x20, al diff --git a/kernel/serial.c b/kernel/serial.c index 39c5ee0..a133865 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -16,6 +16,7 @@ #define RSDATA RSBASE #define RSINTEN (RSBASE + 1) #define RSFIFOC (RSBASE + 2) +#define RSINTID (RSBASE + 2) #define RSLINEC (RSBASE + 3) #define RSMODEMC (RSBASE + 4) #define RSLINES (RSBASE + 5) @@ -27,8 +28,12 @@ extern void rs_isr(void); +/* internal function prototypes */ +void rsint_tx(void); + struct tty_struct tty_rs = { - .init = &serial_init + .init = &serial_init, + .write = &rsint_tx }; static char present; @@ -70,11 +75,18 @@ void serial_init(void) { /* restore access to the divisor */ outb(RSLINEC, inb(RSLINEC) & 0x7F); /* configure port parameters */ - outb(RSFIFOC, 0x06); + outb(RSFIFOC, 0x07); outb(RSLINEC, 0x03); outb(RSMODEMC, 0x0B); - outb(RSINTEN, 0x01); + outb(RSINTEN, 0x03); inb(RSDATA); + + /* test FIFO functionality */ + if(inb(RSINTID) & 0xC0 != 0xC0) { + printk("[rs] Failed to enable FIFO on COM0!\n"); + return; + } + /* register the interrupt handler */ register_isr(0x24, 0, &rs_isr); irq_enable(0x10); @@ -85,7 +97,7 @@ void serial_init(void) { present = 1; } -void rs_handler(void) { +void rsint_rx(void) { struct tty_queue *q = &tty_rs.rqueue; if((inb(RSLINES) & 1) == 0) @@ -98,3 +110,22 @@ void rs_handler(void) { wake_up(&q->waiting); } + +void rsint_tx(void) { + int copied = 0; + struct tty_queue *q = &tty_rs.wqueue; + + while(q->pread != q->pwrite) { + /* we're done if the TX FIFO is full */ + if((inb(RSLINES) & 0x20) == 0) + break; + + outb(RSDATA, q->buf[q->pread]); + q->pread = (q->pread + 1) % TTY_BUF_SIZE; + + copied = 1; + } + + if(copied) + wake_up(&q->waiting); +} diff --git a/kernel/sys.c b/kernel/sys.c index 6127f58..8e28edd 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1,5 +1,6 @@ #include <errno.h> #include <kernel/con.h> +#include <kernel/kernel.h> #include <kernel/sched.h> #include <kernel/serial.h> #include <kernel/tty.h> @@ -84,6 +85,14 @@ ssize_t sys_read(void *buf, size_t len) { return tty_read(ctask->ctty, buf, len); } +ssize_t sys_write(void *buf, size_t len) { + return tty_write(ctask->ctty, buf, len); +} + +void sys_panic(void) { + panic(); +} + int sys_dummy(void) { return -ENOSYS; } 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(); } |
