neuttower/serial.c

109 lines
2.4 KiB
C
Executable file

#include <stdio.h>
#include <dos.h>
#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;
}