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