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