#include #include #include #include #include #include #include #include #include /* 115200 baud */ #define DIVISOR 1 /* this shouldn't change */ #define FIFOSZ 16 #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) extern void rs_isr(void); /* internal function prototypes */ void rsint_tx(void); struct tty_struct tty_rs = { .init = &serial_init, .write = &rsint_tx }; static char present; void serial_init(void) { present = 0; outb(RSSCRATCH, 0x00); outb(RSSCRATCH, 0xAA); if(inb(RSSCRATCH) != 0xAA) { printk("[rs] COM0 not detected!\n"); return; } /* enable access to the divisor */ outb(RSLINEC, inb(RSLINEC) | 0x80); /* write the divisor */ outb(RSBASE, DIVISOR); outb(RSBASE + 1, DIVISOR >> 8); /* restore access to the divisor */ outb(RSLINEC, inb(RSLINEC) & 0x7F); /* configure port parameters */ outb(RSFIFOC, 0x07); outb(RSLINEC, 0x03); outb(RSMODEMC, 0x0B); 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); printk("[rs] Serial port COM0 initialized!\n"); present = 1; } void rsint_rx(void) { struct tty_queue *q = &tty_rs.rqueue; if((inb(RSLINES) & 1) == 0) return; if(q->pwrite == ((q->pread - 1) % sizeof(q->buf))) return; q->buf[q->pwrite] = inb(RSDATA); q->pwrite = (q->pwrite + 1) % sizeof(q->buf); wake_up(&q->waiting); } void rsint_tx(void) { int i; int copied = 0; struct tty_queue *q = &tty_rs.wqueue; if((inb(RSLINES) & 0x20) == 0) return; for(i = 0; i < FIFOSZ; i++) { if(q->pread == q->pwrite) break; outb(RSDATA, q->buf[q->pread]); q->pread = (q->pread + 1) % TTY_BUF_SIZE; copied = 1; } if(copied) wake_up(&q->waiting); }