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