#include #include #include "serial.h" int comport = 0; #define SER_LATCH_LO 0 #define SER_LATCH_HI 1 #define SER_TX 0 #define SER_RX 0 #define SER_IER 1 #define SER_LCR 3 #define SER_MCR 4 #define SER_LSR 5 #define PIC1 0x20 #define OCW1 0x21 #define PIC_EOI 0x20 // COM1 - IRQ4, COM2 - IRQ3, COM3 - IRQ4, COM4 - IRQ3 #define SER_IRQ(port) (4 - (port % 2)) #define SER_VECTOR(irq) (0x08 + (irq)) static char readbuf[SER_READ_BUFFER_SIZE]; static int ireadbufStart = 0; static volatile int ireadbufLim = 0; static int irq = 0; static void interrupt (*oldSerISR)() = NULL; static void interrupt ser_isr() { while (inp(comport + SER_LSR) & 0x01) { readbuf[ireadbufLim] = inp(comport + SER_RX); ireadbufLim = (ireadbufLim + 1) % SER_READ_BUFFER_SIZE; } outp(PIC1, PIC_EOI); } static void ser_cleanup() { if (irq) { int ocw = inp(OCW1) | (1 << irq); outp(OCW1, ocw); setvect(SER_VECTOR(irq), oldSerISR); irq = 0; } } void ser_init(int port, int baudrate, int protocol) { int far *comport_addr = MK_FP(0x0040, 0x0000); int lcr, ocw; comport = comport_addr[port]; irq = SER_IRQ(port); outp(comport + SER_LCR, 0x80); outp(comport + SER_LATCH_HI, baudrate >> 8); outp(comport + SER_LATCH_LO, baudrate & 0xff); outp(comport + SER_LCR, protocol); outp(comport + SER_MCR, 0x0b); oldSerISR = getvect(SER_VECTOR(irq)); setvect(SER_VECTOR(irq), ser_isr); ocw = inp(OCW1) & ~(1 << irq); outp(OCW1, ocw); outp(comport + SER_IER, 0x01); atexit(ser_cleanup); } int ser_poll() { int result = SER_NODATA; if (ireadbufStart != ireadbufLim) { result = readbuf[ireadbufStart]; ireadbufStart = (ireadbufStart + 1) % SER_READ_BUFFER_SIZE; } return result; } void ser_write_byte(char byte) { while (!(inp(comport + SER_LSR) & 0x20)) {} outp(comport + SER_TX, byte); } void ser_write(char *str) { for (; *str; str ++) { ser_write_byte(*str); } } int ser_getline(char *line) { int i = strlen(line); int value; for (value = ser_poll(); value != SER_NODATA; value = ser_poll()) { if (value == '\b' || value == 127) { i --; } else { line[i] = value; i ++; } line[i] = '\0'; ser_write_byte(value); // echo if (value == '\r') { line[i - 1] = '\n'; ser_write_byte('\n'); return 1; } } return 0; }