ser-go32.c revision 1.11 1 1.1 christos /* Remote serial interface for local (hardwired) serial ports for GO32.
2 1.11 christos Copyright (C) 1992-2024 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos Contributed by Nigel Stephens, Algorithmics Ltd. (nigel (at) algor.co.uk).
5 1.1 christos
6 1.1 christos This version uses DPMI interrupts to handle buffered i/o
7 1.1 christos without the separate "asynctsr" program.
8 1.1 christos
9 1.1 christos This file is part of GDB.
10 1.1 christos
11 1.1 christos This program is free software; you can redistribute it and/or modify
12 1.1 christos it under the terms of the GNU General Public License as published by
13 1.1 christos the Free Software Foundation; either version 3 of the License, or
14 1.1 christos (at your option) any later version.
15 1.1 christos
16 1.1 christos This program is distributed in the hope that it will be useful,
17 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
18 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 1.1 christos GNU General Public License for more details.
20 1.1 christos
21 1.1 christos You should have received a copy of the GNU General Public License
22 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 1.1 christos
24 1.11 christos #include "cli/cli-cmds.h"
25 1.1 christos #include "serial.h"
26 1.1 christos /*
27 1.1 christos * NS16550 UART registers
28 1.1 christos */
29 1.1 christos
30 1.1 christos #define COM1ADDR 0x3f8
31 1.1 christos #define COM2ADDR 0x2f8
32 1.1 christos #define COM3ADDR 0x3e8
33 1.1 christos #define COM4ADDR 0x3e0
34 1.1 christos
35 1.1 christos #define com_data 0 /* data register (R/W) */
36 1.1 christos #define com_dlbl 0 /* divisor latch low (W) */
37 1.1 christos #define com_ier 1 /* interrupt enable (W) */
38 1.1 christos #define com_dlbh 1 /* divisor latch high (W) */
39 1.1 christos #define com_iir 2 /* interrupt identification (R) */
40 1.1 christos #define com_fifo 2 /* FIFO control (W) */
41 1.1 christos #define com_lctl 3 /* line control register (R/W) */
42 1.1 christos #define com_cfcr 3 /* line control register (R/W) */
43 1.1 christos #define com_mcr 4 /* modem control register (R/W) */
44 1.1 christos #define com_lsr 5 /* line status register (R/W) */
45 1.1 christos #define com_msr 6 /* modem status register (R/W) */
46 1.1 christos
47 1.1 christos /*
48 1.1 christos * Constants for computing 16 bit baud rate divisor (lower byte
49 1.1 christos * in com_dlbl, upper in com_dlbh) from 1.8432MHz crystal. Divisor is
50 1.1 christos * 1.8432 MHz / (16 * X) for X bps. If the baud rate can't be set
51 1.1 christos * to within +- (desired_rate*SPEED_TOLERANCE/1000) bps, we fail.
52 1.1 christos */
53 1.1 christos #define COMTICK (1843200/16)
54 1.1 christos #define SPEED_TOLERANCE 30 /* thousandths; real == desired +- 3.0% */
55 1.1 christos
56 1.1 christos /* interrupt enable register */
57 1.1 christos #define IER_ERXRDY 0x1 /* int on rx ready */
58 1.1 christos #define IER_ETXRDY 0x2 /* int on tx ready */
59 1.1 christos #define IER_ERLS 0x4 /* int on line status change */
60 1.1 christos #define IER_EMSC 0x8 /* int on modem status change */
61 1.1 christos
62 1.1 christos /* interrupt identification register */
63 1.1 christos #define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
64 1.1 christos #define IIR_IMASK 0xf /* interrupt cause mask */
65 1.1 christos #define IIR_NOPEND 0x1 /* nothing pending */
66 1.1 christos #define IIR_RLS 0x6 /* receive line status */
67 1.1 christos #define IIR_RXRDY 0x4 /* receive ready */
68 1.1 christos #define IIR_RXTOUT 0xc /* receive timeout */
69 1.1 christos #define IIR_TXRDY 0x2 /* transmit ready */
70 1.1 christos #define IIR_MLSC 0x0 /* modem status */
71 1.1 christos
72 1.1 christos
73 1.1 christos /* fifo control register */
74 1.1 christos #define FIFO_ENABLE 0x01 /* enable fifo */
75 1.1 christos #define FIFO_RCV_RST 0x02 /* reset receive fifo */
76 1.1 christos #define FIFO_XMT_RST 0x04 /* reset transmit fifo */
77 1.1 christos #define FIFO_DMA_MODE 0x08 /* enable dma mode */
78 1.1 christos #define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */
79 1.1 christos #define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */
80 1.1 christos #define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */
81 1.1 christos #define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */
82 1.1 christos
83 1.1 christos /* character format control register */
84 1.1 christos #define CFCR_DLAB 0x80 /* divisor latch */
85 1.1 christos #define CFCR_SBREAK 0x40 /* send break */
86 1.1 christos #define CFCR_PZERO 0x30 /* zero parity */
87 1.1 christos #define CFCR_PONE 0x20 /* one parity */
88 1.1 christos #define CFCR_PEVEN 0x10 /* even parity */
89 1.1 christos #define CFCR_PODD 0x00 /* odd parity */
90 1.1 christos #define CFCR_PENAB 0x08 /* parity enable */
91 1.1 christos #define CFCR_STOPB 0x04 /* 2 stop bits */
92 1.1 christos #define CFCR_8BITS 0x03 /* 8 data bits */
93 1.1 christos #define CFCR_7BITS 0x02 /* 7 data bits */
94 1.1 christos #define CFCR_6BITS 0x01 /* 6 data bits */
95 1.1 christos #define CFCR_5BITS 0x00 /* 5 data bits */
96 1.1 christos
97 1.1 christos /* modem control register */
98 1.1 christos #define MCR_LOOPBACK 0x10 /* loopback */
99 1.1 christos #define MCR_IENABLE 0x08 /* output 2 = int enable */
100 1.1 christos #define MCR_DRS 0x04 /* output 1 = xxx */
101 1.1 christos #define MCR_RTS 0x02 /* enable RTS */
102 1.1 christos #define MCR_DTR 0x01 /* enable DTR */
103 1.1 christos
104 1.1 christos /* line status register */
105 1.1 christos #define LSR_RCV_FIFO 0x80 /* error in receive fifo */
106 1.1 christos #define LSR_TSRE 0x40 /* transmitter empty */
107 1.1 christos #define LSR_TXRDY 0x20 /* transmitter ready */
108 1.1 christos #define LSR_BI 0x10 /* break detected */
109 1.1 christos #define LSR_FE 0x08 /* framing error */
110 1.1 christos #define LSR_PE 0x04 /* parity error */
111 1.1 christos #define LSR_OE 0x02 /* overrun error */
112 1.1 christos #define LSR_RXRDY 0x01 /* receiver ready */
113 1.1 christos #define LSR_RCV_MASK 0x1f
114 1.1 christos
115 1.1 christos /* modem status register */
116 1.1 christos #define MSR_DCD 0x80
117 1.1 christos #define MSR_RI 0x40
118 1.1 christos #define MSR_DSR 0x20
119 1.1 christos #define MSR_CTS 0x10
120 1.1 christos #define MSR_DDCD 0x08
121 1.1 christos #define MSR_TERI 0x04
122 1.1 christos #define MSR_DDSR 0x02
123 1.1 christos #define MSR_DCTS 0x01
124 1.1 christos
125 1.1 christos #include <time.h>
126 1.1 christos #include <dos.h>
127 1.1 christos #include <go32.h>
128 1.1 christos #include <dpmi.h>
129 1.1 christos typedef unsigned long u_long;
130 1.1 christos
131 1.1 christos /* 16550 rx fifo trigger point */
132 1.1 christos #define FIFO_TRIGGER FIFO_TRIGGER_4
133 1.1 christos
134 1.1 christos /* input buffer size */
135 1.1 christos #define CBSIZE 4096
136 1.1 christos
137 1.1 christos #define RAWHZ 18
138 1.1 christos
139 1.1 christos #ifdef DOS_STATS
140 1.1 christos #define CNT_RX 16
141 1.1 christos #define CNT_TX 17
142 1.1 christos #define CNT_STRAY 18
143 1.1 christos #define CNT_ORUN 19
144 1.1 christos #define NCNT 20
145 1.1 christos
146 1.1 christos static int intrcnt;
147 1.1 christos static size_t cnts[NCNT];
148 1.1 christos static char *cntnames[NCNT] =
149 1.1 christos {
150 1.1 christos /* h/w interrupt counts. */
151 1.1 christos "mlsc", "nopend", "txrdy", "?3",
152 1.1 christos "rxrdy", "?5", "rls", "?7",
153 1.1 christos "?8", "?9", "?a", "?b",
154 1.1 christos "rxtout", "?d", "?e", "?f",
155 1.1 christos /* s/w counts. */
156 1.1 christos "rxcnt", "txcnt", "stray", "swoflo"
157 1.1 christos };
158 1.1 christos
159 1.1 christos #define COUNT(x) cnts[x]++
160 1.1 christos #else
161 1.1 christos #define COUNT(x)
162 1.1 christos #endif
163 1.1 christos
164 1.1 christos /* Main interrupt controller port addresses. */
165 1.1 christos #define ICU_BASE 0x20
166 1.1 christos #define ICU_OCW2 (ICU_BASE + 0)
167 1.1 christos #define ICU_MASK (ICU_BASE + 1)
168 1.1 christos
169 1.1 christos /* Original interrupt controller mask register. */
170 1.1 christos unsigned char icu_oldmask;
171 1.1 christos
172 1.1 christos /* Maximum of 8 interrupts (we don't handle the slave icu yet). */
173 1.1 christos #define NINTR 8
174 1.1 christos
175 1.1 christos static struct intrupt
176 1.1 christos {
177 1.1 christos char inuse;
178 1.1 christos struct dos_ttystate *port;
179 1.1 christos _go32_dpmi_seginfo old_rmhandler;
180 1.1 christos _go32_dpmi_seginfo old_pmhandler;
181 1.1 christos _go32_dpmi_seginfo new_rmhandler;
182 1.1 christos _go32_dpmi_seginfo new_pmhandler;
183 1.1 christos _go32_dpmi_registers regs;
184 1.1 christos }
185 1.1 christos intrupts[NINTR];
186 1.1 christos
187 1.1 christos
188 1.1 christos static struct dos_ttystate
189 1.1 christos {
190 1.1 christos int base;
191 1.1 christos int irq;
192 1.1 christos int refcnt;
193 1.1 christos struct intrupt *intrupt;
194 1.1 christos int fifo;
195 1.1 christos int baudrate;
196 1.1 christos unsigned char cbuf[CBSIZE];
197 1.1 christos unsigned int first;
198 1.1 christos unsigned int count;
199 1.1 christos int txbusy;
200 1.1 christos unsigned char old_mcr;
201 1.1 christos int ferr;
202 1.1 christos int perr;
203 1.1 christos int oflo;
204 1.1 christos int msr;
205 1.1 christos }
206 1.1 christos ports[4] =
207 1.1 christos {
208 1.1 christos {
209 1.1 christos COM1ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
210 1.1 christos }
211 1.1 christos ,
212 1.1 christos {
213 1.1 christos COM2ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
214 1.1 christos }
215 1.1 christos ,
216 1.1 christos {
217 1.1 christos COM3ADDR, 4, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
218 1.1 christos }
219 1.1 christos ,
220 1.1 christos {
221 1.1 christos COM4ADDR, 3, 0, NULL, 0, 0, "", 0, 0, 0, 0, 0, 0, 0, 0
222 1.1 christos }
223 1.1 christos };
224 1.1 christos
225 1.1 christos static int dos_open (struct serial *scb, const char *name);
226 1.1 christos static void dos_raw (struct serial *scb);
227 1.1 christos static int dos_readchar (struct serial *scb, int timeout);
228 1.1 christos static int dos_setbaudrate (struct serial *scb, int rate);
229 1.1 christos static int dos_write (struct serial *scb, const void *buf, size_t count);
230 1.1 christos static void dos_close (struct serial *scb);
231 1.1 christos static serial_ttystate dos_get_tty_state (struct serial *scb);
232 1.1 christos static int dos_set_tty_state (struct serial *scb, serial_ttystate state);
233 1.1 christos static int dos_baudconv (int rate);
234 1.1 christos
235 1.1 christos #define inb(p,a) inportb((p)->base + (a))
236 1.1 christos #define outb(p,a,v) outportb((p)->base + (a), (v))
237 1.1 christos #define disable() asm volatile ("cli");
238 1.1 christos #define enable() asm volatile ("sti");
239 1.1 christos
240 1.1 christos
241 1.1 christos static int
242 1.1 christos dos_getc (volatile struct dos_ttystate *port)
243 1.1 christos {
244 1.1 christos int c;
245 1.1 christos
246 1.1 christos if (port->count == 0)
247 1.1 christos return -1;
248 1.1 christos
249 1.1 christos c = port->cbuf[port->first];
250 1.1 christos disable ();
251 1.1 christos port->first = (port->first + 1) & (CBSIZE - 1);
252 1.1 christos port->count--;
253 1.1 christos enable ();
254 1.1 christos return c;
255 1.1 christos }
256 1.1 christos
257 1.1 christos
258 1.1 christos static int
259 1.1 christos dos_putc (int c, struct dos_ttystate *port)
260 1.1 christos {
261 1.1 christos if (port->count >= CBSIZE - 1)
262 1.1 christos return -1;
263 1.1 christos port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
264 1.1 christos port->count++;
265 1.1 christos return 0;
266 1.1 christos }
267 1.1 christos
268 1.1 christos
270 1.1 christos
271 1.1 christos static void
272 1.1 christos dos_comisr (int irq)
273 1.1 christos {
274 1.1 christos struct dos_ttystate *port;
275 1.1 christos unsigned char iir, lsr, c;
276 1.1 christos
277 1.1 christos disable (); /* Paranoia */
278 1.1 christos outportb (ICU_OCW2, 0x20); /* End-Of-Interrupt */
279 1.1 christos #ifdef DOS_STATS
280 1.1 christos ++intrcnt;
281 1.1 christos #endif
282 1.1 christos
283 1.1 christos port = intrupts[irq].port;
284 1.1 christos if (!port)
285 1.1 christos {
286 1.1 christos COUNT (CNT_STRAY);
287 1.1 christos return; /* not open */
288 1.1 christos }
289 1.1 christos
290 1.1 christos while (1)
291 1.1 christos {
292 1.1 christos iir = inb (port, com_iir) & IIR_IMASK;
293 1.1 christos switch (iir)
294 1.1 christos {
295 1.1 christos
296 1.1 christos case IIR_RLS:
297 1.1 christos lsr = inb (port, com_lsr);
298 1.1 christos goto rx;
299 1.1 christos
300 1.1 christos case IIR_RXTOUT:
301 1.1 christos case IIR_RXRDY:
302 1.1 christos lsr = 0;
303 1.1 christos
304 1.1 christos rx:
305 1.1 christos do
306 1.1 christos {
307 1.1 christos c = inb (port, com_data);
308 1.1 christos if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
309 1.1 christos {
310 1.1 christos if (lsr & (LSR_BI | LSR_FE))
311 1.1 christos port->ferr++;
312 1.1 christos else if (lsr & LSR_PE)
313 1.1 christos port->perr++;
314 1.1 christos if (lsr & LSR_OE)
315 1.1 christos port->oflo++;
316 1.1 christos }
317 1.1 christos
318 1.1 christos if (dos_putc (c, port) < 0)
319 1.1 christos {
320 1.1 christos COUNT (CNT_ORUN);
321 1.1 christos }
322 1.1 christos else
323 1.1 christos {
324 1.1 christos COUNT (CNT_RX);
325 1.1 christos }
326 1.1 christos }
327 1.1 christos while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
328 1.1 christos break;
329 1.1 christos
330 1.1 christos case IIR_MLSC:
331 1.1 christos /* could be used to flowcontrol Tx */
332 1.1 christos port->msr = inb (port, com_msr);
333 1.1 christos break;
334 1.1 christos
335 1.1 christos case IIR_TXRDY:
336 1.1 christos port->txbusy = 0;
337 1.1 christos break;
338 1.1 christos
339 1.1 christos case IIR_NOPEND:
340 1.1 christos /* No more pending interrupts, all done. */
341 1.1 christos return;
342 1.1 christos
343 1.1 christos default:
344 1.1 christos /* Unexpected interrupt, ignore. */
345 1.1 christos break;
346 1.1 christos }
347 1.1 christos COUNT (iir);
348 1.1 christos }
349 1.1 christos }
350 1.1 christos
351 1.1 christos #define ISRNAME(x) dos_comisr##x
352 1.1 christos #define ISR(x) static void ISRNAME(x)(void) {dos_comisr(x);}
353 1.1 christos
354 1.1 christos ISR (0) ISR (1) ISR (2) ISR (3) /* OK */
355 1.1 christos ISR (4) ISR (5) ISR (6) ISR (7) /* OK */
356 1.1 christos
357 1.1 christos typedef void (*isr_t) (void);
358 1.1 christos
359 1.1 christos static isr_t isrs[NINTR] =
360 1.1 christos {
361 1.1 christos ISRNAME (0), ISRNAME (1), ISRNAME (2), ISRNAME (3),
362 1.1 christos ISRNAME (4), ISRNAME (5), ISRNAME (6), ISRNAME (7)
363 1.1 christos };
364 1.1 christos
365 1.1 christos
367 1.1 christos
368 1.1 christos static struct intrupt *
369 1.1 christos dos_hookirq (unsigned int irq)
370 1.1 christos {
371 1.1 christos struct intrupt *intr;
372 1.1 christos unsigned int vec;
373 1.1 christos isr_t isr;
374 1.1 christos
375 1.1 christos if (irq >= NINTR)
376 1.1 christos return 0;
377 1.1 christos
378 1.1 christos intr = &intrupts[irq];
379 1.1 christos if (intr->inuse)
380 1.1 christos return 0;
381 1.1 christos
382 1.1 christos vec = 0x08 + irq;
383 1.1 christos isr = isrs[irq];
384 1.1 christos
385 1.1 christos /* Setup real mode handler. */
386 1.1 christos _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
387 1.1 christos
388 1.1 christos intr->new_rmhandler.pm_selector = _go32_my_cs ();
389 1.1 christos intr->new_rmhandler.pm_offset = (u_long) isr;
390 1.1 christos if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
391 1.1 christos &intr->regs))
392 1.1 christos {
393 1.1 christos return 0;
394 1.1 christos }
395 1.1 christos
396 1.1 christos if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
397 1.1 christos {
398 1.1 christos return 0;
399 1.1 christos }
400 1.1 christos
401 1.1 christos /* Setup protected mode handler. */
402 1.1 christos _go32_dpmi_get_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
403 1.1 christos
404 1.1 christos intr->new_pmhandler.pm_selector = _go32_my_cs ();
405 1.1 christos intr->new_pmhandler.pm_offset = (u_long) isr;
406 1.1 christos _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
407 1.1 christos
408 1.1 christos if (_go32_dpmi_set_protected_mode_interrupt_vector (vec,
409 1.1 christos &intr->new_pmhandler))
410 1.1 christos {
411 1.1 christos return 0;
412 1.1 christos }
413 1.1 christos
414 1.1 christos /* Setup interrupt controller mask. */
415 1.1 christos disable ();
416 1.1 christos outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
417 1.1 christos enable ();
418 1.1 christos
419 1.1 christos intr->inuse = 1;
420 1.1 christos return intr;
421 1.1 christos }
422 1.1 christos
423 1.1 christos
424 1.1 christos static void
425 1.1 christos dos_unhookirq (struct intrupt *intr)
426 1.1 christos {
427 1.1 christos unsigned int irq, vec;
428 1.1 christos unsigned char mask;
429 1.1 christos
430 1.1 christos irq = intr - intrupts;
431 1.1 christos vec = 0x08 + irq;
432 1.1 christos
433 1.1 christos /* Restore old interrupt mask bit. */
434 1.1 christos mask = 1 << irq;
435 1.1 christos disable ();
436 1.1 christos outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
437 1.1 christos enable ();
438 1.1 christos
439 1.1 christos /* Remove real mode handler. */
440 1.1 christos _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
441 1.1 christos _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
442 1.1 christos
443 1.1 christos /* Remove protected mode handler. */
444 1.1 christos _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
445 1.1 christos _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
446 1.1 christos intr->inuse = 0;
447 1.1 christos }
448 1.1 christos
449 1.1 christos
451 1.1 christos
452 1.1 christos static int
453 1.1 christos dos_open (struct serial *scb, const char *name)
454 1.1 christos {
455 1.1 christos struct dos_ttystate *port;
456 1.1 christos int fd, i;
457 1.1 christos
458 1.1 christos if (strncasecmp (name, "/dev/", 5) == 0)
459 1.1 christos name += 5;
460 1.1 christos else if (strncasecmp (name, "\\dev\\", 5) == 0)
461 1.1 christos name += 5;
462 1.1 christos
463 1.1 christos if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
464 1.1 christos {
465 1.1 christos errno = ENOENT;
466 1.1 christos return -1;
467 1.1 christos }
468 1.1 christos
469 1.1 christos if (name[3] < '1' || name[3] > '4')
470 1.1 christos {
471 1.1 christos errno = ENOENT;
472 1.1 christos return -1;
473 1.1 christos }
474 1.1 christos
475 1.1 christos /* FIXME: this is a Bad Idea (tm)! One should *never* invent file
476 1.1 christos handles, since they might be already used by other files/devices.
477 1.1 christos The Right Way to do this is to create a real handle by dup()'ing
478 1.1 christos some existing one. */
479 1.1 christos fd = name[3] - '1';
480 1.1 christos port = &ports[fd];
481 1.1 christos if (port->refcnt++ > 0)
482 1.1 christos {
483 1.1 christos /* Device already opened another user. Just point at it. */
484 1.1 christos scb->fd = fd;
485 1.1 christos return 0;
486 1.1 christos }
487 1.1 christos
488 1.1 christos /* Force access to ID reg. */
489 1.1 christos outb (port, com_cfcr, 0);
490 1.1 christos outb (port, com_iir, 0);
491 1.1 christos for (i = 0; i < 17; i++)
492 1.1 christos {
493 1.1 christos if ((inb (port, com_iir) & 0x38) == 0)
494 1.1 christos goto ok;
495 1.1 christos (void) inb (port, com_data); /* clear recv */
496 1.1 christos }
497 1.1 christos errno = ENODEV;
498 1.1 christos return -1;
499 1.1 christos
500 1.1 christos ok:
501 1.1 christos /* Disable all interrupts in chip. */
502 1.1 christos outb (port, com_ier, 0);
503 1.1 christos
504 1.1 christos /* Tentatively enable 16550 fifo, and see if it responds. */
505 1.1 christos outb (port, com_fifo,
506 1.1 christos FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER);
507 1.1 christos sleep (1);
508 1.1 christos port->fifo = ((inb (port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
509 1.1 christos
510 1.1 christos /* clear pending status reports. */
511 1.1 christos (void) inb (port, com_lsr);
512 1.1 christos (void) inb (port, com_msr);
513 1.1 christos
514 1.1 christos /* Enable external interrupt gate (to avoid floating IRQ). */
515 1.1 christos outb (port, com_mcr, MCR_IENABLE);
516 1.1 christos
517 1.1 christos /* Hook up interrupt handler and initialise icu. */
518 1.1 christos port->intrupt = dos_hookirq (port->irq);
519 1.1 christos if (!port->intrupt)
520 1.1 christos {
521 1.1 christos outb (port, com_mcr, 0);
522 1.1 christos outb (port, com_fifo, 0);
523 1.1 christos errno = ENODEV;
524 1.1 christos return -1;
525 1.1 christos }
526 1.1 christos
527 1.1 christos disable ();
528 1.1 christos
529 1.1 christos /* record port */
530 1.1 christos port->intrupt->port = port;
531 1.1 christos scb->fd = fd;
532 1.1 christos
533 1.1 christos /* Clear rx buffer, tx busy flag and overflow count. */
534 1.1 christos port->first = port->count = 0;
535 1.1 christos port->txbusy = 0;
536 1.1 christos port->oflo = 0;
537 1.1 christos
538 1.1 christos /* Set default baud rate and mode: 9600,8,n,1 */
539 1.1 christos i = dos_baudconv (port->baudrate = 9600);
540 1.1 christos outb (port, com_cfcr, CFCR_DLAB);
541 1.1 christos outb (port, com_dlbl, i & 0xff);
542 1.1 christos outb (port, com_dlbh, i >> 8);
543 1.1 christos outb (port, com_cfcr, CFCR_8BITS);
544 1.1 christos
545 1.1 christos /* Enable all interrupts. */
546 1.1 christos outb (port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
547 1.1 christos
548 1.1 christos /* Enable DTR & RTS. */
549 1.1 christos outb (port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
550 1.1 christos
551 1.1 christos enable ();
552 1.1 christos
553 1.1 christos return 0;
554 1.1 christos }
555 1.1 christos
556 1.1 christos
557 1.1 christos static void
558 1.1 christos dos_close (struct serial *scb)
559 1.1 christos {
560 1.1 christos struct dos_ttystate *port;
561 1.1 christos struct intrupt *intrupt;
562 1.1 christos
563 1.1 christos if (!scb)
564 1.1 christos return;
565 1.1 christos
566 1.1 christos port = &ports[scb->fd];
567 1.1 christos
568 1.1 christos if (port->refcnt-- > 1)
569 1.1 christos return;
570 1.1 christos
571 1.1 christos if (!(intrupt = port->intrupt))
572 1.1 christos return;
573 1.1 christos
574 1.1 christos /* Disable interrupts, fifo, flow control. */
575 1.1 christos disable ();
576 1.1 christos port->intrupt = 0;
577 1.1 christos intrupt->port = 0;
578 1.1 christos outb (port, com_fifo, 0);
579 1.1 christos outb (port, com_ier, 0);
580 1.1 christos enable ();
581 1.1 christos
582 1.1 christos /* Unhook handler, and disable interrupt gate. */
583 1.1 christos dos_unhookirq (intrupt);
584 1.1 christos outb (port, com_mcr, 0);
585 1.1 christos
586 1.10 christos /* Check for overflow errors. */
587 1.10 christos if (port->oflo)
588 1.10 christos {
589 1.10 christos gdb_printf (gdb_stderr,
590 1.10 christos "Serial input overruns occurred.\n");
591 1.1 christos gdb_printf (gdb_stderr, "This system %s handle %d baud.\n",
592 1.1 christos port->fifo ? "cannot" : "needs a 16550 to",
593 1.1 christos port->baudrate);
594 1.1 christos }
595 1.6 christos }
596 1.1 christos
597 1.1 christos
599 1.6 christos /* Implementation of the serial_ops flush_output method. */
600 1.6 christos
601 1.6 christos static int
602 1.6 christos dos_flush_output (struct serial *scb)
603 1.6 christos {
604 1.6 christos return 0;
605 1.6 christos }
606 1.6 christos
607 1.6 christos /* Implementation of the serial_ops setparity method. */
608 1.6 christos
609 1.6 christos static int
610 1.6 christos dos_setparity (struct serial *scb, int parity)
611 1.6 christos {
612 1.6 christos return 0;
613 1.6 christos }
614 1.6 christos
615 1.1 christos /* Implementation of the serial_ops drain_output method. */
616 1.1 christos
617 1.1 christos static int
618 1.1 christos dos_drain_output (struct serial *scb)
619 1.1 christos {
620 1.1 christos return 0;
621 1.1 christos }
622 1.1 christos
623 1.1 christos static void
624 1.1 christos dos_raw (struct serial *scb)
625 1.1 christos {
626 1.1 christos /* Always in raw mode. */
627 1.1 christos }
628 1.1 christos
629 1.1 christos static int
630 1.1 christos dos_readchar (struct serial *scb, int timeout)
631 1.1 christos {
632 1.1 christos struct dos_ttystate *port = &ports[scb->fd];
633 1.1 christos long then;
634 1.1 christos int c;
635 1.6 christos
636 1.6 christos then = rawclock () + (timeout * RAWHZ);
637 1.1 christos while ((c = dos_getc (port)) < 0)
638 1.1 christos {
639 1.1 christos QUIT;
640 1.1 christos
641 1.1 christos if (timeout >= 0 && (rawclock () - then) >= 0)
642 1.1 christos return SERIAL_TIMEOUT;
643 1.1 christos }
644 1.1 christos
645 1.1 christos return c;
646 1.1 christos }
647 1.1 christos
648 1.1 christos
649 1.1 christos static serial_ttystate
650 1.1 christos dos_get_tty_state (struct serial *scb)
651 1.1 christos {
652 1.1 christos struct dos_ttystate *port = &ports[scb->fd];
653 1.1 christos struct dos_ttystate *state;
654 1.1 christos
655 1.1 christos /* Are they asking about a port we opened? */
656 1.1 christos if (port->refcnt <= 0)
657 1.9 christos {
658 1.1 christos /* We've never heard about this port. We should fail this call,
659 1.1 christos unless they are asking about one of the 3 standard handles,
660 1.1 christos in which case we pretend the handle was open by us if it is
661 1.1 christos connected to a terminal device. This is because Unix
662 1.1 christos terminals use the serial interface, so GDB expects the
663 1.1 christos standard handles to go through here. */
664 1.6 christos if (scb->fd >= 3 || !isatty (scb->fd))
665 1.1 christos return NULL;
666 1.1 christos }
667 1.1 christos
668 1.1 christos state = XNEW (struct dos_ttystate);
669 1.1 christos *state = *port;
670 1.1 christos return (serial_ttystate) state;
671 1.1 christos }
672 1.1 christos
673 1.1 christos static serial_ttystate
674 1.6 christos dos_copy_tty_state (struct serial *scb, serial_ttystate ttystate)
675 1.1 christos {
676 1.1 christos struct dos_ttystate *state;
677 1.1 christos
678 1.1 christos state = XNEW (struct dos_ttystate);
679 1.1 christos *state = *(struct dos_ttystate *) ttystate;
680 1.1 christos
681 1.1 christos return (serial_ttystate) state;
682 1.1 christos }
683 1.1 christos
684 1.1 christos static int
685 1.1 christos dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
686 1.1 christos {
687 1.1 christos struct dos_ttystate *state;
688 1.1 christos
689 1.1 christos state = (struct dos_ttystate *) ttystate;
690 1.1 christos dos_setbaudrate (scb, state->baudrate);
691 1.1 christos return 0;
692 1.1 christos }
693 1.1 christos
694 1.1 christos static int
695 1.1 christos dos_flush_input (struct serial *scb)
696 1.1 christos {
697 1.1 christos struct dos_ttystate *port = &ports[scb->fd];
698 1.1 christos
699 1.1 christos disable ();
700 1.1 christos port->first = port->count = 0;
701 1.1 christos if (port->fifo)
702 1.1 christos outb (port, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_TRIGGER);
703 1.1 christos enable ();
704 1.1 christos return 0;
705 1.1 christos }
706 1.1 christos
707 1.1 christos static void
708 1.1 christos dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
709 1.1 christos struct ui_file *stream)
710 1.1 christos {
711 1.1 christos /* Nothing to print. */
712 1.1 christos return;
713 1.1 christos }
714 1.1 christos
715 1.1 christos static int
716 1.1 christos dos_baudconv (int rate)
717 1.1 christos {
718 1.1 christos long x, err;
719 1.1 christos
720 1.1 christos if (rate <= 0)
721 1.1 christos return -1;
722 1.1 christos
723 1.1 christos #define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* Divide and round off. */
724 1.1 christos x = divrnd (COMTICK, rate);
725 1.1 christos if (x <= 0)
726 1.1 christos return -1;
727 1.1 christos
728 1.1 christos err = divrnd (1000 * COMTICK, x * rate) - 1000;
729 1.1 christos if (err < 0)
730 1.1 christos err = -err;
731 1.1 christos if (err > SPEED_TOLERANCE)
732 1.1 christos return -1;
733 1.1 christos #undef divrnd
734 1.1 christos return x;
735 1.1 christos }
736 1.1 christos
737 1.1 christos
738 1.1 christos static int
739 1.1 christos dos_setbaudrate (struct serial *scb, int rate)
740 1.1 christos {
741 1.1 christos struct dos_ttystate *port = &ports[scb->fd];
742 1.1 christos
743 1.1 christos if (port->baudrate != rate)
744 1.1 christos {
745 1.1 christos int x;
746 1.1 christos unsigned char cfcr;
747 1.10 christos
748 1.1 christos x = dos_baudconv (rate);
749 1.1 christos if (x <= 0)
750 1.1 christos {
751 1.1 christos gdb_printf (gdb_stderr, "%d: impossible baudrate\n", rate);
752 1.1 christos errno = EINVAL;
753 1.1 christos return -1;
754 1.1 christos }
755 1.1 christos
756 1.1 christos disable ();
757 1.1 christos cfcr = inb (port, com_cfcr);
758 1.1 christos
759 1.1 christos outb (port, com_cfcr, CFCR_DLAB);
760 1.1 christos outb (port, com_dlbl, x & 0xff);
761 1.1 christos outb (port, com_dlbh, x >> 8);
762 1.1 christos outb (port, com_cfcr, cfcr);
763 1.1 christos port->baudrate = rate;
764 1.1 christos enable ();
765 1.1 christos }
766 1.1 christos
767 1.1 christos return 0;
768 1.1 christos }
769 1.1 christos
770 1.1 christos static int
771 1.1 christos dos_setstopbits (struct serial *scb, int num)
772 1.1 christos {
773 1.1 christos struct dos_ttystate *port = &ports[scb->fd];
774 1.1 christos unsigned char cfcr;
775 1.1 christos
776 1.1 christos disable ();
777 1.1 christos cfcr = inb (port, com_cfcr);
778 1.1 christos
779 1.1 christos switch (num)
780 1.1 christos {
781 1.1 christos case SERIAL_1_STOPBITS:
782 1.1 christos outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
783 1.1 christos break;
784 1.1 christos case SERIAL_1_AND_A_HALF_STOPBITS:
785 1.1 christos case SERIAL_2_STOPBITS:
786 1.1 christos outb (port, com_cfcr, cfcr | CFCR_STOPB);
787 1.1 christos break;
788 1.1 christos default:
789 1.1 christos enable ();
790 1.1 christos return 1;
791 1.1 christos }
792 1.1 christos enable ();
793 1.1 christos
794 1.1 christos return 0;
795 1.1 christos }
796 1.1 christos
797 1.1 christos static int
798 1.1 christos dos_write (struct serial *scb, const void *buf, size_t count)
799 1.1 christos {
800 1.6 christos volatile struct dos_ttystate *port = &ports[scb->fd];
801 1.1 christos size_t fifosize = port->fifo ? 16 : 1;
802 1.1 christos long then;
803 1.1 christos size_t cnt;
804 1.6 christos const char *str = (const char *) buf;
805 1.6 christos
806 1.1 christos while (count > 0)
807 1.1 christos {
808 1.1 christos QUIT;
809 1.1 christos
810 1.1 christos /* Send the data, fifosize bytes at a time. */
811 1.1 christos cnt = fifosize > count ? count : fifosize;
812 1.1 christos port->txbusy = 1;
813 1.1 christos /* Francisco Pastor <fpastor.etra-id (at) etra.es> says OUTSB messes
814 1.1 christos up the communications with UARTs with FIFOs. */
815 1.1 christos #ifdef UART_FIFO_WORKS
816 1.1 christos outportsb (port->base + com_data, str, cnt);
817 1.1 christos str += cnt;
818 1.1 christos count -= cnt;
819 1.1 christos #else
820 1.1 christos for ( ; cnt > 0; cnt--, count--)
821 1.1 christos outportb (port->base + com_data, *str++);
822 1.1 christos #endif
823 1.1 christos #ifdef DOS_STATS
824 1.1 christos cnts[CNT_TX] += cnt;
825 1.1 christos #endif
826 1.1 christos /* Wait for transmission to complete (max 1 sec). */
827 1.1 christos then = rawclock () + RAWHZ;
828 1.1 christos while (port->txbusy)
829 1.1 christos {
830 1.1 christos if ((rawclock () - then) >= 0)
831 1.1 christos {
832 1.1 christos errno = EIO;
833 1.1 christos return SERIAL_ERROR;
834 1.1 christos }
835 1.1 christos }
836 1.1 christos }
837 1.1 christos return 0;
838 1.1 christos }
839 1.1 christos
840 1.1 christos
841 1.1 christos static int
842 1.1 christos dos_sendbreak (struct serial *scb)
843 1.1 christos {
844 1.1 christos volatile struct dos_ttystate *port = &ports[scb->fd];
845 1.1 christos unsigned char cfcr;
846 1.1 christos long then;
847 1.1 christos
848 1.1 christos cfcr = inb (port, com_cfcr);
849 1.1 christos outb (port, com_cfcr, cfcr | CFCR_SBREAK);
850 1.1 christos
851 1.1 christos /* 0.25 sec delay */
852 1.1 christos then = rawclock () + RAWHZ / 4;
853 1.1 christos while ((rawclock () - then) < 0)
854 1.1 christos continue;
855 1.1 christos
856 1.1 christos outb (port, com_cfcr, cfcr);
857 1.1 christos return 0;
858 1.1 christos }
859 1.1 christos
860 1.1 christos
861 1.1 christos static const struct serial_ops dos_ops =
862 1.1 christos {
863 1.1 christos "hardwire",
864 1.1 christos dos_open,
865 1.6 christos dos_close,
866 1.1 christos NULL, /* fdopen, not implemented */
867 1.1 christos dos_readchar,
868 1.1 christos dos_write,
869 1.1 christos dos_flush_output,
870 1.1 christos dos_flush_input,
871 1.1 christos dos_sendbreak,
872 1.1 christos dos_raw,
873 1.1 christos dos_get_tty_state,
874 1.1 christos dos_copy_tty_state,
875 1.6 christos dos_set_tty_state,
876 1.6 christos dos_print_tty_state,
877 1.1 christos dos_setbaudrate,
878 1.1 christos dos_setstopbits,
879 1.1 christos dos_setparity,
880 1.1 christos dos_drain_output,
881 1.1 christos (void (*)(struct serial *, int))NULL /* Change into async mode. */
882 1.1 christos };
883 1.1 christos
884 1.1 christos int
885 1.1 christos gdb_pipe (int pdes[2])
886 1.1 christos {
887 1.1 christos /* No support for pipes. */
888 1.1 christos errno = ENOSYS;
889 1.8 christos return -1;
890 1.1 christos }
891 1.1 christos
892 1.1 christos static void
893 1.1 christos info_serial_command (const char *arg, int from_tty)
894 1.1 christos {
895 1.1 christos struct dos_ttystate *port;
896 1.1 christos #ifdef DOS_STATS
897 1.1 christos int i;
898 1.1 christos #endif
899 1.1 christos
900 1.10 christos for (port = ports; port < &ports[4]; port++)
901 1.10 christos {
902 1.10 christos if (port->baudrate == 0)
903 1.10 christos continue;
904 1.10 christos gdb_printf ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
905 1.10 christos port->intrupt ? "" : "not ");
906 1.10 christos gdb_printf ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
907 1.1 christos gdb_printf ("16550:\t%s\n", port->fifo ? "yes" : "no");
908 1.1 christos gdb_printf ("Speed:\t%d baud\n", port->baudrate);
909 1.1 christos gdb_printf ("Errs:\tframing %d parity %d overflow %d\n\n",
910 1.10 christos port->ferr, port->perr, port->oflo);
911 1.1 christos }
912 1.1 christos
913 1.10 christos #ifdef DOS_STATS
914 1.1 christos gdb_printf ("\nTotal interrupts: %d\n", intrcnt);
915 1.1 christos for (i = 0; i < NCNT; i++)
916 1.1 christos if (cnts[i])
917 1.9 christos gdb_printf ("%s:\t%lu\n", cntnames[i], (unsigned long) cnts[i]);
918 1.1 christos #endif
919 1.9 christos }
920 1.1 christos
921 1.1 christos void _initialize_ser_dos ();
922 1.1 christos void
923 1.1 christos _initialize_ser_dos ()
924 1.1 christos {
925 1.1 christos serial_add_interface (&dos_ops);
926 1.1 christos
927 1.1 christos /* Save original interrupt mask register. */
928 1.1 christos icu_oldmask = inportb (ICU_MASK);
929 1.1 christos
930 1.1 christos /* Mark fixed motherboard irqs as inuse. */
931 1.1 christos intrupts[0].inuse = /* timer tick */
932 1.1 christos intrupts[1].inuse = /* keyboard */
933 1.1 christos intrupts[2].inuse = 1; /* slave icu */
934 1.1 christos
935 1.1 christos add_setshow_zinteger_cmd ("com1base", class_obscure, &ports[0].base, _("\
936 1.1 christos Set COM1 base i/o port address."), _("\
937 1.1 christos Show COM1 base i/o port address."), NULL,
938 1.1 christos NULL,
939 1.1 christos NULL, /* FIXME: i18n: */
940 1.1 christos &setlist, &showlist);
941 1.1 christos
942 1.1 christos add_setshow_zinteger_cmd ("com1irq", class_obscure, &ports[0].irq, _("\
943 1.1 christos Set COM1 interrupt request."), _("\
944 1.1 christos Show COM1 interrupt request."), NULL,
945 1.1 christos NULL,
946 1.1 christos NULL, /* FIXME: i18n: */
947 1.1 christos &setlist, &showlist);
948 1.1 christos
949 1.1 christos add_setshow_zinteger_cmd ("com2base", class_obscure, &ports[1].base, _("\
950 1.1 christos Set COM2 base i/o port address."), _("\
951 1.1 christos Show COM2 base i/o port address."), NULL,
952 1.1 christos NULL,
953 1.1 christos NULL, /* FIXME: i18n: */
954 1.1 christos &setlist, &showlist);
955 1.1 christos
956 1.1 christos add_setshow_zinteger_cmd ("com2irq", class_obscure, &ports[1].irq, _("\
957 1.1 christos Set COM2 interrupt request."), _("\
958 1.1 christos Show COM2 interrupt request."), NULL,
959 1.1 christos NULL,
960 1.1 christos NULL, /* FIXME: i18n: */
961 1.1 christos &setlist, &showlist);
962 1.1 christos
963 1.1 christos add_setshow_zinteger_cmd ("com3base", class_obscure, &ports[2].base, _("\
964 1.1 christos Set COM3 base i/o port address."), _("\
965 1.1 christos Show COM3 base i/o port address."), NULL,
966 1.1 christos NULL,
967 1.1 christos NULL, /* FIXME: i18n: */
968 1.1 christos &setlist, &showlist);
969 1.1 christos
970 1.1 christos add_setshow_zinteger_cmd ("com3irq", class_obscure, &ports[2].irq, _("\
971 1.1 christos Set COM3 interrupt request."), _("\
972 1.1 christos Show COM3 interrupt request."), NULL,
973 1.1 christos NULL,
974 1.1 christos NULL, /* FIXME: i18n: */
975 1.1 christos &setlist, &showlist);
976 1.1 christos
977 1.1 christos add_setshow_zinteger_cmd ("com4base", class_obscure, &ports[3].base, _("\
978 1.1 christos Set COM4 base i/o port address."), _("\
979 1.1 christos Show COM4 base i/o port address."), NULL,
980 1.1 christos NULL,
981 1.1 christos NULL, /* FIXME: i18n: */
982 1.1 christos &setlist, &showlist);
983 1.1 christos
984 1.1 christos add_setshow_zinteger_cmd ("com4irq", class_obscure, &ports[3].irq, _("\
985 1.1 christos Set COM4 interrupt request."), _("\
986 1.1 christos Show COM4 interrupt request."), NULL,
987 1.8 christos NULL,
988 1.1 christos NULL, /* FIXME: i18n: */
989 1.1 christos &setlist, &showlist);
990
991 add_info ("serial", info_serial_command,
992 _("Print DOS serial port status."));
993 }
994