summaryrefslogtreecommitdiff
path: root/kernel/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/serial.c')
-rw-r--r--kernel/serial.c39
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);
+}