OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [ser-go32.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.