]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/ser-go32.c
* gdb.python/py-infthread.exp: Load gdb-python.exp.
[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{
c906108c 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",
c906108c 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
169/* Main interrupt controller port addresses. */
170#define ICU_BASE 0x20
171#define ICU_OCW2 (ICU_BASE + 0)
172#define ICU_MASK (ICU_BASE + 1)
173
174/* Original interrupt controller mask register. */
c5aa993b 175unsigned char icu_oldmask;
c906108c
SS
176
177/* Maximum of 8 interrupts (we don't handle the slave icu yet). */
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:
344 /* no more pending interrupts, all done */
345 return;
346
347 default:
348 /* unexpected interrupt, ignore */
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
388 /* setup real mode handler */
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
c906108c 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
417 /* setup interrupt controller mask */
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
436 /* restore old interrupt mask bit */
437 mask = 1 << irq;
438 disable ();
439 outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
440 enable ();
441
442 /* remove real mode handler */
443 _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
444 _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
c5aa993b 445
c906108c
SS
446 /* remove protected mode handler */
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 {
485 /* Device already opened another user. Just point at it. */
486 scb->fd = fd;
487 return 0;
488 }
489
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:
503 /* disable all interrupts in chip */
c5aa993b 504 outb (port, com_ier, 0);
c906108c
SS
505
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
SS
511
512 /* clear pending status reports. */
c5aa993b
JM
513 (void) inb (port, com_lsr);
514 (void) inb (port, com_msr);
c906108c
SS
515
516 /* enable external interrupt gate (to avoid floating IRQ) */
c5aa993b 517 outb (port, com_mcr, MCR_IENABLE);
c906108c
SS
518
519 /* hook up interrupt handler and initialise icu */
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
535 /* clear rx buffer, tx busy flag and overflow count */
536 port->first = port->count = 0;
537 port->txbusy = 0;
538 port->oflo = 0;
539
540 /* set default baud rate and mode: 9600,8,n,1 */
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
SS
546
547 /* enable all interrupts */
c5aa993b 548 outb (port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
c906108c
SS
549
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
576 /* disable interrupts, fifo, flow control */
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
584 /* unhook handler, and disable interrupt gate */
585 dos_unhookirq (intrupt);
586 outb (port, com_mcr, 0);
587
588 /* Check for overflow errors */
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
SS
609{
610 /* Always in raw mode */
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
655static int
819cc324 656dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
c906108c
SS
657{
658 struct dos_ttystate *state;
659
660 state = (struct dos_ttystate *) ttystate;
661 dos_setbaudrate (scb, state->baudrate);
662 return 0;
663}
664
665static int
819cc324 666dos_noflush_set_tty_state (struct serial *scb, serial_ttystate new_ttystate,
4d277981 667 serial_ttystate old_ttystate)
c906108c
SS
668{
669 struct dos_ttystate *state;
670
671 state = (struct dos_ttystate *) new_ttystate;
672 dos_setbaudrate (scb, state->baudrate);
673 return 0;
674}
675
676static int
819cc324 677dos_flush_input (struct serial *scb)
c906108c
SS
678{
679 struct dos_ttystate *port = &ports[scb->fd];
433759f7 680
c5aa993b 681 disable ();
c906108c
SS
682 port->first = port->count = 0;
683 if (port->fifo)
c5aa993b
JM
684 outb (port, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_TRIGGER);
685 enable ();
9d271fd8 686 return 0;
c906108c
SS
687}
688
689static void
819cc324 690dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
4d277981 691 struct ui_file *stream)
c906108c
SS
692{
693 /* Nothing to print */
694 return;
695}
696
697static int
fba45db2 698dos_baudconv (int rate)
c906108c
SS
699{
700 long x, err;
c5aa993b
JM
701
702 if (rate <= 0)
c906108c
SS
703 return -1;
704
4d277981 705#define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* divide and round off */
c5aa993b 706 x = divrnd (COMTICK, rate);
c906108c
SS
707 if (x <= 0)
708 return -1;
c5aa993b
JM
709
710 err = divrnd (1000 * COMTICK, x * rate) - 1000;
c906108c
SS
711 if (err < 0)
712 err = -err;
713 if (err > SPEED_TOLERANCE)
714 return -1;
715#undef divrnd
716 return x;
717}
718
719
720static int
819cc324 721dos_setbaudrate (struct serial *scb, int rate)
c906108c 722{
c5aa993b 723 struct dos_ttystate *port = &ports[scb->fd];
c906108c 724
c5aa993b
JM
725 if (port->baudrate != rate)
726 {
727 int x;
728 unsigned char cfcr;
729
730 x = dos_baudconv (rate);
731 if (x <= 0)
732 {
733 fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
734 errno = EINVAL;
735 return -1;
736 }
737
738 disable ();
739 cfcr = inb (port, com_cfcr);
740
741 outb (port, com_cfcr, CFCR_DLAB);
742 outb (port, com_dlbl, x & 0xff);
743 outb (port, com_dlbh, x >> 8);
744 outb (port, com_cfcr, cfcr);
745 port->baudrate = rate;
746 enable ();
747 }
748
749 return 0;
c906108c
SS
750}
751
752static int
819cc324 753dos_setstopbits (struct serial *scb, int num)
c906108c 754{
c5aa993b
JM
755 struct dos_ttystate *port = &ports[scb->fd];
756 unsigned char cfcr;
c906108c 757
c5aa993b
JM
758 disable ();
759 cfcr = inb (port, com_cfcr);
760
761 switch (num)
762 {
763 case SERIAL_1_STOPBITS:
764 outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
765 break;
766 case SERIAL_1_AND_A_HALF_STOPBITS:
767 case SERIAL_2_STOPBITS:
768 outb (port, com_cfcr, cfcr | CFCR_STOPB);
769 break;
770 default:
771 enable ();
772 return 1;
773 }
774 enable ();
775
776 return 0;
c906108c
SS
777}
778
779static int
819cc324 780dos_write (struct serial *scb, const char *str, int len)
c906108c
SS
781{
782 volatile struct dos_ttystate *port = &ports[scb->fd];
783 int fifosize = port->fifo ? 16 : 1;
784 long then;
785 int cnt;
786
c5aa993b
JM
787 while (len > 0)
788 {
789 /* send the data, fifosize bytes at a time */
790 cnt = fifosize > len ? len : fifosize;
791 port->txbusy = 1;
cd42d3a8
EZ
792 /* Francisco Pastor <fpastor.etra-id@etra.es> says OUTSB messes
793 up the communications with UARTs with FIFOs. */
794#ifdef UART_FIFO_WORKS
c5aa993b
JM
795 outportsb (port->base + com_data, str, cnt);
796 str += cnt;
797 len -= cnt;
cd42d3a8
EZ
798#else
799 for ( ; cnt > 0; cnt--, len--)
800 outportb (port->base + com_data, *str++);
801#endif
c906108c 802#ifdef DOS_STATS
c5aa993b 803 cnts[CNT_TX] += cnt;
c906108c 804#endif
c5aa993b
JM
805 /* wait for transmission to complete (max 1 sec) */
806 then = rawclock () + RAWHZ;
807 while (port->txbusy)
808 {
809 if ((rawclock () - then) >= 0)
810 {
811 errno = EIO;
812 return SERIAL_ERROR;
813 }
814 }
c906108c
SS
815 }
816 return 0;
817}
818
819
820static int
819cc324 821dos_sendbreak (struct serial *scb)
c906108c
SS
822{
823 volatile struct dos_ttystate *port = &ports[scb->fd];
824 unsigned char cfcr;
825 long then;
826
c5aa993b
JM
827 cfcr = inb (port, com_cfcr);
828 outb (port, com_cfcr, cfcr | CFCR_SBREAK);
c906108c
SS
829
830 /* 0.25 sec delay */
831 then = rawclock () + RAWHZ / 4;
832 while ((rawclock () - then) < 0)
833 continue;
834
c5aa993b 835 outb (port, com_cfcr, cfcr);
c906108c
SS
836 return 0;
837}
838
839
840static struct serial_ops dos_ops =
841{
842 "hardwire",
843 0,
844 dos_open,
845 dos_close,
c1b5be38 846 NULL, /* fdopen, not implemented */
c906108c
SS
847 dos_readchar,
848 dos_write,
849 dos_noop, /* flush output */
850 dos_flush_input,
851 dos_sendbreak,
852 dos_raw,
853 dos_get_tty_state,
854 dos_set_tty_state,
855 dos_print_tty_state,
856 dos_noflush_set_tty_state,
857 dos_setbaudrate,
858 dos_setstopbits,
859 dos_noop, /* wait for output to drain */
819cc324 860 (void (*)(struct serial *, int))NULL /* change into async mode */
c906108c
SS
861};
862
58f07bae
PA
863int
864gdb_pipe (int pdes[2])
865{
866 /* No support for pipes. */
867 errno = ENOSYS;
868 return -1;
869}
c906108c
SS
870
871static void
4d277981 872dos_info (char *arg, int from_tty)
c906108c
SS
873{
874 struct dos_ttystate *port;
263fe37d 875#ifdef DOS_STATS
c906108c 876 int i;
263fe37d 877#endif
c906108c 878
c5aa993b 879 for (port = ports; port < &ports[4]; port++)
c906108c
SS
880 {
881 if (port->baudrate == 0)
882 continue;
263fe37d 883 printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
c906108c
SS
884 port->intrupt ? "" : "not ");
885 printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
886 printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
887 printf_filtered ("Speed:\t%d baud\n", port->baudrate);
c5aa993b 888 printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
c906108c
SS
889 port->ferr, port->perr, port->oflo);
890 }
891
892#ifdef DOS_STATS
893 printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
894 for (i = 0; i < NCNT; i++)
895 if (cnts[i])
896 printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]);
897#endif
898}
899
900
901void
fba45db2 902_initialize_ser_dos (void)
c906108c 903{
c906108c
SS
904 serial_add_interface (&dos_ops);
905
906 /* Save original interrupt mask register. */
907 icu_oldmask = inportb (ICU_MASK);
908
909 /* Mark fixed motherboard irqs as inuse. */
910 intrupts[0].inuse = /* timer tick */
911 intrupts[1].inuse = /* keyboard */
c5aa993b
JM
912 intrupts[2].inuse = 1; /* slave icu */
913
85c07804
AC
914 add_setshow_zinteger_cmd ("com1base", class_obscure, &ports[0].base, _("\
915Set COM1 base i/o port address."), _("\
916Show COM1 base i/o port address."), NULL,
917 NULL,
918 NULL, /* FIXME: i18n: */
919 &setlist, &showlist);
920
921 add_setshow_zinteger_cmd ("com1irq", class_obscure, &ports[0].irq, _("\
922Set COM1 interrupt request."), _("\
923Show COM1 interrupt request."), NULL,
924 NULL,
925 NULL, /* FIXME: i18n: */
926 &setlist, &showlist);
927
928 add_setshow_zinteger_cmd ("com2base", class_obscure, &ports[1].base, _("\
929Set COM2 base i/o port address."), _("\
930Show COM2 base i/o port address."), NULL,
931 NULL,
932 NULL, /* FIXME: i18n: */
933 &setlist, &showlist);
934
935 add_setshow_zinteger_cmd ("com2irq", class_obscure, &ports[1].irq, _("\
936Set COM2 interrupt request."), _("\
937Show COM2 interrupt request."), NULL,
938 NULL,
939 NULL, /* FIXME: i18n: */
940 &setlist, &showlist);
941
942 add_setshow_zinteger_cmd ("com3base", class_obscure, &ports[2].base, _("\
943Set COM3 base i/o port address."), _("\
944Show COM3 base i/o port address."), NULL,
945 NULL,
946 NULL, /* FIXME: i18n: */
947 &setlist, &showlist);
948
949 add_setshow_zinteger_cmd ("com3irq", class_obscure, &ports[2].irq, _("\
950Set COM3 interrupt request."), _("\
951Show COM3 interrupt request."), NULL,
952 NULL,
953 NULL, /* FIXME: i18n: */
954 &setlist, &showlist);
955
956 add_setshow_zinteger_cmd ("com4base", class_obscure, &ports[3].base, _("\
957Set COM4 base i/o port address."), _("\
958Show COM4 base i/o port address."), NULL,
959 NULL,
960 NULL, /* FIXME: i18n: */
961 &setlist, &showlist);
962
963 add_setshow_zinteger_cmd ("com4irq", class_obscure, &ports[3].irq, _("\
964Set COM4 interrupt request."), _("\
965Show COM4 interrupt request."), NULL,
966 NULL,
967 NULL, /* FIXME: i18n: */
968 &setlist, &showlist);
c906108c
SS
969
970 add_info ("serial", dos_info,
1bedd215 971 _("Print DOS serial port status."));
c906108c 972}