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