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