]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/ser-go32.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / gdb / ser-go32.c
CommitLineData
771d7a99
SC
1/* Remote serial interface for local (hardwired) serial ports for
2 GO32. Copyright 1992, 1993 Free Software Foundation, Inc.
ae0ea72e 3
771d7a99
SC
4 Contributed by Nigel Stephens, Algorithmics Ltd. (nigel@algor.co.uk).
5
6 This version uses DPMI interrupts to handle buffered i/o
7 without the separate "asynctsr" program.
8
9 This file is part of GDB.
ae0ea72e 10
08c0d7b8
SC
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
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
ae0ea72e 15
08c0d7b8
SC
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.
ae0ea72e 20
08c0d7b8
SC
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
6c9638b4 23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
ae0ea72e 24
ae0ea72e 25#include "defs.h"
771d7a99 26#include "gdbcmd.h"
ae0ea72e 27#include "serial.h"
771d7a99
SC
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
5140562f 129#include <sys/dos.h>
771d7a99
SC
130#include <sys/go32.h>
131#include <sys/dpmi.h>
132
133/* DPMI Communication */
134static union REGS dpmi_regs;
135static struct SREGS dpmi_sregs;
136
137/* 16550 rx fifo trigger point */
138#define FIFO_TRIGGER FIFO_TRIGGER_4
139
140/* input buffer size */
141#define CBSIZE 4096
142
143/* return raw 18Hz clock count */
144extern long rawclock (void);
145
146#define RAWHZ 18
147
148#ifdef DOS_STATS
149#define CNT_RX 16
150#define CNT_TX 17
151#define CNT_STRAY 18
152#define CNT_ORUN 19
153#define NCNT 20
154
155static int intrcnt;
156static int cnts[NCNT];
157static char *cntnames[NCNT] = {
158 /* h/w interrupt counts. */
159 "mlsc", "nopend", "txrdy", "?3",
160 "rxrdy", "?5", "rls", "?7",
161 "?8", "?9", "?a", "?b",
162 "rxtout", "?d", "?e", "?f",
163 /* s/w counts. */
164 "rxcnt", "txcnt", "stray", "swoflo"
165};
ae0ea72e 166
771d7a99
SC
167#define COUNT(x) cnts[x]++
168#else
169#define COUNT(x)
170#endif
aa48187b 171
771d7a99
SC
172/* Main interrupt controller port addresses. */
173#define ICU_BASE 0x20
174#define ICU_OCW2 (ICU_BASE + 0)
175#define ICU_MASK (ICU_BASE + 1)
ae0ea72e 176
771d7a99
SC
177/* Original interrupt controller mask register. */
178unsigned char icu_oldmask;
ae0ea72e 179
771d7a99
SC
180/* Maximum of 8 interrupts (we don't handle the slave icu yet). */
181#define NINTR 8
182
183static struct intrupt
184{
185 char inuse;
186 struct dos_ttystate *port;
187 _go32_dpmi_seginfo old_rmhandler;
188 _go32_dpmi_seginfo old_pmhandler;
189 _go32_dpmi_seginfo new_rmhandler;
190 _go32_dpmi_seginfo new_pmhandler;
191 _go32_dpmi_registers regs;
192} intrupts[NINTR];
ae0ea72e 193
771d7a99
SC
194
195static struct dos_ttystate
ae0ea72e 196{
771d7a99
SC
197 int base;
198 int irq;
a76ef70a 199 int refcnt;
771d7a99
SC
200 struct intrupt *intrupt;
201 int fifo;
202 int baudrate;
203 unsigned char cbuf[CBSIZE];
204 unsigned int first;
205 unsigned int count;
206 int txbusy;
207 unsigned char old_mcr;
208 int ferr;
209 int perr;
210 int oflo;
211 int msr;
212} ports[4] = {
213 {COM1ADDR, 4},
214 {COM2ADDR, 3},
215 {COM3ADDR, 4},
216 {COM4ADDR, 3}
217};
ae0ea72e 218
771d7a99
SC
219static int dos_open PARAMS ((serial_t scb, const char *name));
220static void dos_raw PARAMS ((serial_t scb));
221static int dos_readchar PARAMS ((serial_t scb, int timeout));
222static int dos_setbaudrate PARAMS ((serial_t scb, int rate));
223static int dos_write PARAMS ((serial_t scb, const char *str, int len));
224static void dos_close PARAMS ((serial_t scb));
225static serial_ttystate dos_get_tty_state PARAMS ((serial_t scb));
226static int dos_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
227static int dos_baudconv PARAMS ((int rate));
b83bf6b3 228
771d7a99
SC
229#define inb(p,a) inportb((p)->base + (a))
230#define outb(p,a,v) outportb((p)->base + (a), (v))
231#define disable() asm volatile ("cli");
232#define enable() asm volatile ("sti");
ae0ea72e 233
ae0ea72e 234
5d2b030a 235static int
771d7a99
SC
236dos_getc (port)
237 volatile struct dos_ttystate *port;
ae0ea72e 238{
771d7a99 239 int c;
07861607 240
771d7a99
SC
241 if (port->count == 0)
242 return -1;
07861607 243
771d7a99
SC
244 c = port->cbuf[port->first];
245 disable ();
246 port->first = (port->first + 1) & (CBSIZE - 1);
247 port->count--;
248 enable ();
249 return c;
ae0ea72e 250}
771d7a99 251
ae0ea72e 252
771d7a99
SC
253static int
254dos_putc (c, port)
255 int c;
256 struct dos_ttystate *port;
ae0ea72e 257{
771d7a99
SC
258 if (port->count >= CBSIZE - 1)
259 return -1;
260 port->cbuf[(port->first + port->count) & (CBSIZE - 1)] = c;
261 port->count++;
262 return 0;
ae0ea72e
SC
263}
264
771d7a99 265\f
aa48187b 266
771d7a99
SC
267static void
268dos_comisr (irq)
269 int irq;
270{
271 struct dos_ttystate *port;
272 unsigned char iir, lsr, c;
be5e6fff 273
771d7a99
SC
274 disable (); /* Paranoia */
275 outportb (ICU_OCW2, 0x20); /* End-Of-Interrupt */
276#ifdef DOS_STATS
277 ++intrcnt;
aa48187b 278#endif
ae0ea72e 279
771d7a99
SC
280 port = intrupts[irq].port;
281 if (!port)
282 {
283 COUNT (CNT_STRAY);
284 return; /* not open */
285 }
5d2b030a 286
be5e6fff 287 while (1)
08c0d7b8 288 {
771d7a99
SC
289 iir = inb (port, com_iir) & IIR_IMASK;
290 switch (iir)
08c0d7b8 291 {
771d7a99
SC
292
293 case IIR_RLS:
294 lsr = inb (port, com_lsr);
295 goto rx;
296
297 case IIR_RXTOUT:
298 case IIR_RXRDY:
299 lsr = 0;
300
301 rx:
302 do
be5e6fff 303 {
771d7a99
SC
304 c = inb (port, com_data);
305 if (lsr & (LSR_BI | LSR_FE | LSR_PE | LSR_OE))
306 {
307 if (lsr & (LSR_BI | LSR_FE))
308 port->ferr++;
309 else if (lsr & LSR_PE)
310 port->perr++;
311 if (lsr & LSR_OE)
312 port->oflo++;
313 }
314
a76ef70a 315 if (dos_putc (c, port) < 0)
771d7a99
SC
316 {
317 COUNT (CNT_ORUN);
318 }
319 else
320 {
321 COUNT (CNT_RX);
322 }
be5e6fff 323 }
771d7a99
SC
324 while ((lsr = inb (port, com_lsr)) & LSR_RXRDY);
325 break;
326
327 case IIR_MLSC:
328 /* could be used to flowcontrol Tx */
329 port->msr = inb (port, com_msr);
330 break;
331
332 case IIR_TXRDY:
333 port->txbusy = 0;
334 break;
335
336 case IIR_NOPEND:
337 /* no more pending interrupts, all done */
338 return;
339
340 default:
341 /* unexpected interrupt, ignore */
342 break;
08c0d7b8 343 }
771d7a99
SC
344 COUNT (iir);
345 }
346}
be5e6fff 347
771d7a99
SC
348#ifdef __STDC__
349#define ISRNAME(x) dos_comisr##x
350#else
351#define ISRNAME(x) dos_comisr/**/x
352#endif
353#define ISR(x) static void ISRNAME(x)() {dos_comisr(x);}
be5e6fff 354
771d7a99
SC
355ISR(0) ISR(1) ISR(2) ISR(3)
356ISR(4) ISR(5) ISR(6) ISR(7)
be5e6fff 357
771d7a99 358typedef void (*isr_t)();
be5e6fff 359
771d7a99
SC
360static isr_t isrs[NINTR] = {
361 ISRNAME(0), ISRNAME(1), ISRNAME(2), ISRNAME(3),
362 ISRNAME(4), ISRNAME(5), ISRNAME(6), ISRNAME(7)
363};
be5e6fff 364
771d7a99 365\f
be5e6fff 366
771d7a99
SC
367static struct intrupt *
368dos_hookirq (irq)
369 unsigned int irq;
370{
371 struct intrupt *intr;
372 unsigned int vec;
373 isr_t isr;
be5e6fff 374
771d7a99
SC
375 if (irq >= NINTR)
376 return 0;
be5e6fff 377
771d7a99
SC
378 intr = &intrupts[irq];
379 if (intr->inuse)
380 return 0;
381
382 vec = 0x08 + irq;
383 isr = isrs[irq];
be5e6fff 384
771d7a99
SC
385 /* setup real mode handler */
386 _go32_dpmi_get_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
be5e6fff 387
771d7a99
SC
388 intr->new_rmhandler.pm_selector = _go32_my_cs();
389 intr->new_rmhandler.pm_offset = (u_long)isr;
390 if (_go32_dpmi_allocate_real_mode_callback_iret (&intr->new_rmhandler,
391 &intr->regs))
392 {
393 return 0;
08c0d7b8 394 }
ae0ea72e 395
771d7a99
SC
396 if (_go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->new_rmhandler))
397 {
398 return 0;
399 }
400
401 /* setup protected mode handler */
402 _go32_dpmi_get_protected_mode_interrupt_vector(vec, &intr->old_pmhandler);
63eef03a 403
771d7a99
SC
404 intr->new_pmhandler.pm_selector = _go32_my_cs();
405 intr->new_pmhandler.pm_offset = (u_long)isr;
406 _go32_dpmi_allocate_iret_wrapper (&intr->new_pmhandler);
5d2b030a 407
771d7a99 408 if (_go32_dpmi_set_protected_mode_interrupt_vector(vec, &intr->new_pmhandler))
ae0ea72e 409 {
771d7a99 410 return 0;
ae0ea72e 411 }
771d7a99
SC
412
413 /* setup interrupt controller mask */
414 disable ();
415 outportb (ICU_MASK, inportb (ICU_MASK) & ~(1 << irq));
416 enable ();
417
418 intr->inuse = 1;
419 return intr;
ae0ea72e
SC
420}
421
771d7a99
SC
422
423static void
424dos_unhookirq (intr)
425 struct intrupt *intr;
5d2b030a 426{
771d7a99
SC
427 unsigned int irq, vec;
428 unsigned char mask;
ae0ea72e 429
771d7a99
SC
430 irq = intr - intrupts;
431 vec = 0x08 + irq;
ae0ea72e 432
771d7a99
SC
433 /* restore old interrupt mask bit */
434 mask = 1 << irq;
435 disable ();
436 outportb (ICU_MASK, inportb (ICU_MASK) | (mask & icu_oldmask));
437 enable ();
438
439 /* remove real mode handler */
440 _go32_dpmi_set_real_mode_interrupt_vector (vec, &intr->old_rmhandler);
441 _go32_dpmi_free_real_mode_callback (&intr->new_rmhandler);
442
443 /* remove protected mode handler */
444 _go32_dpmi_set_protected_mode_interrupt_vector (vec, &intr->old_pmhandler);
445 _go32_dpmi_free_iret_wrapper (&intr->new_pmhandler);
446 intr->inuse = 0;
ae0ea72e
SC
447}
448
771d7a99
SC
449\f
450
5d2b030a 451static int
771d7a99 452dos_open (scb, name)
5d2b030a
SG
453 serial_t scb;
454 const char *name;
b52373a2 455{
771d7a99
SC
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;
b83bf6b3 463
771d7a99 464 if (strlen (name) != 4 || strncasecmp (name, "com", 3) != 0)
b83bf6b3
SG
465 {
466 errno = ENOENT;
4febd102 467 return -1;
b83bf6b3
SG
468 }
469
771d7a99 470 if (name[3] < '1' || name[3] > '4')
b83bf6b3
SG
471 {
472 errno = ENOENT;
771d7a99 473 return -1;
b83bf6b3
SG
474 }
475
771d7a99
SC
476 fd = name[3] - '1';
477 port = &ports[fd];
a76ef70a 478 if (port->refcnt++ > 0)
771d7a99 479 {
a76ef70a
SG
480 /* Device already opened another user. Just point at it. */
481 scb->fd = fd;
482 return 0;
771d7a99
SC
483 }
484
485 /* force access to ID reg */
486 outb(port, com_cfcr, 0);
487 outb(port, com_iir, 0);
488 for (i = 0; i < 17; i++) {
489 if ((inb(port, com_iir) & 0x38) == 0)
490 goto ok;
491 (void) inb(port, com_data); /* clear recv */
492 }
493 errno = ENODEV;
494 return -1;
495
496ok:
497 /* disable all interrupts in chip */
498 outb(port, com_ier, 0);
499
500 /* tentatively enable 16550 fifo, and see if it responds */
501 outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER);
502 sleep(1);
503 port->fifo = ((inb(port, com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK);
504
505 /* clear pending status reports. */
506 (void) inb(port, com_lsr);
507 (void) inb(port, com_msr);
508
509 /* enable external interrupt gate (to avoid floating IRQ) */
510 outb(port, com_mcr, MCR_IENABLE);
511
512 /* hook up interrupt handler and initialise icu */
513 port->intrupt = dos_hookirq (port->irq);
514 if (!port->intrupt)
515 {
516 outb(port, com_mcr, 0);
517 outb(port, com_fifo, 0);
518 errno = ENODEV;
519 return -1;
520 }
521
522 disable ();
523
524 /* record port */
525 port->intrupt->port = port;
526 scb->fd = fd;
527
528 /* clear rx buffer, tx busy flag and overflow count */
529 port->first = port->count = 0;
530 port->txbusy = 0;
531 port->oflo = 0;
532
533 /* set default baud rate and mode: 9600,8,n,1 */
534 i = dos_baudconv (port->baudrate = 9600);
535 outb(port, com_cfcr, CFCR_DLAB);
536 outb(port, com_dlbl, i & 0xff);
537 outb(port, com_dlbh, i >> 8);
538 outb(port, com_cfcr, CFCR_8BITS);
539
540 /* enable all interrupts */
541 outb(port, com_ier, IER_ETXRDY | IER_ERXRDY | IER_ERLS | IER_EMSC);
542
543 /* enable DTR & RTS */
544 outb(port, com_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
545
546 enable ();
ae0ea72e 547
5d2b030a 548 return 0;
ae0ea72e
SC
549}
550
771d7a99
SC
551
552static void
553dos_close (scb)
554 serial_t scb;
555{
ccbae889 556 struct dos_ttystate *port;
771d7a99
SC
557 struct intrupt *intrupt;
558
ccbae889
SC
559 if (!scb)
560 return;
561
562 port = &ports[scb->fd];
a76ef70a
SG
563
564 if (port->refcnt-- > 1)
565 return;
566
771d7a99
SC
567 if (!(intrupt = port->intrupt))
568 return;
569
570 /* disable interrupts, fifo, flow control */
571 disable ();
572 port->intrupt = 0;
573 intrupt->port = 0;
574 outb(port, com_fifo, 0);
575 outb(port, com_ier, 0);
576 enable ();
577
578 /* unhook handler, and disable interrupt gate */
579 dos_unhookirq (intrupt);
580 outb(port, com_mcr, 0);
581
582 /* Check for overflow errors */
583 if (port->oflo)
584 {
585 fprintf_unfiltered (gdb_stderr,
586 "Serial input overruns occurred.\n");
587 fprintf_unfiltered (gdb_stderr, "This system %s handle %d baud.\n",
588 port->fifo ? "cannot" : "needs a 16550 to",
589 port->baudrate);
590 }
591}
592
593\f
594
c2e247c4 595static int
771d7a99 596dos_noop (scb)
c2e247c4
JK
597 serial_t scb;
598{
c2e247c4
JK
599 return 0;
600}
601
5d2b030a 602static void
771d7a99 603dos_raw (scb)
5d2b030a 604 serial_t scb;
ae0ea72e 605{
5d2b030a 606 /* Always in raw mode */
ae0ea72e
SC
607}
608
5d2b030a 609static int
771d7a99 610dos_readchar (scb, timeout)
5d2b030a
SG
611 serial_t scb;
612 int timeout;
ae0ea72e 613{
771d7a99
SC
614 struct dos_ttystate *port = &ports[scb->fd];
615 long then;
616 int c;
5d2b030a 617
771d7a99
SC
618 then = rawclock() + (timeout * RAWHZ);
619 while ((c = dos_getc (port)) < 0)
08c0d7b8 620 {
771d7a99
SC
621 if (timeout >= 0 && (rawclock () - then) >= 0)
622 return SERIAL_TIMEOUT;
623 notice_quit ();
08c0d7b8
SC
624 }
625
771d7a99 626 return c;
ae0ea72e
SC
627}
628
38dc5e12
SG
629
630static serial_ttystate
771d7a99 631dos_get_tty_state (scb)
38dc5e12
SG
632 serial_t scb;
633{
771d7a99
SC
634 struct dos_ttystate *port = &ports[scb->fd];
635 struct dos_ttystate *state;
38dc5e12 636
771d7a99
SC
637 state = (struct dos_ttystate *) xmalloc (sizeof *state);
638 *state = *port;
08c0d7b8 639 return (serial_ttystate) state;
38dc5e12
SG
640}
641
642static int
771d7a99 643dos_set_tty_state (scb, ttystate)
38dc5e12
SG
644 serial_t scb;
645 serial_ttystate ttystate;
646{
771d7a99
SC
647 struct dos_ttystate *state;
648
649 state = (struct dos_ttystate *) ttystate;
650 dos_setbaudrate (scb, state->baudrate);
38dc5e12
SG
651 return 0;
652}
653
c2e247c4 654static int
771d7a99 655dos_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
c2e247c4
JK
656 serial_t scb;
657 serial_ttystate new_ttystate;
658 serial_ttystate old_ttystate;
659{
771d7a99
SC
660 struct dos_ttystate *state;
661
662 state = (struct dos_ttystate *) new_ttystate;
663 dos_setbaudrate (scb, state->baudrate);
c2e247c4
JK
664 return 0;
665}
666
771d7a99
SC
667static int
668dos_flush_input (scb)
669 serial_t scb;
670{
671 struct dos_ttystate *port = &ports[scb->fd];
672 disable();
673 port->first = port->count = 0;
674 if (port->fifo)
675 outb(port, com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_TRIGGER);
676 enable();
677}
678
c2e247c4 679static void
771d7a99 680dos_print_tty_state (scb, ttystate)
c2e247c4
JK
681 serial_t scb;
682 serial_ttystate ttystate;
683{
771d7a99 684 /* Nothing to print */
c2e247c4
JK
685 return;
686}
687
5d2b030a 688static int
771d7a99 689dos_baudconv (rate)
5d2b030a 690 int rate;
ae0ea72e 691{
771d7a99
SC
692 long x, err;
693
694 if (rate <= 0)
695 return -1;
696
697#define divrnd(n, q) (((n) * 2 / (q) + 1) / 2) /* divide and round off */
698 x = divrnd(COMTICK, rate);
699 if (x <= 0)
700 return -1;
701
702 err = divrnd(1000 * COMTICK, x * rate) - 1000;
703 if (err < 0)
704 err = -err;
705 if (err > SPEED_TOLERANCE)
706 return -1;
707#undef divrnd
708 return x;
ae0ea72e
SC
709}
710
771d7a99 711
5d2b030a 712static int
771d7a99 713dos_setbaudrate (scb, rate)
5d2b030a 714 serial_t scb;
771d7a99 715 int rate;
5d2b030a 716{
771d7a99 717 struct dos_ttystate *port = &ports[scb->fd];
4febd102 718
771d7a99
SC
719 if (port->baudrate != rate)
720 {
721 int x;
85c8b135 722 unsigned char cfcr;
771d7a99
SC
723
724 x = dos_baudconv (rate);
725 if (x <= 0)
726 {
727 fprintf_unfiltered (gdb_stderr, "%d: impossible baudrate\n", rate);
728 errno = EINVAL;
729 return -1;
730 }
731
732 disable ();
85c8b135
SG
733 cfcr = inb (port, com_cfcr);
734
771d7a99
SC
735 outb(port, com_cfcr, CFCR_DLAB);
736 outb(port, com_dlbl, x & 0xff);
737 outb(port, com_dlbh, x >> 8);
85c8b135 738 outb(port, com_cfcr, cfcr);
771d7a99
SC
739 port->baudrate = rate;
740 enable ();
741 }
742
743 return 0;
5d2b030a
SG
744}
745
85c8b135
SG
746static int
747dos_setstopbits (scb, num)
748 serial_t scb;
749 int num;
750{
751 struct dos_ttystate *port = &ports[scb->fd];
752 unsigned char cfcr;
753
754 disable ();
755 cfcr = inb (port, com_cfcr);
756
757 switch (num)
758 {
759 case SERIAL_1_STOPBITS:
760 outb (port, com_cfcr, cfcr & ~CFCR_STOPB);
761 break;
762 case SERIAL_1_AND_A_HALF_STOPBITS:
763 case SERIAL_2_STOPBITS:
764 outb (port, com_cfcr, cfcr | CFCR_STOPB);
765 break;
766 default:
767 enable ();
768 return 1;
769 }
770 enable ();
771
772 return 0;
773}
771d7a99
SC
774
775static int
776dos_write (scb, str, len)
452b4b00 777 serial_t scb;
771d7a99
SC
778 const char *str;
779 int len;
ae0ea72e 780{
771d7a99
SC
781 volatile struct dos_ttystate *port = &ports[scb->fd];
782 int fifosize = port->fifo ? 16 : 1;
783 long then;
784 int cnt;
785
786 while (len > 0)
787 {
788 /* send the data, fifosize bytes at a time */
789 cnt = fifosize > len ? len : fifosize;
790 port->txbusy = 1;
791 outportsb (port->base + com_data, str, cnt);
792 str += cnt;
793 len -= cnt;
794#ifdef DOS_STATS
795 cnts[CNT_TX] += cnt;
796#endif
797 /* wait for transmission to complete (max 1 sec) */
798 then = rawclock() + RAWHZ;
799 while (port->txbusy)
800 {
801 if ((rawclock () - then) >= 0)
802 {
803 errno = EIO;
804 return SERIAL_ERROR;
805 }
806 }
807 }
808 return 0;
ae0ea72e
SC
809}
810
ccbae889
SC
811
812static int
813dos_sendbreak (scb)
814 serial_t scb;
815{
816 volatile struct dos_ttystate *port = &ports[scb->fd];
817 unsigned char cfcr;
818 long then;
819
820 cfcr = inb(port, com_cfcr);
821 outb(port, com_cfcr, cfcr | CFCR_SBREAK);
822
823 /* 0.25 sec delay */
824 then = rawclock () + RAWHZ / 4;
825 while ((rawclock () - then) < 0)
826 continue;
827
828 outb(port, com_cfcr, cfcr);
829 return 0;
830}
831
832
771d7a99 833static struct serial_ops dos_ops =
5d2b030a
SG
834{
835 "hardwire",
836 0,
771d7a99
SC
837 dos_open,
838 dos_close,
839 dos_readchar,
840 dos_write,
841 dos_noop, /* flush output */
842 dos_flush_input,
ccbae889 843 dos_sendbreak,
771d7a99
SC
844 dos_raw,
845 dos_get_tty_state,
846 dos_set_tty_state,
847 dos_print_tty_state,
848 dos_noflush_set_tty_state,
849 dos_setbaudrate,
85c8b135 850 dos_setstopbits,
3ffbdf15 851 dos_noop, /* wait for output to drain */
5d2b030a
SG
852};
853
771d7a99
SC
854
855static void
856dos_info (arg, from_tty)
857 char *arg;
858 int from_tty;
859{
860 struct dos_ttystate *port;
861 int i;
862
863 for (port = ports; port < &ports[4]; port++)
864 {
865 if (port->baudrate == 0)
866 continue;
ccbae889 867 printf_filtered ("Port:\tCOM%d (%sactive)\n", port - ports + 1,
771d7a99
SC
868 port->intrupt ? "" : "not ");
869 printf_filtered ("Addr:\t0x%03x (irq %d)\n", port->base, port->irq);
870 printf_filtered ("16550:\t%s\n", port->fifo ? "yes" : "no");
871 printf_filtered ("Speed:\t%d baud\n", port->baudrate);
ccbae889 872 printf_filtered ("Errs:\tframing %d parity %d overflow %d\n\n",
771d7a99
SC
873 port->ferr, port->perr, port->oflo);
874 }
875
876#ifdef DOS_STATS
877 printf_filtered ("\nTotal interrupts: %d\n", intrcnt);
878 for (i = 0; i < NCNT; i++)
879 if (cnts[i])
880 printf_filtered ("%s:\t%d\n", cntnames[i], cnts[i]);
881#endif
882}
883
884
976bb0be 885void
771d7a99 886_initialize_ser_dos ()
ae0ea72e 887{
771d7a99
SC
888 struct cmd_list_element *c;
889
890 serial_add_interface (&dos_ops);
891
892 /* Save original interrupt mask register. */
893 icu_oldmask = inportb (ICU_MASK);
894
895 /* Mark fixed motherboard irqs as inuse. */
896 intrupts[0].inuse = /* timer tick */
897 intrupts[1].inuse = /* keyboard */
898 intrupts[2].inuse = 1; /* slave icu */
899
900 add_show_from_set (
901 add_set_cmd ("com1base", class_obscure, var_zinteger,
902 (char *) &ports[0].base,
903 "Set COM1 base i/o port address.",
904 &setlist),
905 &showlist);
906
907 add_show_from_set (
908 add_set_cmd ("com1irq", class_obscure, var_zinteger,
909 (char *) &ports[0].irq,
910 "Set COM1 interrupt request.",
911 &setlist),
912 &showlist);
913
914 add_show_from_set (
915 add_set_cmd ("com2base", class_obscure, var_zinteger,
916 (char *) &ports[1].base,
917 "Set COM2 base i/o port address.",
918 &setlist),
919 &showlist);
920
921 add_show_from_set (
922 add_set_cmd ("com2irq", class_obscure, var_zinteger,
923 (char *) &ports[1].irq,
924 "Set COM2 interrupt request.",
925 &setlist),
926 &showlist);
927
928 add_show_from_set (
929 add_set_cmd ("com3base", class_obscure, var_zinteger,
930 (char *) &ports[2].base,
931 "Set COM3 base i/o port address.",
932 &setlist),
933 &showlist);
934
935 add_show_from_set (
936 add_set_cmd ("com3irq", class_obscure, var_zinteger,
937 (char *) &ports[2].irq,
938 "Set COM3 interrupt request.",
939 &setlist),
940 &showlist);
941
942 add_show_from_set (
943 add_set_cmd ("com4base", class_obscure, var_zinteger,
944 (char *) &ports[3].base,
945 "Set COM4 base i/o port address.",
946 &setlist),
947 &showlist);
948
949 add_show_from_set (
950 add_set_cmd ("com4irq", class_obscure, var_zinteger,
951 (char *) &ports[3].irq,
952 "Set COM4 interrupt request.",
953 &setlist),
954 &showlist);
955
956 add_info ("serial", dos_info,
957 "Print DOS serial port status.");
ae0ea72e 958}