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