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