#include #include #include #include #include #include #include #include #include /* 115200 baud */ #define DIVISOR 1 #define RSBASE 0x3F8 #define RSDATA RSBASE #define RSINTEN (RSBASE + 1) #define RSFIFOC (RSBASE + 2) #define RSLINEC (RSBASE + 3) #define RSMODEMC (RSBASE + 4) #define RSLINES (RSBASE + 5) #define RSMODEMS (RSBASE + 6) #define RSSCRATCH (RSBASE + 7) #define rswait()\ while((inb(RSLINES) & 0x20) == 0); extern void rs_isr(void); struct tty_struct tty_rs = { .init = &serial_init }; static char present; int rsputs(char *s) { if(!present) return -ENXIO; while(*s) { rswait(); if(*s == '\n' || *s == '\r') { outb(RSDATA, '\n'); rswait(); outb(RSDATA, '\r'); s++; } else { outb(RSDATA, *s++); } } return 0; } 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, 0x06); outb(RSLINEC, 0x03); 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"); present = 1; } void rs_handler(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); }