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