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