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