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