diff options
Diffstat (limited to 'kernel/serial.c')
| -rw-r--r-- | kernel/serial.c | 39 |
1 files changed, 35 insertions, 4 deletions
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); +} |
