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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [ser-go32.c] - Blame information for rev 1768

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

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

powered by: WebSVN 2.1.0

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