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