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