11 #define UART1_BASE 0x3f8
12 #define UART2_BASE 0x2f8
27 /* interrupt enable register bits */
33 /* fifo control register bits */
34 #define FIFO_ENABLE 0x01
35 #define FIFO_RECV_CLEAR 0x02
36 #define FIFO_SEND_CLEAR 0x04
38 #define FIFO_TRIG_4 0x40
39 #define FIFO_TRIG_8 0x80
40 #define FIFO_TRIG_14 0xc0
42 /* interrupt id register bits */
43 #define IID_PENDING 0x01
47 #define IID_FIFO_EN 0xc0
49 #define IID_SOURCE 0xe
55 #define IID_STATUS 0x6
57 /* line control register bits */
58 #define LCTL_BITS_8 0x03
59 #define LCTL_STOP_2 0x04
60 #define LCTL_DLAB 0x80
61 #define LCTL_8N1 LCTL_BITS_8
62 #define LCTL_8N2 (LCTL_BITS_8 | LCTL_STOP_2)
64 /* modem control register bits */
67 #define MCTL_OUT1 0x04
68 #define MCTL_OUT2 0x08
69 #define MCTL_LOOP 0x10
71 /* line status register bits */
73 #define LST_ERR_OVER 0x02
74 #define LST_ERR_PARITY 0x04
75 #define LST_ERR_FRAME 0x08
76 #define LST_ERR_BRK 0x10
77 #define LST_TREG_EMPTY 0x20
78 #define LST_TIDLE 0x40
79 #define LST_ERROR 0x80
81 /* modem status register bits */
82 #define MST_DELTA_CTS 0x01
83 #define MST_DELTA_DSR 0x02
85 #define MST_DELTA_DCD 0x08
91 /* interrupt controller stuff */
92 #define PIC1_CMD_PORT 0x20
93 #define PIC1_DATA_PORT 0x21
94 #define PIC2_CMD_PORT 0xa0
95 #define PIC2_DATA_PORT 0xa1
98 #define COM_FMT_8N1 LCTL_8N1
99 #define COM_FMT_8N2 LCTL_8N2
106 int inbuf_ridx, inbuf_widx;
109 #define BNEXT(x) (((x) + 1) & 0xff)
110 #define BEMPTY(b) (b##_ridx == b##_widx)
112 static void ser_putc(int uart_base, char c);
113 static void ser_puts(int uart_base, const char *s);
114 static int ser_getc(int uart_base);
115 static int have_recv(int base);
116 static void __interrupt __far recv_intr(void);
118 static struct serial_port ports[2];
121 static int uart_base[] = {UART1_BASE, UART2_BASE};
122 static int uart_irq[] = {UART1_IRQ, UART2_IRQ};
124 static void (__interrupt __far *prev_recv_intr)(void);
127 int ser_open(const char *port, int baud, unsigned int mode)
130 unsigned short div = 115200 / baud;
131 int i, pidx, base, intr, fd;
134 if(toupper(port[0]) != 'C' || toupper(port[1]) != 'O' || toupper(port[2]) != 'M'
135 || !isdigit(port[3])) {
136 fprintf(stderr, "ser_open: invalid com port: %s\n", port);
139 pidx = port[3] - '0';
140 if(pidx < 1 || pidx > 2) {
141 fprintf(stderr, "ser_open: invalid com port: %d\n", pidx);
145 if(ports[pidx].base) {
146 fprintf(stderr, "ser_open: port %d already open!\n", pidx);
149 memset(ports + pidx, 0, sizeof ports[pidx]);
151 base = uart_base[pidx];
152 intr = uart_irq[pidx] | 8;
161 if(!prev_recv_intr) {
162 prev_recv_intr = _dos_getvect(intr);
163 _dos_setvect(intr, recv_intr);
165 /* unmask the appropriate interrupt */
166 outp(PIC1_DATA_PORT, inp(PIC1_DATA_PORT) & ~(1 << uart_irq[pidx]));
168 outp(base + UART_LCTL, LCTL_DLAB);
169 outp(base + UART_DIVLO, div & 0xff);
170 outp(base + UART_DIVHI, (div >> 8) & 0xff);
171 outp(base + UART_LCTL, fmt); /* fmt should be LCTL_8N1, LCTL_8N2 etc */
172 outp(base + UART_FIFO, FIFO_ENABLE | FIFO_SEND_CLEAR | FIFO_RECV_CLEAR);
173 outp(base + UART_MCTL, MCTL_DTR | MCTL_RTS | MCTL_OUT2);
174 outp(base + UART_INTR, INTR_RECV);
178 ports[pidx].base = base;
179 ports[pidx].intr = intr;
180 ports[pidx].blocking = 1;
185 void ser_close(int fd)
187 if(--num_open == 0) {
189 outp(ports[fd].base + UART_INTR, 0);
190 outp(ports[fd].base + UART_MCTL, 0);
191 _dos_setvect(ports[fd].intr, prev_recv_intr);
199 int ser_block(int fd)
201 ports[fd].blocking = 1;
205 int ser_nonblock(int fd)
207 ports[fd].blocking = 0;
211 int ser_pending(int fd)
213 return !BEMPTY(ports[fd].inbuf);
216 /* if msec < 0: wait for ever */
217 int ser_wait(int fd, long msec)
220 while(!(res = ser_pending(fd))) {
223 if((msec -= 25) < 0) msec = 0;
229 static int can_send(int fd)
231 int base = ports[fd].base;
232 return inp(base + UART_LSTAT) & LST_TREG_EMPTY;
235 static void ser_putc(int fd, char c)
237 int base = ports[fd].base;
238 while(!can_send(fd));
239 while((inp(base + UART_MSTAT) & MST_CTS) == 0);
240 outp(base + UART_DATA, c);
243 static void ser_puts(int fd, const char *s)
245 int base = ports[fd].base;
251 static int ser_getc(int fd)
253 struct serial_port *p = ports + fd;
257 while(!(have = ser_pending(fd)));
259 have = ser_pending(fd);
263 c = p->inbuf[p->inbuf_ridx];
264 p->inbuf_ridx = BNEXT(p->inbuf_ridx);
269 int ser_write(int fd, const char *buf, int count)
273 ser_putc(fd, *buf++);
278 int ser_read(int fd, char *buf, int count)
281 while(n < count && (c = ser_getc(fd)) != -1) {
288 void ser_printf(int fd, const char *fmt, ...)
290 static char buf[128];
294 vsprintf(buf, fmt, ap);
300 char *ser_getline(int fd, char *buf, int bsz)
302 static char linebuf[512];
304 int i, rd, size, offs;
306 size = sizeof linebuf - widx;
307 while(size && (rd = ser_read(fd, linebuf + widx, size)) > 0) {
314 for(i=0; i<widx; i++) {
315 if(linebuf[i] == '\r' || linebuf[i] == '\n') {
316 size = i >= bsz ? bsz - 1 : i;
317 memcpy(buf, linebuf, size);
321 memmove(linebuf, linebuf + offs, widx - offs);
329 static int have_recv(int base)
331 unsigned short stat = inp(base + UART_LSTAT);
332 if(stat & LST_ERROR) {
333 fprintf(stderr, "receive error\n");
336 return stat & LST_DRDY;
339 static void __interrupt __far recv_intr()
344 int base = uart_base[i];
345 struct serial_port *p = ports + i;
347 while(((idreg = inp(base + UART_IID)) & IID_PENDING) == 0) {
348 while(have_recv(base)) {
349 c = inp(base + UART_DATA);
351 p->inbuf[p->inbuf_widx] = inp(base + UART_DATA);
352 p->inbuf_widx = BNEXT(p->inbuf_widx);
354 if(p->inbuf_widx == p->inbuf_ridx) {
355 /* we overflowed, drop the oldest */
356 p->inbuf_ridx = BNEXT(p->inbuf_ridx);
362 outp(PIC1_CMD_PORT, OCW2_EOI);