Add copyright header in gdb.base/return.c
[deliverable/binutils-gdb.git] / gdb / ser-go32.c
CommitLineData
d9fcf2fb 1/* Remote serial interface for local (hardwired) serial ports for GO32.
618f726f 2 Copyright (C) 1992-2016 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
c5aa993b 596
c906108c 597static int
819cc324 598dos_noop (struct serial *scb)
c906108c
SS
599{
600 return 0;
601}
602
603static void
819cc324 604dos_raw (struct serial *scb)
c906108c 605{
c378eb4e 606 /* Always in raw mode. */
c906108c
SS
607}
608
609static int
819cc324 610dos_readchar (struct serial *scb, int timeout)
c906108c
SS
611{
612 struct dos_ttystate *port = &ports[scb->fd];
613 long then;
614 int c;
615
c5aa993b 616 then = rawclock () + (timeout * RAWHZ);
c906108c
SS
617 while ((c = dos_getc (port)) < 0)
618 {
048094ac
PA
619 QUIT;
620
c906108c
SS
621 if (timeout >= 0 && (rawclock () - then) >= 0)
622 return SERIAL_TIMEOUT;
c906108c
SS
623 }
624
625 return c;
626}
627
628
629static serial_ttystate
819cc324 630dos_get_tty_state (struct serial *scb)
c906108c
SS
631{
632 struct dos_ttystate *port = &ports[scb->fd];
633 struct dos_ttystate *state;
634
dfed996b
EZ
635 /* Are they asking about a port we opened? */
636 if (port->refcnt <= 0)
637 {
638 /* We've never heard about this port. We should fail this call,
639 unless they are asking about one of the 3 standard handles,
640 in which case we pretend the handle was open by us if it is
641 connected to a terminal device. This is beacuse Unix
642 terminals use the serial interface, so GDB expects the
643 standard handles to go through here. */
644 if (scb->fd >= 3 || !isatty (scb->fd))
645 return NULL;
646 }
647
8d749320 648 state = XNEW (struct dos_ttystate);
c906108c
SS
649 *state = *port;
650 return (serial_ttystate) state;
651}
652
1e182ce8
UW
653static serial_ttystate
654dos_copy_tty_state (struct serial *scb, serial_ttystate ttystate)
655{
656 struct dos_ttystate *state;
657
8d749320 658 state = XNEW (struct dos_ttystate);
1e182ce8
UW
659 *state = *(struct dos_ttystate *) ttystate;
660
661 return (serial_ttystate) state;
662}
663
c906108c 664static int
819cc324 665dos_set_tty_state (struct serial *scb, serial_ttystate ttystate)
c906108c
SS
666{
667 struct dos_ttystate *state;
668
669 state = (struct dos_ttystate *) ttystate;
670 dos_setbaudrate (scb, state->baudrate);
671 return 0;
672}
673
674static int
819cc324 675dos_noflush_set_tty_state (struct serial *scb, serial_ttystate new_ttystate,
4d277981 676 serial_ttystate old_ttystate)
c906108c
SS
677{
678 struct dos_ttystate *state;
679
680 state = (struct dos_ttystate *) new_ttystate;
681 dos_setbaudrate (scb, state->baudrate);
682 return 0;
683}
684
685static int
819cc324 686dos_flush_input (struct serial *scb)
c906108c
SS
687{
688 struct dos_ttystate *port = &ports[scb->fd];
433759f7 689
c5aa993b 690 disable ();
c906108c
SS
691 port->first = port->count = 0;
692 if (port->fifo)
c5aa993b
JM
693 outb (port, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_TRIGGER);
694 enable ();
9d271fd8 695 return 0;
c906108c
SS
696}
697
698static void
819cc324 699dos_print_tty_state (struct serial *scb, serial_ttystate ttystate,
4d277981 700 struct ui_file *stream)
c906108c 701{
c378eb4e 702 /* Nothing to print. */
c906108c
SS
703 return;
704}
705
706static int
fba45db2 707dos_baudconv (int rate)
c906108c
SS
708{
709 long x, err;
c5aa993b
JM
710
711 if (rate <= 0)
c906108c
SS
712 return -1;
713
c378eb4e 714#define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* Divide and round off. */
c5aa993b 715 x = divrnd (COMTICK, rate);
c906108c
SS
716 if (x <= 0)
717 return -1;
c5aa993b
JM
718
719 err = divrnd (1000 * COMTICK, x * rate) - 1000;
c906108c
SS
720 if (err < 0)
721 err = -err;
722 if (err > SPEED_TOLERANCE)
723 return -1;
724#undef divrnd
725 return x;
726}
727
728
729static int
819cc324 730dos_setbaudrate (struct serial *scb, int rate)
c906108c 731{
c5aa993b 732 struct dos_ttystate *port = &ports[scb->fd];
c906108c 733
c5aa993b
JM
734 if (port->baudrate != rate)
735 {
736 int x;
737 unsigned char cfcr;
738
739 x = dos_baudconv (rate);
740 if (x <= 0)
741 {
742 fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
743 errno = EINVAL;
744 return -1;
745 }
746
747 disable ();
748 cfcr = inb (port, com_cfcr);
749
750 outb (port, com_cfcr, CFCR_DLAB);
751 outb (port, com_dlbl, x & 0xff);
752 outb (port, com_dlbh, x >> 8);
753 outb (port, com_cfcr, cfcr);
754 port->baudrate = rate;
755 enable ();
756 }
757
758 return 0;
c906108c
SS
759}
760
761static int
819cc324 762dos_setstopbits (struct serial *scb, int num)
c906108c 763{
c5aa993b
JM
764 struct dos_ttystate *port = &ports[scb->fd];
765 unsigned char cfcr;
c906108c 766
c5aa993b
JM
767 disable ();
768 cfcr = inb (port, com_cfcr);
769
770 switch (num)
771 {
772 case SERIAL_1_STOPBITS:
773 outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
774 break;
775 case SERIAL_1_AND_A_HALF_STOPBITS:
776 case SERIAL_2_STOPBITS:
777 outb (port, com_cfcr, cfcr | CFCR_STOPB);
778 break;
779 default:
780 enable ();
781 return 1;
782 }
783 enable ();
784
785 return 0;
c906108c
SS
786}
787
788static int
c628b528 789dos_write (struct serial *scb, const void *buf, size_t count)
c906108c
SS
790{
791 volatile struct dos_ttystate *port = &ports[scb->fd];
c628b528 792 size_t fifosize = port->fifo ? 16 : 1;
c906108c 793 long then;
c628b528
PA
794 size_t cnt;
795 const char *str = buf;
c906108c 796
c628b528 797 while (count > 0)
c5aa993b 798 {
048094ac
PA
799 QUIT;
800
c378eb4e 801 /* Send the data, fifosize bytes at a time. */
c628b528 802 cnt = fifosize > count ? count : fifosize;
c5aa993b 803 port->txbusy = 1;
cd42d3a8
EZ
804 /* Francisco Pastor <fpastor.etra-id@etra.es> says OUTSB messes
805 up the communications with UARTs with FIFOs. */
806#ifdef UART_FIFO_WORKS
c5aa993b
JM
807 outportsb (port->base + com_data, str, cnt);
808 str += cnt;
c628b528 809 count -= cnt;
cd42d3a8 810#else
c628b528 811 for ( ; cnt > 0; cnt--, count--)
cd42d3a8
EZ
812 outportb (port->base + com_data, *str++);
813#endif
c906108c 814#ifdef DOS_STATS
c5aa993b 815 cnts[CNT_TX] += cnt;
c906108c 816#endif
c378eb4e 817 /* Wait for transmission to complete (max 1 sec). */
c5aa993b
JM
818 then = rawclock () + RAWHZ;
819 while (port->txbusy)
820 {
821 if ((rawclock () - then) >= 0)
822 {
823 errno = EIO;
824 return SERIAL_ERROR;
825 }
826 }
c906108c
SS
827 }
828 return 0;
829}
830
831
832static int
819cc324 833dos_sendbreak (struct serial *scb)
c906108c
SS
834{
835 volatile struct dos_ttystate *port = &ports[scb->fd];
836 unsigned char cfcr;
837 long then;
838
c5aa993b
JM
839 cfcr = inb (port, com_cfcr);
840 outb (port, com_cfcr, cfcr | CFCR_SBREAK);
c906108c
SS
841
842 /* 0.25 sec delay */
843 then = rawclock () + RAWHZ / 4;
844 while ((rawclock () - then) < 0)
845 continue;
846
c5aa993b 847 outb (port, com_cfcr, cfcr);
c906108c
SS
848 return 0;
849}
850
851
fcd488ca 852static const struct serial_ops dos_ops =
c906108c
SS
853{
854 "hardwire",
c906108c
SS
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,
236af5e3 871 dos_noop,
c378eb4e
MS
872 dos_noop, /* Wait for output to drain. */
873 (void (*)(struct serial *, int))NULL /* Change into async mode. */
c906108c
SS
874};
875
58f07bae
PA
876int
877gdb_pipe (int pdes[2])
878{
879 /* No support for pipes. */
880 errno = ENOSYS;
881 return -1;
882}
c906108c
SS
883
884static void
4d277981 885dos_info (char *arg, int from_tty)
c906108c
SS
886{
887 struct dos_ttystate *port;
263fe37d 888#ifdef DOS_STATS
c906108c 889 int i;
263fe37d 890#endif
c906108c 891
c5aa993b 892 for (port = ports; port < &ports[4]; port++)
c906108c
SS
893 {
894 if (port->baudrate == 0)
895 continue;
263fe37d 896 printf_filtered ("Port:\tCOM%ld (%sactive)\n", (long)(port - ports) + 1,
c906108c
SS
897 port->intrupt ? "" : "not ");
898 printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
899 printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
900 printf_filtered ("Speed:\t%d baud\n", port->baudrate);
c5aa993b 901 printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
c906108c
SS
902 port->ferr, port->perr, port->oflo);
903 }
904
905#ifdef DOS_STATS
906 printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
907 for (i = 0; i < NCNT; i++)
908 if (cnts[i])
c628b528 909 printf_filtered ("%s:\t%lu\n", cntnames[i], (unsigned long) cnts[i]);
c906108c
SS
910#endif
911}
912
70976b65
YQ
913/* -Wmissing-prototypes */
914extern initialize_file_ftype _initialize_ser_dos;
c906108c
SS
915
916void
fba45db2 917_initialize_ser_dos (void)
c906108c 918{
c906108c
SS
919 serial_add_interface (&dos_ops);
920
c378eb4e 921 /* Save original interrupt mask register. */
c906108c
SS
922 icu_oldmask = inportb (ICU_MASK);
923
c378eb4e 924 /* Mark fixed motherboard irqs as inuse. */
c906108c
SS
925 intrupts[0].inuse = /* timer tick */
926 intrupts[1].inuse = /* keyboard */
c5aa993b
JM
927 intrupts[2].inuse = 1; /* slave icu */
928
85c07804
AC
929 add_setshow_zinteger_cmd ("com1base", class_obscure, &ports[0].base, _("\
930Set COM1 base i/o port address."), _("\
931Show COM1 base i/o port address."), NULL,
932 NULL,
933 NULL, /* FIXME: i18n: */
934 &setlist, &showlist);
935
936 add_setshow_zinteger_cmd ("com1irq", class_obscure, &ports[0].irq, _("\
937Set COM1 interrupt request."), _("\
938Show COM1 interrupt request."), NULL,
939 NULL,
940 NULL, /* FIXME: i18n: */
941 &setlist, &showlist);
942
943 add_setshow_zinteger_cmd ("com2base", class_obscure, &ports[1].base, _("\
944Set COM2 base i/o port address."), _("\
945Show COM2 base i/o port address."), NULL,
946 NULL,
947 NULL, /* FIXME: i18n: */
948 &setlist, &showlist);
949
950 add_setshow_zinteger_cmd ("com2irq", class_obscure, &ports[1].irq, _("\
951Set COM2 interrupt request."), _("\
952Show COM2 interrupt request."), NULL,
953 NULL,
954 NULL, /* FIXME: i18n: */
955 &setlist, &showlist);
956
957 add_setshow_zinteger_cmd ("com3base", class_obscure, &ports[2].base, _("\
958Set COM3 base i/o port address."), _("\
959Show COM3 base i/o port address."), NULL,
960 NULL,
961 NULL, /* FIXME: i18n: */
962 &setlist, &showlist);
963
964 add_setshow_zinteger_cmd ("com3irq", class_obscure, &ports[2].irq, _("\
965Set COM3 interrupt request."), _("\
966Show COM3 interrupt request."), NULL,
967 NULL,
968 NULL, /* FIXME: i18n: */
969 &setlist, &showlist);
970
971 add_setshow_zinteger_cmd ("com4base", class_obscure, &ports[3].base, _("\
972Set COM4 base i/o port address."), _("\
973Show COM4 base i/o port address."), NULL,
974 NULL,
975 NULL, /* FIXME: i18n: */
976 &setlist, &showlist);
977
978 add_setshow_zinteger_cmd ("com4irq", class_obscure, &ports[3].irq, _("\
979Set COM4 interrupt request."), _("\
980Show COM4 interrupt request."), NULL,
981 NULL,
982 NULL, /* FIXME: i18n: */
983 &setlist, &showlist);
c906108c
SS
984
985 add_info ("serial", dos_info,
1bedd215 986 _("Print DOS serial port status."));
c906108c 987}
This page took 1.626029 seconds and 4 git commands to generate.