dcm.c revision 1.36 1 /* $NetBSD: dcm.c,v 1.36 1997/03/31 07:29:49 scottr Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996 Jason R. Thorpe. All rights reserved.
5 * Copyright (c) 1988 University of Utah.
6 * Copyright (c) 1982, 1986, 1990, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * the Systems Programming Group of the University of Utah Computer
11 * Science Department.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 * from Utah: $Hdr: dcm.c 1.29 92/01/21$
42 *
43 * @(#)dcm.c 8.4 (Berkeley) 1/12/94
44 */
45
46 /*
47 * TODO:
48 * Timeouts
49 * Test console support.
50 */
51
52 /*
53 * 98642/MUX
54 */
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/ioctl.h>
58 #include <sys/proc.h>
59 #include <sys/tty.h>
60 #include <sys/conf.h>
61 #include <sys/file.h>
62 #include <sys/uio.h>
63 #include <sys/kernel.h>
64 #include <sys/syslog.h>
65 #include <sys/time.h>
66 #include <sys/device.h>
67
68 #include <machine/autoconf.h>
69 #include <machine/cpu.h>
70
71 #include <dev/cons.h>
72
73 #include <hp300/dev/dioreg.h>
74 #include <hp300/dev/diovar.h>
75 #include <hp300/dev/diodevs.h>
76 #include <hp300/dev/dcmreg.h>
77 #include <hp300/hp300/isr.h>
78
79 #ifndef DEFAULT_BAUD_RATE
80 #define DEFAULT_BAUD_RATE 9600
81 #endif
82
83 struct speedtab dcmspeedtab[] = {
84 { 0, BR_0 },
85 { 50, BR_50 },
86 { 75, BR_75 },
87 { 110, BR_110 },
88 { 134, BR_134 },
89 { 150, BR_150 },
90 { 300, BR_300 },
91 { 600, BR_600 },
92 { 1200, BR_1200 },
93 { 1800, BR_1800 },
94 { 2400, BR_2400 },
95 { 4800, BR_4800 },
96 { 9600, BR_9600 },
97 { 19200, BR_19200 },
98 { 38400, BR_38400 },
99 { -1, -1 },
100 };
101
102 /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
103 #define DCM_USPERCH(s) (10000000 / (s))
104
105 /*
106 * Per board interrupt scheme. 16.7ms is the polling interrupt rate
107 * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
108 */
109 #define DIS_TIMER 0
110 #define DIS_PERCHAR 1
111 #define DIS_RESET 2
112
113 int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
114 int dcminterval = 5; /* interval (secs) between checks */
115 struct dcmischeme {
116 int dis_perchar; /* non-zero if interrupting per char */
117 long dis_time; /* last time examined */
118 int dis_intr; /* recv interrupts during last interval */
119 int dis_char; /* characters read during last interval */
120 };
121
122 /*
123 * Stuff for DCM console support. This could probably be done a little
124 * better.
125 */
126 static struct dcmdevice *dcm_cn = NULL; /* pointer to hardware */
127 static int dcmconsinit; /* has been initialized */
128 /* static int dcm_lastcnpri = CN_DEAD; */ /* XXX last priority */
129
130 int dcmdefaultrate = DEFAULT_BAUD_RATE;
131 int dcmconbrdbusy = 0;
132 int dcmmajor;
133
134 #ifdef KGDB
135 /*
136 * Kernel GDB support
137 */
138 #include <machine/remote-sl.h>
139
140 extern dev_t kgdb_dev;
141 extern int kgdb_rate;
142 extern int kgdb_debug_init;
143 #endif
144
145 /* #define DCMSTATS */
146
147 #ifdef DEBUG
148 int dcmdebug = 0x0;
149 #define DDB_SIOERR 0x01
150 #define DDB_PARAM 0x02
151 #define DDB_INPUT 0x04
152 #define DDB_OUTPUT 0x08
153 #define DDB_INTR 0x10
154 #define DDB_IOCTL 0x20
155 #define DDB_INTSCHM 0x40
156 #define DDB_MODEM 0x80
157 #define DDB_OPENCLOSE 0x100
158 #endif
159
160 #ifdef DCMSTATS
161 #define DCMRBSIZE 94
162 #define DCMXBSIZE 24
163
164 struct dcmstats {
165 long xints; /* # of xmit ints */
166 long xchars; /* # of xmit chars */
167 long xempty; /* times outq is empty in dcmstart */
168 long xrestarts; /* times completed while xmitting */
169 long rints; /* # of recv ints */
170 long rchars; /* # of recv chars */
171 long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
172 long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
173 };
174 #endif
175
176 #define DCMUNIT(x) minor(x)
177 #define DCMBOARD(x) (((x) >> 2) & 0x3f)
178 #define DCMPORT(x) ((x) & 3)
179
180 /*
181 * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
182 * the distribution panel uses "HP DCE" conventions. If requested via
183 * the device flags, we swap the inputs to something closer to normal DCE,
184 * allowing a straight-through cable to a DTE or a reversed cable
185 * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
186 * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
187 * DSR or make RTS work, though). The following gives the full
188 * details of a cable from this mux panel to a modem:
189 *
190 * HP modem
191 * name pin pin name
192 * HP inputs:
193 * "Rx" 2 3 Tx
194 * CTS 4 5 CTS (only needed for CCTS_OFLOW)
195 * DCD 20 8 DCD
196 * "DSR" 9 6 DSR (unneeded)
197 * RI 22 22 RI (unneeded)
198 *
199 * HP outputs:
200 * "Tx" 3 2 Rx
201 * "DTR" 6 not connected
202 * "RTS" 8 20 DTR
203 * "SR" 23 4 RTS (often not needed)
204 */
205 #define hp2dce_in(ibits) (iconv[(ibits) & 0xf])
206 static char iconv[16] = {
207 0, MI_DM, MI_CTS, MI_CTS|MI_DM,
208 MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM,
209 MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM,
210 MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
211 MI_RI|MI_CD|MI_CTS|MI_DM
212 };
213
214 /*
215 * Note that 8-port boards appear as 2 4-port boards at consecutive
216 * select codes.
217 */
218 #define NDCMPORT 4
219
220 struct dcm_softc {
221 struct device sc_dev; /* generic device glue */
222 struct dcmdevice *sc_dcm; /* pointer to hardware */
223 struct tty *sc_tty[NDCMPORT]; /* our tty instances */
224 struct modemreg *sc_modem[NDCMPORT]; /* modem control */
225 char sc_mcndlast[NDCMPORT]; /* XXX last modem status for port */
226 short sc_softCAR; /* mask of ports with soft-carrier */
227 struct dcmischeme sc_scheme; /* interrupt scheme for board */
228
229 /*
230 * Mask of soft-carrier bits in config flags.
231 */
232 #define DCM_SOFTCAR 0x0000000f
233
234 int sc_flags; /* misc. configuration info */
235
236 /*
237 * Bits for sc_flags
238 */
239 #define DCM_ACTIVE 0x00000001 /* indicates board is alive */
240 #define DCM_ISCONSOLE 0x00000002 /* indicates board is console */
241 #define DCM_STDDCE 0x00000010 /* re-map DCE to standard */
242 #define DCM_FLAGMASK (DCM_STDDCE) /* mask of valid bits in config flags */
243
244 #ifdef DCMSTATS
245 struct dcmstats sc_stats; /* metrics gathering */
246 #endif
247 };
248
249 int dcmmatch __P((struct device *, struct cfdata *, void *));
250 void dcmattach __P((struct device *, struct device *, void *));
251
252 struct cfattach dcm_ca = {
253 sizeof(struct dcm_softc), dcmmatch, dcmattach
254 };
255
256 struct cfdriver dcm_cd = {
257 NULL, "dcm", DV_TTY
258 };
259
260 cdev_decl(dcm);
261
262 int dcmintr __P((void *));
263 void dcmpint __P((struct dcm_softc *, int, int));
264 void dcmrint __P((struct dcm_softc *));
265 void dcmreadbuf __P((struct dcm_softc *, int));
266 void dcmxint __P((struct dcm_softc *, int));
267 void dcmmint __P((struct dcm_softc *, int, int));
268
269 int dcmparam __P((struct tty *, struct termios *));
270 void dcmstart __P((struct tty *));
271 void dcmstop __P((struct tty *, int));
272 int dcmmctl __P((dev_t, int, int));
273 void dcmsetischeme __P((int, int));
274 void dcminit __P((struct dcmdevice *, int, int));
275
276 int dcmselftest __P((struct dcm_softc *));
277
278 int dcm_console_scan __P((int, caddr_t, void *));
279 void dcmcnprobe __P((struct consdev *));
280 void dcmcninit __P((struct consdev *));
281 int dcmcngetc __P((dev_t));
282 void dcmcnputc __P((dev_t, int));
283
284 int
285 dcmmatch(parent, match, aux)
286 struct device *parent;
287 struct cfdata *match;
288 void *aux;
289 {
290 struct dio_attach_args *da = aux;
291
292 switch (da->da_id) {
293 case DIO_DEVICE_ID_DCM:
294 case DIO_DEVICE_ID_DCMREM:
295 return (1);
296 }
297
298 return (0);
299 }
300
301 void
302 dcmattach(parent, self, aux)
303 struct device *parent, *self;
304 void *aux;
305 {
306 struct dcm_softc *sc = (struct dcm_softc *)self;
307 struct dio_attach_args *da = aux;
308 struct dcmdevice *dcm;
309 int brd = self->dv_unit;
310 int scode = da->da_scode;
311 int i, mbits, ipl;
312
313 sc->sc_flags = 0;
314
315 if (scode == conscode) {
316 dcm = (struct dcmdevice *)conaddr;
317 sc->sc_flags |= DCM_ISCONSOLE;
318
319 /*
320 * We didn't know which unit this would be during
321 * the console probe, so we have to fixup cn_dev here.
322 * Note that we always assume port 1 on the board.
323 */
324 cn_tab->cn_dev = makedev(dcmmajor, (brd << 2) | DCMCONSPORT);
325 } else {
326 dcm = (struct dcmdevice *)iomap(dio_scodetopa(da->da_scode),
327 da->da_size);
328 if (dcm == NULL) {
329 printf("\n%s: can't map registers\n",
330 sc->sc_dev.dv_xname);
331 return;
332 }
333 }
334
335 sc->sc_dcm = dcm;
336
337 ipl = DIO_IPL(dcm);
338 printf(" ipl %d", ipl);
339
340 if (dcmselftest(sc)) {
341 printf("\n%s: self-test failed\n", sc->sc_dev.dv_xname);
342 return;
343 }
344
345 /* Extract configuration info from flags. */
346 sc->sc_softCAR = self->dv_cfdata->cf_flags & DCM_SOFTCAR;
347 sc->sc_flags |= self->dv_cfdata->cf_flags & DCM_FLAGMASK;
348
349 /* Mark our unit as configured. */
350 sc->sc_flags |= DCM_ACTIVE;
351
352 /* Establish the interrupt handler. */
353 (void) isrlink(dcmintr, sc, ipl, ISRPRI_TTY);
354
355 if (dcmistype == DIS_TIMER)
356 dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
357 else
358 dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
359
360 /* load pointers to modem control */
361 sc->sc_modem[0] = &dcm->dcm_modem0;
362 sc->sc_modem[1] = &dcm->dcm_modem1;
363 sc->sc_modem[2] = &dcm->dcm_modem2;
364 sc->sc_modem[3] = &dcm->dcm_modem3;
365
366 /* set DCD (modem) and CTS (flow control) on all ports */
367 if (sc->sc_flags & DCM_STDDCE)
368 mbits = hp2dce_in(MI_CD|MI_CTS);
369 else
370 mbits = MI_CD|MI_CTS;
371
372 for (i = 0; i < NDCMPORT; i++)
373 sc->sc_modem[i]->mdmmsk = mbits;
374
375 dcm->dcm_ic = IC_IE; /* turn all interrupts on */
376
377 /*
378 * Need to reset baud rate, etc. of next print so reset dcmconsinit.
379 * Also make sure console is always "hardwired"
380 */
381 if (sc->sc_flags & DCM_ISCONSOLE) {
382 dcmconsinit = 0;
383 sc->sc_softCAR |= (1 << DCMCONSPORT);
384 printf(": console on port %d\n", DCMCONSPORT);
385 } else
386 printf("\n");
387
388 #ifdef KGDB
389 if (major(kgdb_dev) == dcmmajor &&
390 DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
391 if (dcmconsole == DCMUNIT(kgdb_dev)) /* XXX fixme */
392 kgdb_dev = NODEV; /* can't debug over console port */
393 #ifndef KGDB_CHEAT
394 /*
395 * The following could potentially be replaced
396 * by the corresponding code in dcmcnprobe.
397 */
398 else {
399 dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)),
400 kgdb_rate);
401 if (kgdb_debug_init) {
402 printf("%s port %d: ", sc->sc_dev.dv_xname,
403 DCMPORT(DCMUNIT(kgdb_dev)));
404 kgdb_connect(1);
405 } else
406 printf("%s port %d: kgdb enabled\n",
407 sc->sc_dev.dv_xname,
408 DCMPORT(DCMUNIT(kgdb_dev)));
409 }
410 /* end could be replaced */
411 #endif /* KGDB_CHEAT */
412 }
413 #endif /* KGDB */
414 }
415
416 /* ARGSUSED */
417 int
418 dcmopen(dev, flag, mode, p)
419 dev_t dev;
420 int flag, mode;
421 struct proc *p;
422 {
423 struct dcm_softc *sc;
424 struct tty *tp;
425 int unit, brd, port;
426 int error = 0, mbits, s;
427
428 unit = DCMUNIT(dev);
429 brd = DCMBOARD(unit);
430 port = DCMPORT(unit);
431
432 if (brd >= dcm_cd.cd_ndevs || port >= NDCMPORT ||
433 (sc = dcm_cd.cd_devs[brd]) == NULL)
434 return (ENXIO);
435
436 if ((sc->sc_flags & DCM_ACTIVE) == 0)
437 return (ENXIO);
438
439 if (sc->sc_tty[port] == NULL) {
440 tp = sc->sc_tty[port] = ttymalloc();
441 tty_attach(tp);
442 } else
443 tp = sc->sc_tty[port];
444
445 tp->t_oproc = dcmstart;
446 tp->t_param = dcmparam;
447 tp->t_dev = dev;
448
449 if ((tp->t_state & TS_ISOPEN) == 0) {
450 /*
451 * Sanity clause: reset the card on first open.
452 * The card might be left in an inconsistent state
453 * if the card memory is read inadvertently.
454 */
455 dcminit(sc->sc_dcm, port, dcmdefaultrate);
456
457 tp->t_state |= TS_WOPEN;
458 ttychars(tp);
459 tp->t_iflag = TTYDEF_IFLAG;
460 tp->t_oflag = TTYDEF_OFLAG;
461 tp->t_cflag = TTYDEF_CFLAG;
462 tp->t_lflag = TTYDEF_LFLAG;
463 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
464
465 s = spltty();
466
467 (void) dcmparam(tp, &tp->t_termios);
468 ttsetwater(tp);
469 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
470 return (EBUSY);
471 else
472 s = spltty();
473
474 /* Set modem control state. */
475 mbits = MO_ON;
476 if (sc->sc_flags & DCM_STDDCE)
477 mbits |= MO_SR; /* pin 23, could be used as RTS */
478
479 (void) dcmmctl(dev, mbits, DMSET); /* enable port */
480
481 /* Set soft-carrier if so configured. */
482 if ((sc->sc_softCAR & (1 << port)) ||
483 (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
484 tp->t_state |= TS_CARR_ON;
485
486 #ifdef DEBUG
487 if (dcmdebug & DDB_MODEM)
488 printf("%s: dcmopen port %d softcarr %c\n",
489 sc->sc_dev.dv_xname, port,
490 (tp->t_state & TS_CARR_ON) ? '1' : '0');
491 #endif
492
493 /* Wait for carrier if necessary. */
494 if ((flag & O_NONBLOCK) == 0)
495 while ((tp->t_cflag & CLOCAL) == 0 &&
496 (tp->t_state & TS_CARR_ON) == 0) {
497 tp->t_state |= TS_WOPEN;
498 error = ttysleep(tp, (caddr_t)&tp->t_rawq,
499 TTIPRI | PCATCH, ttopen, 0);
500 if (error) {
501 splx(s);
502 return (error);
503 }
504 }
505
506 splx(s);
507
508 #ifdef DEBUG
509 if (dcmdebug & DDB_OPENCLOSE)
510 printf("%s port %d: dcmopen: st %x fl %x\n",
511 sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags);
512 #endif
513 if (error == 0)
514 error = (*linesw[tp->t_line].l_open)(dev, tp);
515
516 return (error);
517 }
518
519 /*ARGSUSED*/
520 int
521 dcmclose(dev, flag, mode, p)
522 dev_t dev;
523 int flag, mode;
524 struct proc *p;
525 {
526 int s, unit, board, port;
527 struct dcm_softc *sc;
528 struct tty *tp;
529
530 unit = DCMUNIT(dev);
531 board = DCMBOARD(unit);
532 port = DCMPORT(unit);
533
534 sc = dcm_cd.cd_devs[board];
535 tp = sc->sc_tty[port];
536
537 (*linesw[tp->t_line].l_close)(tp, flag);
538
539 s = spltty();
540
541 if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
542 (tp->t_state & TS_ISOPEN) == 0)
543 (void) dcmmctl(dev, MO_OFF, DMSET);
544 #ifdef DEBUG
545 if (dcmdebug & DDB_OPENCLOSE)
546 printf("%s port %d: dcmclose: st %x fl %x\n",
547 sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags);
548 #endif
549 splx(s);
550 ttyclose(tp);
551 #if 0
552 tty_detach(tp);
553 ttyfree(tp);
554 sc->sc_tty[port] == NULL;
555 #endif
556 return (0);
557 }
558
559 int
560 dcmread(dev, uio, flag)
561 dev_t dev;
562 struct uio *uio;
563 int flag;
564 {
565 int unit, board, port;
566 struct dcm_softc *sc;
567 struct tty *tp;
568
569 unit = DCMUNIT(dev);
570 board = DCMBOARD(unit);
571 port = DCMPORT(unit);
572
573 sc = dcm_cd.cd_devs[board];
574 tp = sc->sc_tty[port];
575
576 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
577 }
578
579 int
580 dcmwrite(dev, uio, flag)
581 dev_t dev;
582 struct uio *uio;
583 int flag;
584 {
585 int unit, board, port;
586 struct dcm_softc *sc;
587 struct tty *tp;
588
589 unit = DCMUNIT(dev);
590 board = DCMBOARD(unit);
591 port = DCMPORT(unit);
592
593 sc = dcm_cd.cd_devs[board];
594 tp = sc->sc_tty[port];
595
596 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
597 }
598
599 struct tty *
600 dcmtty(dev)
601 dev_t dev;
602 {
603 int unit, board, port;
604 struct dcm_softc *sc;
605
606 unit = DCMUNIT(dev);
607 board = DCMBOARD(unit);
608 port = DCMPORT(unit);
609
610 sc = dcm_cd.cd_devs[board];
611
612 return (sc->sc_tty[port]);
613 }
614
615 int
616 dcmintr(arg)
617 void *arg;
618 {
619 struct dcm_softc *sc = arg;
620 struct dcmdevice *dcm = sc->sc_dcm;
621 struct dcmischeme *dis = &sc->sc_scheme;
622 int brd = sc->sc_dev.dv_unit;
623 int code, i;
624 int pcnd[4], mcode, mcnd[4];
625
626 /*
627 * Do all guarded accesses right off to minimize
628 * block out of hardware.
629 */
630 SEM_LOCK(dcm);
631 if ((dcm->dcm_ic & IC_IR) == 0) {
632 SEM_UNLOCK(dcm);
633 return (0);
634 }
635 for (i = 0; i < 4; i++) {
636 pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
637 dcm->dcm_icrtab[i].dcm_data = 0;
638 code = sc->sc_modem[i]->mdmin;
639 if (sc->sc_flags & DCM_STDDCE)
640 code = hp2dce_in(code);
641 mcnd[i] = code;
642 }
643 code = dcm->dcm_iir & IIR_MASK;
644 dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */
645 mcode = dcm->dcm_modemintr;
646 dcm->dcm_modemintr = 0;
647 SEM_UNLOCK(dcm);
648
649 #ifdef DEBUG
650 if (dcmdebug & DDB_INTR) {
651 printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
652 sc->sc_dev.dv_xname, code, pcnd[0], pcnd[1],
653 pcnd[2], pcnd[3]);
654 printf("miir %x mc %x/%x/%x/%x\n",
655 mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
656 }
657 #endif
658 if (code & IIR_TIMEO)
659 dcmrint(sc);
660 if (code & IIR_PORT0)
661 dcmpint(sc, 0, pcnd[0]);
662 if (code & IIR_PORT1)
663 dcmpint(sc, 1, pcnd[1]);
664 if (code & IIR_PORT2)
665 dcmpint(sc, 2, pcnd[2]);
666 if (code & IIR_PORT3)
667 dcmpint(sc, 3, pcnd[3]);
668 if (code & IIR_MODM) {
669 if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */
670 dcmmint(sc, 0, mcnd[0]);
671 if (mcode & 0x2)
672 dcmmint(sc, 1, mcnd[1]);
673 if (mcode & 0x4)
674 dcmmint(sc, 2, mcnd[2]);
675 if (mcode & 0x8)
676 dcmmint(sc, 3, mcnd[3]);
677 }
678
679 /*
680 * Chalk up a receiver interrupt if the timer running or one of
681 * the ports reports a special character interrupt.
682 */
683 if ((code & IIR_TIMEO) ||
684 ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
685 dis->dis_intr++;
686 /*
687 * See if it is time to check/change the interrupt rate.
688 */
689 if (dcmistype < 0 &&
690 (i = time.tv_sec - dis->dis_time) >= dcminterval) {
691 /*
692 * If currently per-character and averaged over 70 interrupts
693 * per-second (66 is threshold of 600 baud) in last interval,
694 * switch to timer mode.
695 *
696 * XXX decay counts ala load average to avoid spikes?
697 */
698 if (dis->dis_perchar && dis->dis_intr > 70 * i)
699 dcmsetischeme(brd, DIS_TIMER);
700 /*
701 * If currently using timer and had more interrupts than
702 * received characters in the last interval, switch back
703 * to per-character. Note that after changing to per-char
704 * we must process any characters already in the queue
705 * since they may have arrived before the bitmap was setup.
706 *
707 * XXX decay counts?
708 */
709 else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
710 dcmsetischeme(brd, DIS_PERCHAR);
711 dcmrint(sc);
712 }
713 dis->dis_intr = dis->dis_char = 0;
714 dis->dis_time = time.tv_sec;
715 }
716 return (1);
717 }
718
719 /*
720 * Port interrupt. Can be two things:
721 * First, it might be a special character (exception interrupt);
722 * Second, it may be a buffer empty (transmit interrupt);
723 */
724 void
725 dcmpint(sc, port, code)
726 struct dcm_softc *sc;
727 int port, code;
728 {
729
730 if (code & IT_SPEC)
731 dcmreadbuf(sc, port);
732 if (code & IT_TX)
733 dcmxint(sc, port);
734 }
735
736 void
737 dcmrint(sc)
738 struct dcm_softc *sc;
739 {
740 int port;
741
742 for (port = 0; port < NDCMPORT; port++)
743 dcmreadbuf(sc, port);
744 }
745
746 void
747 dcmreadbuf(sc, port)
748 struct dcm_softc *sc;
749 int port;
750 {
751 struct dcmdevice *dcm = sc->sc_dcm;
752 struct tty *tp = sc->sc_tty[port];
753 struct dcmpreg *pp = dcm_preg(dcm, port);
754 struct dcmrfifo *fifo;
755 int c, stat;
756 u_int head;
757 int nch = 0;
758 #ifdef DCMSTATS
759 struct dcmstats *dsp = &sc->sc_stats;
760
761 dsp->rints++;
762 #endif
763 if ((tp->t_state & TS_ISOPEN) == 0) {
764 #ifdef KGDB
765 if ((makedev(dcmmajor, minor(tp->t_dev)) == kgdb_dev) &&
766 (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
767 dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
768 pp->r_head = (head + 2) & RX_MASK;
769 kgdb_connect(0); /* trap into kgdb */
770 return;
771 }
772 #endif /* KGDB */
773 pp->r_head = pp->r_tail & RX_MASK;
774 return;
775 }
776
777 head = pp->r_head & RX_MASK;
778 fifo = &dcm->dcm_rfifos[3-port][head>>1];
779 /*
780 * XXX upper bound on how many chars we will take in one swallow?
781 */
782 while (head != (pp->r_tail & RX_MASK)) {
783 /*
784 * Get character/status and update head pointer as fast
785 * as possible to make room for more characters.
786 */
787 c = fifo->data_char;
788 stat = fifo->data_stat;
789 head = (head + 2) & RX_MASK;
790 pp->r_head = head;
791 fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
792 nch++;
793
794 #ifdef DEBUG
795 if (dcmdebug & DDB_INPUT)
796 printf("%s port %d: dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
797 sc->sc_dev.dv_xname, port,
798 c&0xFF, c, stat&0xFF,
799 tp->t_flags, head, pp->r_tail);
800 #endif
801 /*
802 * Check for and handle errors
803 */
804 if (stat & RD_MASK) {
805 #ifdef DEBUG
806 if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
807 printf("%s port %d: dcmreadbuf: err: c%x('%c') s%x\n",
808 sc->sc_dev.dv_xname, port,
809 stat, c&0xFF, c);
810 #endif
811 if (stat & (RD_BD | RD_FE))
812 c |= TTY_FE;
813 else if (stat & RD_PE)
814 c |= TTY_PE;
815 else if (stat & RD_OVF)
816 log(LOG_WARNING,
817 "%s port %d: silo overflow\n",
818 sc->sc_dev.dv_xname, port);
819 else if (stat & RD_OE)
820 log(LOG_WARNING,
821 "%s port %d: uart overflow\n",
822 sc->sc_dev.dv_xname, port);
823 }
824 (*linesw[tp->t_line].l_rint)(c, tp);
825 }
826 sc->sc_scheme.dis_char += nch;
827
828 #ifdef DCMSTATS
829 dsp->rchars += nch;
830 if (nch <= DCMRBSIZE)
831 dsp->rsilo[nch]++;
832 else
833 dsp->rsilo[DCMRBSIZE+1]++;
834 #endif
835 }
836
837 void
838 dcmxint(sc, port)
839 struct dcm_softc *sc;
840 int port;
841 {
842 struct tty *tp = sc->sc_tty[port];
843
844 tp->t_state &= ~TS_BUSY;
845 if (tp->t_state & TS_FLUSH)
846 tp->t_state &= ~TS_FLUSH;
847 (*linesw[tp->t_line].l_start)(tp);
848 }
849
850 void
851 dcmmint(sc, port, mcnd)
852 struct dcm_softc *sc;
853 int port, mcnd;
854 {
855 int delta;
856 struct tty *tp;
857 struct dcmdevice *dcm = sc->sc_dcm;
858
859 tp = sc->sc_tty[port];
860
861 #ifdef DEBUG
862 if (dcmdebug & DDB_MODEM)
863 printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
864 sc->sc_dev.dv_xname, port, mcnd, sc->sc_mcndlast[port]);
865 #endif
866 delta = mcnd ^ sc->sc_mcndlast[port];
867 sc->sc_mcndlast[port] = mcnd;
868 if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
869 (tp->t_flags & CCTS_OFLOW)) {
870 if (mcnd & MI_CTS) {
871 tp->t_state &= ~TS_TTSTOP;
872 ttstart(tp);
873 } else
874 tp->t_state |= TS_TTSTOP; /* inline dcmstop */
875 }
876 if (delta & MI_CD) {
877 if (mcnd & MI_CD)
878 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
879 else if ((sc->sc_softCAR & (1 << port)) == 0 &&
880 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
881 sc->sc_modem[port]->mdmout = MO_OFF;
882 SEM_LOCK(dcm);
883 dcm->dcm_modemchng |= (1 << port);
884 dcm->dcm_cr |= CR_MODM;
885 SEM_UNLOCK(dcm);
886 DELAY(10); /* time to change lines */
887 }
888 }
889 }
890
891 int
892 dcmioctl(dev, cmd, data, flag, p)
893 dev_t dev;
894 u_long cmd;
895 caddr_t data;
896 int flag;
897 struct proc *p;
898 {
899 struct dcm_softc *sc;
900 struct tty *tp;
901 struct dcmdevice *dcm;
902 int board, port, unit = DCMUNIT(dev);
903 int error, s;
904
905 port = DCMPORT(unit);
906 board = DCMBOARD(unit);
907
908 sc = dcm_cd.cd_devs[board];
909 dcm = sc->sc_dcm;
910 tp = sc->sc_tty[port];
911
912 #ifdef DEBUG
913 if (dcmdebug & DDB_IOCTL)
914 printf("%s port %d: dcmioctl: cmd %x data %x flag %x\n",
915 sc->sc_dev.dv_xname, port, cmd, *data, flag);
916 #endif
917 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
918 if (error >= 0)
919 return (error);
920 error = ttioctl(tp, cmd, data, flag, p);
921 if (error >= 0)
922 return (error);
923
924 switch (cmd) {
925 case TIOCSBRK:
926 /*
927 * Wait for transmitter buffer to empty
928 */
929 s = spltty();
930 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
931 DELAY(DCM_USPERCH(tp->t_ospeed));
932 SEM_LOCK(dcm);
933 dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
934 dcm->dcm_cr |= (1 << port); /* start break */
935 SEM_UNLOCK(dcm);
936 splx(s);
937 break;
938
939 case TIOCCBRK:
940 SEM_LOCK(dcm);
941 dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
942 dcm->dcm_cr |= (1 << port); /* end break */
943 SEM_UNLOCK(dcm);
944 break;
945
946 case TIOCSDTR:
947 (void) dcmmctl(dev, MO_ON, DMBIS);
948 break;
949
950 case TIOCCDTR:
951 (void) dcmmctl(dev, MO_ON, DMBIC);
952 break;
953
954 case TIOCMSET:
955 (void) dcmmctl(dev, *(int *)data, DMSET);
956 break;
957
958 case TIOCMBIS:
959 (void) dcmmctl(dev, *(int *)data, DMBIS);
960 break;
961
962 case TIOCMBIC:
963 (void) dcmmctl(dev, *(int *)data, DMBIC);
964 break;
965
966 case TIOCMGET:
967 *(int *)data = dcmmctl(dev, 0, DMGET);
968 break;
969
970 case TIOCGFLAGS: {
971 int bits = 0;
972
973 if ((sc->sc_softCAR & (1 << port)))
974 bits |= TIOCFLAG_SOFTCAR;
975
976 if (tp->t_cflag & CLOCAL)
977 bits |= TIOCFLAG_CLOCAL;
978
979 *(int *)data = bits;
980 break;
981 }
982
983 case TIOCSFLAGS: {
984 int userbits;
985
986 error = suser(p->p_ucred, &p->p_acflag);
987 if (error)
988 return (EPERM);
989
990 userbits = *(int *)data;
991
992 if ((userbits & TIOCFLAG_SOFTCAR) ||
993 ((sc->sc_flags & DCM_ISCONSOLE) &&
994 (port == DCMCONSPORT)))
995 sc->sc_softCAR |= (1 << port);
996
997 if (userbits & TIOCFLAG_CLOCAL)
998 tp->t_cflag |= CLOCAL;
999
1000 break;
1001 }
1002
1003 default:
1004 return (ENOTTY);
1005 }
1006 return (0);
1007 }
1008
1009 int
1010 dcmparam(tp, t)
1011 struct tty *tp;
1012 struct termios *t;
1013 {
1014 struct dcm_softc *sc;
1015 struct dcmdevice *dcm;
1016 int unit, board, port, mode, cflag = t->c_cflag;
1017 int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
1018
1019 unit = DCMUNIT(tp->t_dev);
1020 board = DCMBOARD(unit);
1021 port = DCMPORT(unit);
1022
1023 sc = dcm_cd.cd_devs[board];
1024 dcm = sc->sc_dcm;
1025
1026 /* check requested parameters */
1027 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
1028 return (EINVAL);
1029 /* and copy to tty */
1030 tp->t_ispeed = t->c_ispeed;
1031 tp->t_ospeed = t->c_ospeed;
1032 tp->t_cflag = cflag;
1033 if (ospeed == 0) {
1034 (void) dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
1035 return (0);
1036 }
1037
1038 mode = 0;
1039 switch (cflag&CSIZE) {
1040 case CS5:
1041 mode = LC_5BITS; break;
1042 case CS6:
1043 mode = LC_6BITS; break;
1044 case CS7:
1045 mode = LC_7BITS; break;
1046 case CS8:
1047 mode = LC_8BITS; break;
1048 }
1049 if (cflag&PARENB) {
1050 if (cflag&PARODD)
1051 mode |= LC_PODD;
1052 else
1053 mode |= LC_PEVEN;
1054 }
1055 if (cflag&CSTOPB)
1056 mode |= LC_2STOP;
1057 else
1058 mode |= LC_1STOP;
1059 #ifdef DEBUG
1060 if (dcmdebug & DDB_PARAM)
1061 printf("%s port %d: dcmparam: cflag %x mode %x speed %d uperch %d\n",
1062 sc->sc_dev.dv_xname, port, cflag, mode, tp->t_ospeed,
1063 DCM_USPERCH(tp->t_ospeed));
1064 #endif
1065
1066 /*
1067 * Wait for transmitter buffer to empty.
1068 */
1069 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1070 DELAY(DCM_USPERCH(tp->t_ospeed));
1071 /*
1072 * Make changes known to hardware.
1073 */
1074 dcm->dcm_data[port].dcm_baud = ospeed;
1075 dcm->dcm_data[port].dcm_conf = mode;
1076 SEM_LOCK(dcm);
1077 dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1078 dcm->dcm_cr |= (1 << port);
1079 SEM_UNLOCK(dcm);
1080 /*
1081 * Delay for config change to take place. Weighted by baud.
1082 * XXX why do we do this?
1083 */
1084 DELAY(16 * DCM_USPERCH(tp->t_ospeed));
1085 return (0);
1086 }
1087
1088 void
1089 dcmstart(tp)
1090 struct tty *tp;
1091 {
1092 struct dcm_softc *sc;
1093 struct dcmdevice *dcm;
1094 struct dcmpreg *pp;
1095 struct dcmtfifo *fifo;
1096 char *bp;
1097 u_int head, tail, next;
1098 int unit, board, port, nch;
1099 char buf[16];
1100 int s;
1101 #ifdef DCMSTATS
1102 struct dcmstats *dsp = &sc->sc_stats;
1103 int tch = 0;
1104 #endif
1105
1106 unit = DCMUNIT(tp->t_dev);
1107 board = DCMBOARD(unit);
1108 port = DCMPORT(unit);
1109
1110 sc = dcm_cd.cd_devs[board];
1111 dcm = sc->sc_dcm;
1112
1113 s = spltty();
1114 #ifdef DCMSTATS
1115 dsp->xints++;
1116 #endif
1117 #ifdef DEBUG
1118 if (dcmdebug & DDB_OUTPUT)
1119 printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
1120 sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags,
1121 tp->t_outq.c_cc);
1122 #endif
1123 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
1124 goto out;
1125 if (tp->t_outq.c_cc <= tp->t_lowat) {
1126 if (tp->t_state&TS_ASLEEP) {
1127 tp->t_state &= ~TS_ASLEEP;
1128 wakeup((caddr_t)&tp->t_outq);
1129 }
1130 selwakeup(&tp->t_wsel);
1131 }
1132 if (tp->t_outq.c_cc == 0) {
1133 #ifdef DCMSTATS
1134 dsp->xempty++;
1135 #endif
1136 goto out;
1137 }
1138
1139 pp = dcm_preg(dcm, port);
1140 tail = pp->t_tail & TX_MASK;
1141 next = (tail + 1) & TX_MASK;
1142 head = pp->t_head & TX_MASK;
1143 if (head == next)
1144 goto out;
1145 fifo = &dcm->dcm_tfifos[3-port][tail];
1146 again:
1147 nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
1148 #ifdef DCMSTATS
1149 tch += nch;
1150 #endif
1151 #ifdef DEBUG
1152 if (dcmdebug & DDB_OUTPUT)
1153 printf("\thead %x tail %x nch %d\n", head, tail, nch);
1154 #endif
1155 /*
1156 * Loop transmitting all the characters we can.
1157 */
1158 for (bp = buf; --nch >= 0; bp++) {
1159 fifo->data_char = *bp;
1160 pp->t_tail = next;
1161 /*
1162 * If this is the first character,
1163 * get the hardware moving right now.
1164 */
1165 if (bp == buf) {
1166 tp->t_state |= TS_BUSY;
1167 SEM_LOCK(dcm);
1168 dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1169 dcm->dcm_cr |= (1 << port);
1170 SEM_UNLOCK(dcm);
1171 }
1172 tail = next;
1173 fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
1174 next = (next + 1) & TX_MASK;
1175 }
1176 /*
1177 * Head changed while we were loading the buffer,
1178 * go back and load some more if we can.
1179 */
1180 if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
1181 #ifdef DCMSTATS
1182 dsp->xrestarts++;
1183 #endif
1184 head = pp->t_head & TX_MASK;
1185 goto again;
1186 }
1187
1188 /*
1189 * Kick it one last time in case it finished while we were
1190 * loading the last bunch.
1191 */
1192 if (bp > &buf[1]) {
1193 tp->t_state |= TS_BUSY;
1194 SEM_LOCK(dcm);
1195 dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1196 dcm->dcm_cr |= (1 << port);
1197 SEM_UNLOCK(dcm);
1198 }
1199 #ifdef DEBUG
1200 if (dcmdebug & DDB_INTR)
1201 printf("%s port %d: dcmstart(%d): head %x tail %x outqcc %d\n",
1202 sc->sc_dev.dv_xname, port, head, tail, tp->t_outq.c_cc);
1203 #endif
1204 out:
1205 #ifdef DCMSTATS
1206 dsp->xchars += tch;
1207 if (tch <= DCMXBSIZE)
1208 dsp->xsilo[tch]++;
1209 else
1210 dsp->xsilo[DCMXBSIZE+1]++;
1211 #endif
1212 splx(s);
1213 }
1214
1215 /*
1216 * Stop output on a line.
1217 */
1218 void
1219 dcmstop(tp, flag)
1220 struct tty *tp;
1221 int flag;
1222 {
1223 int s;
1224
1225 s = spltty();
1226 if (tp->t_state & TS_BUSY) {
1227 /* XXX is there some way to safely stop transmission? */
1228 if ((tp->t_state&TS_TTSTOP) == 0)
1229 tp->t_state |= TS_FLUSH;
1230 }
1231 splx(s);
1232 }
1233
1234 /*
1235 * Modem control
1236 */
1237 int
1238 dcmmctl(dev, bits, how)
1239 dev_t dev;
1240 int bits, how;
1241 {
1242 struct dcm_softc *sc;
1243 struct dcmdevice *dcm;
1244 int s, unit, brd, port, hit = 0;
1245
1246 unit = DCMUNIT(dev);
1247 brd = DCMBOARD(unit);
1248 port = DCMPORT(unit);
1249
1250 sc = dcm_cd.cd_devs[brd];
1251 dcm = sc->sc_dcm;
1252
1253 #ifdef DEBUG
1254 if (dcmdebug & DDB_MODEM)
1255 printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
1256 sc->sc_dev.dv_xname, port, bits, how);
1257 #endif
1258
1259 s = spltty();
1260
1261 switch (how) {
1262 case DMSET:
1263 sc->sc_modem[port]->mdmout = bits;
1264 hit++;
1265 break;
1266
1267 case DMBIS:
1268 sc->sc_modem[port]->mdmout |= bits;
1269 hit++;
1270 break;
1271
1272 case DMBIC:
1273 sc->sc_modem[port]->mdmout &= ~bits;
1274 hit++;
1275 break;
1276
1277 case DMGET:
1278 bits = sc->sc_modem[port]->mdmin;
1279 if (sc->sc_flags & DCM_STDDCE)
1280 bits = hp2dce_in(bits);
1281 break;
1282 }
1283 if (hit) {
1284 SEM_LOCK(dcm);
1285 dcm->dcm_modemchng |= 1<<(unit & 3);
1286 dcm->dcm_cr |= CR_MODM;
1287 SEM_UNLOCK(dcm);
1288 DELAY(10); /* delay until done */
1289 (void) splx(s);
1290 }
1291 return (bits);
1292 }
1293
1294 /*
1295 * Set board to either interrupt per-character or at a fixed interval.
1296 */
1297 void
1298 dcmsetischeme(brd, flags)
1299 int brd, flags;
1300 {
1301 struct dcm_softc *sc = dcm_cd.cd_devs[brd];
1302 struct dcmdevice *dcm = sc->sc_dcm;
1303 struct dcmischeme *dis = &sc->sc_scheme;
1304 int i;
1305 u_char mask;
1306 int perchar = flags & DIS_PERCHAR;
1307
1308 #ifdef DEBUG
1309 if (dcmdebug & DDB_INTSCHM)
1310 printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
1311 sc->sc_dev.dv_xname, perchar, dis->dis_perchar,
1312 dis->dis_intr, dis->dis_char);
1313 if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
1314 printf("%s: dcmsetischeme: redundent request %d\n",
1315 sc->sc_dev.dv_xname, perchar);
1316 return;
1317 }
1318 #endif
1319 /*
1320 * If perchar is non-zero, we enable interrupts on all characters
1321 * otherwise we disable perchar interrupts and use periodic
1322 * polling interrupts.
1323 */
1324 dis->dis_perchar = perchar;
1325 mask = perchar ? 0xf : 0x0;
1326 for (i = 0; i < 256; i++)
1327 dcm->dcm_bmap[i].data_data = mask;
1328 /*
1329 * Don't slow down tandem mode, interrupt on flow control
1330 * chars for any port on the board.
1331 */
1332 if (!perchar) {
1333 struct tty *tp;
1334 int c;
1335
1336 for (i = 0; i < NDCMPORT; i++) {
1337 tp = sc->sc_tty[i];
1338
1339 if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
1340 dcm->dcm_bmap[c].data_data |= (1 << i);
1341 if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
1342 dcm->dcm_bmap[c].data_data |= (1 << i);
1343 }
1344 }
1345 /*
1346 * Board starts with timer disabled so if first call is to
1347 * set perchar mode then we don't want to toggle the timer.
1348 */
1349 if (flags == (DIS_RESET|DIS_PERCHAR))
1350 return;
1351 /*
1352 * Toggle card 16.7ms interrupts (we first make sure that card
1353 * has cleared the bit so it will see the toggle).
1354 */
1355 while (dcm->dcm_cr & CR_TIMER)
1356 ;
1357 SEM_LOCK(dcm);
1358 dcm->dcm_cr |= CR_TIMER;
1359 SEM_UNLOCK(dcm);
1360 }
1361
1362 void
1363 dcminit(dcm, port, rate)
1364 struct dcmdevice *dcm;
1365 int port, rate;
1366 {
1367 int s, mode;
1368
1369 mode = LC_8BITS | LC_1STOP;
1370
1371 s = splhigh();
1372
1373 /*
1374 * Wait for transmitter buffer to empty.
1375 */
1376 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1377 DELAY(DCM_USPERCH(rate));
1378
1379 /*
1380 * Make changes known to hardware.
1381 */
1382 dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1383 dcm->dcm_data[port].dcm_conf = mode;
1384 SEM_LOCK(dcm);
1385 dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1386 dcm->dcm_cr |= (1 << port);
1387 SEM_UNLOCK(dcm);
1388
1389 /*
1390 * Delay for config change to take place. Weighted by baud.
1391 * XXX why do we do this?
1392 */
1393 DELAY(16 * DCM_USPERCH(rate));
1394 splx(s);
1395 }
1396
1397 /*
1398 * Empirically derived self-test magic
1399 */
1400 int
1401 dcmselftest(sc)
1402 struct dcm_softc *sc;
1403 {
1404 struct dcmdevice *dcm = sc->sc_dcm;
1405 int timo = 0;
1406 int s, rv;
1407
1408 rv = 1;
1409
1410 s = splhigh();
1411 dcm->dcm_rsid = DCMRS;
1412 DELAY(50000); /* 5000 is not long enough */
1413 dcm->dcm_rsid = 0;
1414 dcm->dcm_ic = IC_IE;
1415 dcm->dcm_cr = CR_SELFT;
1416 while ((dcm->dcm_ic & IC_IR) == 0) {
1417 if (++timo == 20000)
1418 goto out;
1419 DELAY(1);
1420 }
1421 DELAY(50000); /* XXX why is this needed ???? */
1422 while ((dcm->dcm_iir & IIR_SELFT) == 0) {
1423 if (++timo == 400000)
1424 goto out;
1425 DELAY(1);
1426 }
1427 DELAY(50000); /* XXX why is this needed ???? */
1428 if (dcm->dcm_stcon != ST_OK) {
1429 #if 0
1430 if (hd->hp_args->hw_sc != conscode)
1431 printf("dcm%d: self test failed: %x\n",
1432 brd, dcm->dcm_stcon);
1433 #endif
1434 goto out;
1435 }
1436 dcm->dcm_ic = IC_ID;
1437 rv = 0;
1438
1439 out:
1440 splx(s);
1441 return (rv);
1442 }
1443
1444 /*
1445 * Following are all routines needed for DCM to act as console
1446 */
1447
1448 int
1449 dcm_console_scan(scode, va, arg)
1450 int scode;
1451 caddr_t va;
1452 void *arg;
1453 {
1454 struct dcmdevice *dcm = (struct dcmdevice *)va;
1455 struct consdev *cp = arg;
1456 u_char *dioiidev;
1457 int force = 0, pri;
1458
1459 switch (dcm->dcm_rsid) {
1460 case DCMID:
1461 pri = CN_NORMAL;
1462 break;
1463
1464 case DCMID|DCMCON:
1465 pri = CN_REMOTE;
1466 break;
1467
1468 default:
1469 return (0);
1470 }
1471
1472 #ifdef CONSCODE
1473 /*
1474 * Raise our priority, if appropriate.
1475 */
1476 if (scode == CONSCODE) {
1477 pri = CN_REMOTE;
1478 force = conforced = 1;
1479 }
1480 #endif
1481
1482 /* Only raise priority. */
1483 if (pri > cp->cn_pri)
1484 cp->cn_pri = pri;
1485
1486 /*
1487 * If our priority is higher than the currently-remembered
1488 * console, stash our priority, for the benefit of dcmcninit().
1489 */
1490 if (((cn_tab == NULL) || (cp->cn_pri > cn_tab->cn_pri)) || force) {
1491 cn_tab = cp;
1492 if (scode >= 132) {
1493 dioiidev = (u_char *)va;
1494 return ((dioiidev[0x101] + 1) * 0x100000);
1495 }
1496 return (DIOCSIZE);
1497 }
1498 return (0);
1499 }
1500
1501 void
1502 dcmcnprobe(cp)
1503 struct consdev *cp;
1504 {
1505
1506 /* locate the major number */
1507 for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)
1508 if (cdevsw[dcmmajor].d_open == dcmopen)
1509 break;
1510
1511 /* initialize required fields */
1512 cp->cn_dev = makedev(dcmmajor, 0); /* XXX */
1513 cp->cn_pri = CN_DEAD;
1514
1515 /* Abort early if console already forced. */
1516 if (conforced)
1517 return;
1518
1519 console_scan(dcm_console_scan, cp);
1520
1521 #ifdef KGDB_CHEAT
1522 /* XXX this needs to be fixed. */
1523 /*
1524 * This doesn't currently work, at least not with ite consoles;
1525 * the console hasn't been initialized yet.
1526 */
1527 if (major(kgdb_dev) == dcmmajor &&
1528 DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
1529 dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate);
1530 if (kgdb_debug_init) {
1531 /*
1532 * We assume that console is ready for us...
1533 * this assumes that a dca or ite console
1534 * has been selected already and will init
1535 * on the first putc.
1536 */
1537 printf("dcm%d: ", DCMUNIT(kgdb_dev));
1538 kgdb_connect(1);
1539 }
1540 }
1541 #endif
1542 }
1543
1544 /* ARGSUSED */
1545 void
1546 dcmcninit(cp)
1547 struct consdev *cp;
1548 {
1549
1550 dcm_cn = (struct dcmdevice *)conaddr;
1551 dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
1552 dcmconsinit = 1;
1553 }
1554
1555 /* ARGSUSED */
1556 int
1557 dcmcngetc(dev)
1558 dev_t dev;
1559 {
1560 struct dcmrfifo *fifo;
1561 struct dcmpreg *pp;
1562 u_int head;
1563 int s, c, stat;
1564
1565 pp = dcm_preg(dcm_cn, DCMCONSPORT);
1566
1567 s = splhigh();
1568 head = pp->r_head & RX_MASK;
1569 fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1];
1570 while (head == (pp->r_tail & RX_MASK))
1571 ;
1572 /*
1573 * If board interrupts are enabled, just let our received char
1574 * interrupt through in case some other port on the board was
1575 * busy. Otherwise we must clear the interrupt.
1576 */
1577 SEM_LOCK(dcm_cn);
1578 if ((dcm_cn->dcm_ic & IC_IE) == 0)
1579 stat = dcm_cn->dcm_iir;
1580 SEM_UNLOCK(dcm_cn);
1581 c = fifo->data_char;
1582 stat = fifo->data_stat;
1583 pp->r_head = (head + 2) & RX_MASK;
1584 splx(s);
1585 return (c);
1586 }
1587
1588 /*
1589 * Console kernel output character routine.
1590 */
1591 /* ARGSUSED */
1592 void
1593 dcmcnputc(dev, c)
1594 dev_t dev;
1595 int c;
1596 {
1597 struct dcmpreg *pp;
1598 unsigned tail;
1599 int s, stat;
1600
1601 pp = dcm_preg(dcm_cn, DCMCONSPORT);
1602
1603 s = splhigh();
1604 #ifdef KGDB
1605 if (dev != kgdb_dev)
1606 #endif
1607 if (dcmconsinit == 0) {
1608 dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
1609 dcmconsinit = 1;
1610 }
1611 tail = pp->t_tail & TX_MASK;
1612 while (tail != (pp->t_head & TX_MASK))
1613 ;
1614 dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c;
1615 pp->t_tail = tail = (tail + 1) & TX_MASK;
1616 SEM_LOCK(dcm_cn);
1617 dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX;
1618 dcm_cn->dcm_cr |= (1 << DCMCONSPORT);
1619 SEM_UNLOCK(dcm_cn);
1620 while (tail != (pp->t_head & TX_MASK))
1621 ;
1622 /*
1623 * If board interrupts are enabled, just let our completion
1624 * interrupt through in case some other port on the board
1625 * was busy. Otherwise we must clear the interrupt.
1626 */
1627 if ((dcm_cn->dcm_ic & IC_IE) == 0) {
1628 SEM_LOCK(dcm_cn);
1629 stat = dcm_cn->dcm_iir;
1630 SEM_UNLOCK(dcm_cn);
1631 }
1632 splx(s);
1633 }
1634