Annotation of sys/arch/hp300/dev/dca.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: dca.c,v 1.31 2006/01/01 11:59:37 miod Exp $ */
2: /* $NetBSD: dca.c,v 1.35 1997/05/05 20:58:18 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 1995, 1996, 1997 Jason R. Thorpe. All rights reserved.
6: * Copyright (c) 1982, 1986, 1990, 1993
7: * The Regents of the University of California. All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)dca.c 8.2 (Berkeley) 1/12/94
34: */
35:
36: /*
37: * Driver for the 98626/98644/internal serial interface on hp300/hp400,
38: * based on the National Semiconductor INS8250/NS16550AF/WD16C552 UARTs.
39: *
40: * N.B. On the hp700 and some hp300s, there is a "secret bit" with
41: * undocumented behavior. The third bit of the Modem Control Register
42: * (MCR_IEN == 0x08) must be set to enable interrupts. Failure to do
43: * so can result in deadlock on those machines, whereas the don't seem to
44: * be any harmful side-effects from setting this bit on non-affected
45: * machines.
46: */
47:
48: #include <sys/param.h>
49: #include <sys/systm.h>
50: #include <sys/ioctl.h>
51: #include <sys/proc.h>
52: #include <sys/tty.h>
53: #include <sys/conf.h>
54: #include <sys/file.h>
55: #include <sys/uio.h>
56: #include <sys/kernel.h>
57: #include <sys/syslog.h>
58: #include <sys/device.h>
59:
60: #include <machine/autoconf.h>
61: #include <machine/bus.h>
62: #include <machine/cpu.h>
63: #include <machine/intr.h>
64:
65: #include <dev/cons.h>
66:
67: #include <hp300/dev/dioreg.h>
68: #include <hp300/dev/diovar.h>
69: #include <hp300/dev/diodevs.h>
70: #include <hp300/dev/dcareg.h>
71:
72: #ifdef DDB
73: #include <ddb/db_var.h>
74: #endif
75:
76: struct dca_softc {
77: struct device sc_dev; /* generic device glue */
78: struct isr sc_isr;
79: struct dcadevice *sc_dca; /* pointer to hardware */
80: struct tty *sc_tty; /* our tty instance */
81: int sc_oflows; /* overflow counter */
82: short sc_flags; /* state flags */
83: u_char sc_cua; /* callout mode */
84:
85: /*
86: * Bits for sc_flags.
87: */
88: #define DCA_ACTIVE 0x0001 /* indicates live unit */
89: #define DCA_SOFTCAR 0x0002 /* indicates soft-carrier */
90: #define DCA_HASFIFO 0x0004 /* indicates unit has FIFO */
91: #define DCA_ISCONSOLE 0x0008 /* indicates unit is console */
92:
93: };
94:
95: int dcamatch(struct device *, void *, void *);
96: void dcaattach(struct device *, struct device *, void *);
97:
98: struct cfattach dca_ca = {
99: sizeof(struct dca_softc), dcamatch, dcaattach
100: };
101:
102: struct cfdriver dca_cd = {
103: NULL, "dca", DV_TTY
104: };
105:
106: int dcadefaultrate = TTYDEF_SPEED;
107: int dcamajor;
108:
109: cdev_decl(dca);
110:
111: int dcaintr(void *);
112: void dcaeint(struct dca_softc *, int);
113: void dcamint(struct dca_softc *);
114:
115: int dcaparam(struct tty *, struct termios *);
116: void dcastart(struct tty *);
117: int dcastop(struct tty *, int);
118: int dcamctl(struct dca_softc *, int, int);
119: void dcainit(struct dcadevice *, int);
120:
121: int dca_console_scan(int, caddr_t, void *);
122: cons_decl(dca);
123:
124: /*
125: * Stuff for DCA console support.
126: */
127: static struct dcadevice *dca_cn = NULL; /* pointer to hardware */
128: static int dcaconsinit; /* has been initialized */
129:
130: const struct speedtab dcaspeedtab[] = {
131: { 0, 0 },
132: { 50, DCABRD(50) },
133: { 75, DCABRD(75) },
134: { 110, DCABRD(110) },
135: { 134, DCABRD(134) },
136: { 150, DCABRD(150) },
137: { 200, DCABRD(200) },
138: { 300, DCABRD(300) },
139: { 600, DCABRD(600) },
140: { 1200, DCABRD(1200) },
141: { 1800, DCABRD(1800) },
142: { 2400, DCABRD(2400) },
143: { 4800, DCABRD(4800) },
144: { 9600, DCABRD(9600) },
145: { 19200, DCABRD(19200) },
146: { 38400, DCABRD(38400) },
147: { -1, -1 },
148: };
149:
150: #ifdef KGDB
151: #include <machine/remote-sl.h>
152:
153: extern dev_t kgdb_dev;
154: extern int kgdb_rate;
155: extern int kgdb_debug_init;
156: #endif
157:
158: #define DCAUNIT(x) (minor(x) & 0x7f)
159: #define DCACUA(x) (minor(x) & 0x80)
160:
161: #ifdef DEBUG
162: long fifoin[17];
163: long fifoout[17];
164: long dcaintrcount[16];
165: long dcamintcount[16];
166: #endif
167:
168: void dcainit(struct dcadevice *, int);
169:
170: int
171: dcamatch(parent, match, aux)
172: struct device *parent;
173: void *match, *aux;
174: {
175: struct dio_attach_args *da = aux;
176:
177: switch (da->da_id) {
178: case DIO_DEVICE_ID_DCA0:
179: case DIO_DEVICE_ID_DCA0REM:
180: case DIO_DEVICE_ID_DCA1:
181: case DIO_DEVICE_ID_DCA1REM:
182: return (1);
183: }
184:
185: return (0);
186: }
187:
188: void
189: dcaattach(parent, self, aux)
190: struct device *parent, *self;
191: void *aux;
192: {
193: struct dca_softc *sc = (struct dca_softc *)self;
194: struct dio_attach_args *da = aux;
195: struct dcadevice *dca;
196: int unit = self->dv_unit;
197: int scode = da->da_scode;
198: int ipl;
199:
200: if (scode == conscode) {
201: dca = (struct dcadevice *)conaddr;
202: sc->sc_flags |= DCA_ISCONSOLE;
203: DELAY(100000);
204:
205: /*
206: * We didn't know which unit this would be during
207: * the console probe, so we have to fixup cn_dev here.
208: */
209: cn_tab->cn_dev = makedev(dcamajor, unit);
210: } else {
211: dca = (struct dcadevice *)iomap(dio_scodetopa(da->da_scode),
212: da->da_size);
213: if (dca == NULL) {
214: printf("\n%s: can't map registers\n",
215: sc->sc_dev.dv_xname);
216: return;
217: }
218: }
219:
220: sc->sc_dca = dca;
221:
222: ipl = DIO_IPL(dca);
223: printf(" ipl %d", ipl);
224:
225: dca->dca_reset = 0xFF;
226: DELAY(100);
227:
228: /* look for a NS 16550AF UART with FIFOs */
229: dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
230: DELAY(100);
231: if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
232: sc->sc_flags |= DCA_HASFIFO;
233:
234: /* Establish interrupt handler. */
235: sc->sc_isr.isr_func = dcaintr;
236: sc->sc_isr.isr_arg = sc;
237: sc->sc_isr.isr_ipl = ipl;
238: sc->sc_isr.isr_priority =
239: (sc->sc_flags & DCA_HASFIFO) ? IPL_TTY : IPL_TTYNOBUF;
240: dio_intr_establish(&sc->sc_isr, self->dv_xname);
241:
242: sc->sc_flags |= DCA_ACTIVE;
243: if (self->dv_cfdata->cf_flags)
244: sc->sc_flags |= DCA_SOFTCAR;
245:
246: /* Enable interrupts. */
247: dca->dca_ic = IC_IE;
248:
249: /*
250: * Need to reset baud rate, etc. of next print so reset dcaconsinit.
251: * Also make sure console is always "hardwired."
252: */
253: if (sc->sc_flags & DCA_ISCONSOLE) {
254: dcaconsinit = 0;
255: sc->sc_flags |= DCA_SOFTCAR;
256: printf(": console, ");
257: } else
258: printf(": ");
259:
260: if (sc->sc_flags & DCA_HASFIFO)
261: printf("working fifo\n");
262: else
263: printf("no fifo\n");
264:
265: #ifdef KGDB
266: if (kgdb_dev == makedev(dcamajor, unit)) {
267: if (sc->sc_flags & DCA_ISCONSOLE)
268: kgdb_dev = NODEV; /* can't debug over console port */
269: else {
270: dcainit(dca, kgdb_rate);
271: dcaconsinit = 1; /* don't re-init in dcaputc */
272: if (kgdb_debug_init) {
273: /*
274: * Print prefix of device name,
275: * let kgdb_connect print the rest.
276: */
277: printf("%s: ", sc->sc_dev.dv_xname);
278: kgdb_connect(1);
279: } else
280: printf("%s: kgdb enabled\n",
281: sc->sc_dev.dv_xname);
282: }
283: }
284: #endif
285: }
286:
287: /* ARGSUSED */
288: int
289: dcaopen(dev, flag, mode, p)
290: dev_t dev;
291: int flag, mode;
292: struct proc *p;
293: {
294: int unit = DCAUNIT(dev);
295: struct dca_softc *sc;
296: struct tty *tp;
297: struct dcadevice *dca;
298: u_char code;
299: int s, error = 0;
300:
301: if (unit >= dca_cd.cd_ndevs ||
302: (sc = dca_cd.cd_devs[unit]) == NULL)
303: return (ENXIO);
304:
305: if ((sc->sc_flags & DCA_ACTIVE) == 0)
306: return (ENXIO);
307:
308: dca = sc->sc_dca;
309:
310: s = spltty();
311: if (sc->sc_tty == NULL) {
312: tp = sc->sc_tty = ttymalloc();
313: } else
314: tp = sc->sc_tty;
315: splx(s);
316:
317: tp->t_oproc = dcastart;
318: tp->t_param = dcaparam;
319: tp->t_dev = dev;
320:
321: if ((tp->t_state & TS_ISOPEN) == 0) {
322: /*
323: * Sanity clause: reset the card on first open.
324: * The card might be left in an inconsistent state
325: * if card memory is read inadvertently.
326: */
327: dcainit(dca, dcadefaultrate);
328:
329: tp->t_state |= TS_WOPEN;
330: ttychars(tp);
331: tp->t_iflag = TTYDEF_IFLAG;
332: tp->t_oflag = TTYDEF_OFLAG;
333: tp->t_cflag = TTYDEF_CFLAG;
334: tp->t_lflag = TTYDEF_LFLAG;
335: tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
336:
337: s = spltty();
338:
339: dcaparam(tp, &tp->t_termios);
340: ttsetwater(tp);
341:
342: /* Set the FIFO threshold based on the receive speed. */
343: if (sc->sc_flags & DCA_HASFIFO)
344: dca->dca_fifo = FIFO_ENABLE | FIFO_RCV_RST |
345: FIFO_XMT_RST |
346: (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 :
347: FIFO_TRIGGER_14);
348:
349: /* Flush any pending I/O */
350: while ((dca->dca_iir & IIR_IMASK) == IIR_RXRDY)
351: code = dca->dca_data;
352:
353: } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
354: return (EBUSY);
355: else
356: s = spltty();
357:
358: /* Set modem control state. */
359: (void) dcamctl(sc, MCR_DTR | MCR_RTS, DMSET);
360:
361: /* Set soft-carrier if so configured. */
362: if ((sc->sc_flags & DCA_SOFTCAR) || DCACUA(dev) ||
363: (dcamctl(sc, 0, DMGET) & MSR_DCD))
364: tp->t_state |= TS_CARR_ON;
365:
366: if (DCACUA(dev)) {
367: if (tp->t_state & TS_ISOPEN) {
368: /* Ah, but someone already is dialed in... */
369: splx(s);
370: return (EBUSY);
371: }
372: sc->sc_cua = 1; /* We go into CUA mode */
373: }
374:
375: /* Wait for carrier if necessary. */
376: if (flag & O_NONBLOCK) {
377: if (!DCACUA(dev) && sc->sc_cua) {
378: /* Opening TTY non-blocking... but the CUA is busy */
379: splx(s);
380: return (EBUSY);
381: }
382: } else {
383: while (sc->sc_cua ||
384: ((tp->t_cflag & CLOCAL) == 0 &&
385: (tp->t_state & TS_CARR_ON) == 0)) {
386: tp->t_state |= TS_WOPEN;
387: error = ttysleep(tp, (caddr_t)&tp->t_rawq,
388: TTIPRI | PCATCH, ttopen, 0);
389: if (!DCACUA(dev) && sc->sc_cua && error == EINTR)
390: continue;
391: if (error) {
392: if (DCACUA(dev))
393: sc->sc_cua = 0;
394: splx(s);
395: return (error);
396: }
397: if (!DCACUA(dev) && sc->sc_cua)
398: continue;
399: }
400: }
401: splx(s);
402:
403: if (error == 0)
404: error = (*linesw[tp->t_line].l_open)(dev, tp);
405:
406: return (error);
407: }
408:
409: /*ARGSUSED*/
410: int
411: dcaclose(dev, flag, mode, p)
412: dev_t dev;
413: int flag, mode;
414: struct proc *p;
415: {
416: struct dca_softc *sc;
417: struct tty *tp;
418: struct dcadevice *dca;
419: int unit;
420: int s;
421:
422: unit = DCAUNIT(dev);
423:
424: sc = dca_cd.cd_devs[unit];
425:
426: dca = sc->sc_dca;
427: tp = sc->sc_tty;
428: (*linesw[tp->t_line].l_close)(tp, flag);
429:
430: s = spltty();
431:
432: dca->dca_cfcr &= ~CFCR_SBREAK;
433: #ifdef KGDB
434: /* do not disable interrupts if debugging */
435: if (dev != kgdb_dev)
436: #endif
437: dca->dca_ier = 0;
438: if (tp->t_cflag & HUPCL && (sc->sc_flags & DCA_SOFTCAR) == 0) {
439: /* XXX perhaps only clear DTR */
440: (void) dcamctl(sc, 0, DMSET);
441: }
442: tp->t_state &= ~(TS_BUSY | TS_FLUSH);
443: sc->sc_cua = 0;
444: splx(s);
445: ttyclose(tp);
446: #if 0
447: ttyfree(tp);
448: sc->sc_tty = NULL;
449: #endif
450: return (0);
451: }
452:
453: int
454: dcaread(dev, uio, flag)
455: dev_t dev;
456: struct uio *uio;
457: int flag;
458: {
459: int unit = DCAUNIT(dev);
460: struct dca_softc *sc;
461: struct tty *tp;
462: int error, of;
463:
464: sc = dca_cd.cd_devs[unit];
465:
466: tp = sc->sc_tty;
467: of = sc->sc_oflows;
468: error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
469: /*
470: * XXX hardly a reasonable thing to do, but reporting overflows
471: * at interrupt time just exacerbates the problem.
472: */
473: if (sc->sc_oflows != of)
474: log(LOG_WARNING, "%s: silo overflow\n", sc->sc_dev.dv_xname);
475: return (error);
476: }
477:
478: int
479: dcawrite(dev, uio, flag)
480: dev_t dev;
481: struct uio *uio;
482: int flag;
483: {
484: struct dca_softc *sc = dca_cd.cd_devs[DCAUNIT(dev)];
485: struct tty *tp = sc->sc_tty;
486:
487: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
488: }
489:
490: struct tty *
491: dcatty(dev)
492: dev_t dev;
493: {
494: struct dca_softc *sc = dca_cd.cd_devs[DCAUNIT(dev)];
495:
496: return (sc->sc_tty);
497: }
498:
499: int
500: dcaintr(arg)
501: void *arg;
502: {
503: struct dca_softc *sc = arg;
504: #ifdef KGDB
505: int unit = sc->sc_dev.dv_unit;
506: #endif
507: struct dcadevice *dca = sc->sc_dca;
508: struct tty *tp = sc->sc_tty;
509: u_char code;
510: int iflowdone = 0;
511:
512: /*
513: * If interrupts aren't enabled, then the interrupt can't
514: * be for us.
515: */
516: if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
517: return (0);
518:
519: for (;;) {
520: code = dca->dca_iir;
521: #ifdef DEBUG
522: dcaintrcount[code & IIR_IMASK]++;
523: #endif
524:
525: switch (code & IIR_IMASK) {
526: case IIR_NOPEND:
527: return (1);
528: case IIR_RXTOUT:
529: case IIR_RXRDY:
530: /* do time-critical read in-line */
531: /*
532: * Process a received byte. Inline for speed...
533: */
534: #ifdef KGDB
535: #define RCVBYTE() \
536: code = dca->dca_data; \
537: if (tp != NULL) { \
538: if ((tp->t_state & TS_ISOPEN) == 0) { \
539: if (code == FRAME_END && \
540: kgdb_dev == makedev(dcamajor, unit)) \
541: kgdb_connect(0); /* trap into kgdb */ \
542: } else \
543: (*linesw[tp->t_line].l_rint)(code, tp) \
544: }
545: #else
546: #define RCVBYTE() \
547: code = dca->dca_data; \
548: if (tp != NULL && (tp->t_state & TS_ISOPEN) != 0) \
549: (*linesw[tp->t_line].l_rint)(code, tp)
550: #endif
551: RCVBYTE();
552: if (sc->sc_flags & DCA_HASFIFO) {
553: #ifdef DEBUG
554: int fifocnt = 1;
555: #endif
556: while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
557: if (code == LSR_RXRDY) {
558: RCVBYTE();
559: } else
560: dcaeint(sc, code);
561: #ifdef DEBUG
562: fifocnt++;
563: #endif
564: }
565: #ifdef DEBUG
566: if (fifocnt > 16)
567: fifoin[0]++;
568: else
569: fifoin[fifocnt]++;
570: #endif
571: }
572: if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) &&
573: tp->t_rawq.c_cc > TTYHOG/2) {
574: dca->dca_mcr &= ~MCR_RTS;
575: iflowdone = 1;
576: }
577: break;
578: case IIR_TXRDY:
579: if (tp != NULL) {
580: tp->t_state &=~ (TS_BUSY|TS_FLUSH);
581: if (tp->t_line)
582: (*linesw[tp->t_line].l_start)(tp);
583: else
584: dcastart(tp);
585: }
586: break;
587: case IIR_RLS:
588: dcaeint(sc, dca->dca_lsr);
589: break;
590: default:
591: if (code & IIR_NOPEND)
592: return (1);
593: log(LOG_WARNING, "%s: weird interrupt: 0x%x\n",
594: sc->sc_dev.dv_xname, code);
595: /* FALLTHROUGH */
596: case IIR_MLSC:
597: dcamint(sc);
598: break;
599: }
600: }
601: }
602:
603: void
604: dcaeint(sc, stat)
605: struct dca_softc *sc;
606: int stat;
607: {
608: struct tty *tp = sc->sc_tty;
609: struct dcadevice *dca = sc->sc_dca;
610: int c;
611:
612: c = dca->dca_data;
613:
614: #if defined(DDB) && !defined(KGDB)
615: if ((sc->sc_flags & DCA_ISCONSOLE) && db_console && (stat & LSR_BI)) {
616: Debugger();
617: return;
618: }
619: #endif
620:
621: if (tp == NULL)
622: return;
623:
624: if ((tp->t_state & TS_ISOPEN) == 0) {
625: #ifdef KGDB
626: /* we don't care about parity errors */
627: if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
628: kgdb_dev == makedev(dcamajor, sc->sc_hd->hp_unit) &&
629: c == FRAME_END)
630: kgdb_connect(0); /* trap into kgdb */
631: #endif
632: return;
633: }
634:
635: if (stat & (LSR_BI | LSR_FE))
636: c |= TTY_FE;
637: else if (stat & LSR_PE)
638: c |= TTY_PE;
639: else if (stat & LSR_OE)
640: sc->sc_oflows++;
641: (*linesw[tp->t_line].l_rint)(c, tp);
642: }
643:
644: void
645: dcamint(sc)
646: struct dca_softc *sc;
647: {
648: struct tty *tp = sc->sc_tty;
649: struct dcadevice *dca = sc->sc_dca;
650: u_char stat;
651:
652: stat = dca->dca_msr;
653: #ifdef DEBUG
654: dcamintcount[stat & 0xf]++;
655: #endif
656:
657: if (tp == NULL)
658: return;
659:
660: if ((stat & MSR_DDCD) &&
661: (sc->sc_flags & DCA_SOFTCAR) == 0) {
662: if (stat & MSR_DCD)
663: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
664: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
665: dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
666: }
667: /*
668: * CTS change.
669: * If doing HW output flow control start/stop output as appropriate.
670: */
671: if ((stat & MSR_DCTS) &&
672: (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
673: if (stat & MSR_CTS) {
674: tp->t_state &=~ TS_TTSTOP;
675: dcastart(tp);
676: } else {
677: tp->t_state |= TS_TTSTOP;
678: }
679: }
680: }
681:
682: int
683: dcaioctl(dev, cmd, data, flag, p)
684: dev_t dev;
685: u_long cmd;
686: caddr_t data;
687: int flag;
688: struct proc *p;
689: {
690: int unit = DCAUNIT(dev);
691: struct dca_softc *sc = dca_cd.cd_devs[unit];
692: struct tty *tp = sc->sc_tty;
693: struct dcadevice *dca = sc->sc_dca;
694: int error;
695:
696: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
697: if (error >= 0)
698: return (error);
699: error = ttioctl(tp, cmd, data, flag, p);
700: if (error >= 0)
701: return (error);
702:
703: switch (cmd) {
704: case TIOCSBRK:
705: dca->dca_cfcr |= CFCR_SBREAK;
706: break;
707:
708: case TIOCCBRK:
709: dca->dca_cfcr &= ~CFCR_SBREAK;
710: break;
711:
712: case TIOCSDTR:
713: (void) dcamctl(sc, MCR_DTR | MCR_RTS, DMBIS);
714: break;
715:
716: case TIOCCDTR:
717: (void) dcamctl(sc, MCR_DTR | MCR_RTS, DMBIC);
718: break;
719:
720: case TIOCMSET:
721: (void) dcamctl(sc, *(int *)data, DMSET);
722: break;
723:
724: case TIOCMBIS:
725: (void) dcamctl(sc, *(int *)data, DMBIS);
726: break;
727:
728: case TIOCMBIC:
729: (void) dcamctl(sc, *(int *)data, DMBIC);
730: break;
731:
732: case TIOCMGET:
733: *(int *)data = dcamctl(sc, 0, DMGET);
734: break;
735:
736: case TIOCGFLAGS: {
737: int bits = 0;
738:
739: if (sc->sc_flags & DCA_SOFTCAR)
740: bits |= TIOCFLAG_SOFTCAR;
741:
742: if (tp->t_cflag & CLOCAL)
743: bits |= TIOCFLAG_CLOCAL;
744:
745: *(int *)data = bits;
746: break;
747: }
748:
749: case TIOCSFLAGS: {
750: int userbits;
751:
752: error = suser(p, 0);
753: if (error)
754: return (EPERM);
755:
756: userbits = *(int *)data;
757:
758: if ((userbits & TIOCFLAG_SOFTCAR) ||
759: (sc->sc_flags & DCA_ISCONSOLE))
760: sc->sc_flags |= DCA_SOFTCAR;
761:
762: if (userbits & TIOCFLAG_CLOCAL)
763: tp->t_cflag |= CLOCAL;
764:
765: break;
766: }
767:
768: default:
769: return (ENOTTY);
770: }
771: return (0);
772: }
773:
774: int
775: dcaparam(tp, t)
776: struct tty *tp;
777: struct termios *t;
778: {
779: int unit = DCAUNIT(tp->t_dev);
780: struct dca_softc *sc = dca_cd.cd_devs[unit];
781: struct dcadevice *dca = sc->sc_dca;
782: int cfcr, cflag = t->c_cflag;
783: int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
784: int s;
785:
786: /* check requested parameters */
787: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
788: return (EINVAL);
789:
790: switch (cflag & CSIZE) {
791: case CS5:
792: cfcr = CFCR_5BITS;
793: break;
794:
795: case CS6:
796: cfcr = CFCR_6BITS;
797: break;
798:
799: case CS7:
800: cfcr = CFCR_7BITS;
801: break;
802:
803: case CS8:
804: default: /* XXX gcc whines about cfcr being unitialized... */
805: cfcr = CFCR_8BITS;
806: break;
807: }
808: if (cflag & PARENB) {
809: cfcr |= CFCR_PENAB;
810: if ((cflag & PARODD) == 0)
811: cfcr |= CFCR_PEVEN;
812: }
813: if (cflag & CSTOPB)
814: cfcr |= CFCR_STOPB;
815:
816: s = spltty();
817:
818: if (ospeed == 0)
819: (void) dcamctl(sc, 0, DMSET); /* hang up line */
820:
821: /*
822: * Set the FIFO threshold based on the receive speed, if we
823: * are changing it.
824: */
825: if (tp->t_ispeed != t->c_ispeed) {
826: if (sc->sc_flags & DCA_HASFIFO)
827: dca->dca_fifo = FIFO_ENABLE |
828: (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 :
829: FIFO_TRIGGER_14);
830: }
831:
832: if (ospeed != 0) {
833: dca->dca_cfcr |= CFCR_DLAB;
834: dca->dca_data = ospeed & 0xFF;
835: dca->dca_ier = ospeed >> 8;
836: dca->dca_cfcr = cfcr;
837: } else
838: dca->dca_cfcr = cfcr;
839:
840: /* and copy to tty */
841: tp->t_ispeed = t->c_ispeed;
842: tp->t_ospeed = t->c_ospeed;
843: tp->t_cflag = cflag;
844:
845: dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
846: dca->dca_mcr |= MCR_IEN;
847:
848: splx(s);
849: return (0);
850: }
851:
852: void
853: dcastart(tp)
854: struct tty *tp;
855: {
856: int s, c, unit = DCAUNIT(tp->t_dev);
857: struct dca_softc *sc = dca_cd.cd_devs[unit];
858: struct dcadevice *dca = sc->sc_dca;
859:
860: s = spltty();
861:
862: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
863: goto out;
864: if (tp->t_outq.c_cc <= tp->t_lowat) {
865: if (tp->t_state & TS_ASLEEP) {
866: tp->t_state &= ~TS_ASLEEP;
867: wakeup((caddr_t)&tp->t_outq);
868: }
869: if (tp->t_outq.c_cc == 0)
870: goto out;
871: selwakeup(&tp->t_wsel);
872: }
873: if (dca->dca_lsr & LSR_TXRDY) {
874: tp->t_state |= TS_BUSY;
875: if (sc->sc_flags & DCA_HASFIFO) {
876: for (c = 0; c < 16 && tp->t_outq.c_cc; ++c)
877: dca->dca_data = getc(&tp->t_outq);
878: #ifdef DEBUG
879: if (c > 16)
880: fifoout[0]++;
881: else
882: fifoout[c]++;
883: #endif
884: } else
885: dca->dca_data = getc(&tp->t_outq);
886: }
887:
888: out:
889: splx(s);
890: }
891:
892: /*
893: * Stop output on a line.
894: */
895: /*ARGSUSED*/
896: int
897: dcastop(tp, flag)
898: struct tty *tp;
899: int flag;
900: {
901: int s;
902:
903: s = spltty();
904: if (tp->t_state & TS_BUSY)
905: if ((tp->t_state & TS_TTSTOP) == 0)
906: tp->t_state |= TS_FLUSH;
907: splx(s);
908: return (0);
909: }
910:
911: int
912: dcamctl(sc, bits, how)
913: struct dca_softc *sc;
914: int bits, how;
915: {
916: struct dcadevice *dca = sc->sc_dca;
917: int s;
918:
919: /*
920: * Always make sure MCR_IEN is set (unless setting to 0)
921: */
922: #ifdef KGDB
923: if (how == DMSET && kgdb_dev == makedev(dcamajor, sc->sc_hd->hp_unit))
924: bits |= MCR_IEN;
925: else
926: #endif
927: if (how == DMBIS || (how == DMSET && bits))
928: bits |= MCR_IEN;
929: else if (how == DMBIC)
930: bits &= ~MCR_IEN;
931: s = spltty();
932:
933: switch (how) {
934: case DMSET:
935: dca->dca_mcr = bits;
936: break;
937:
938: case DMBIS:
939: dca->dca_mcr |= bits;
940: break;
941:
942: case DMBIC:
943: dca->dca_mcr &= ~bits;
944: break;
945:
946: case DMGET:
947: bits = dca->dca_msr;
948: break;
949: }
950: splx(s);
951: return (bits);
952: }
953:
954: void
955: dcainit(dca, rate)
956: struct dcadevice *dca;
957: int rate;
958: {
959: int s;
960: short stat;
961:
962: s = splhigh();
963:
964: dca->dca_reset = 0xFF;
965: DELAY(100);
966: dca->dca_ic = IC_IE;
967:
968: dca->dca_cfcr = CFCR_DLAB;
969: rate = ttspeedtab(rate, dcaspeedtab);
970: dca->dca_data = rate & 0xFF;
971: dca->dca_ier = rate >> 8;
972: dca->dca_cfcr = CFCR_8BITS;
973: dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
974: dca->dca_fifo =
975: FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1;
976: dca->dca_mcr = MCR_DTR | MCR_RTS;
977: DELAY(100);
978: stat = dca->dca_iir;
979: splx(s);
980: }
981:
982: /*
983: * Following are all routines needed for DCA to act as console
984: */
985:
986: int
987: dca_console_scan(scode, va, arg)
988: int scode;
989: caddr_t va;
990: void *arg;
991: {
992: struct dcadevice *dca = (struct dcadevice *)va;
993: struct consdev *cp = arg;
994: u_int pri;
995:
996: switch (dca->dca_id) {
997: case DCAID0:
998: case DCAID1:
999: pri = CN_NORMAL;
1000: break;
1001:
1002: case DCAID0 | DCACON:
1003: case DCAID1 | DCACON:
1004: pri = CN_REMOTE;
1005: break;
1006:
1007: default:
1008: return (0);
1009: }
1010:
1011: #ifdef CONSCODE
1012: /*
1013: * Raise our priority, if appropriate.
1014: */
1015: if (scode == CONSCODE)
1016: pri = CN_FORCED;
1017: #endif
1018:
1019: /* Only raise priority. */
1020: if (pri > cp->cn_pri)
1021: cp->cn_pri = pri;
1022:
1023: /*
1024: * If our priority is higher than the currently-remembered
1025: * console, stash our priority, for the benefit of dcacninit().
1026: */
1027: if (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri) {
1028: cn_tab = cp;
1029: conscode = scode;
1030: return (DIO_SIZE(scode, va));
1031: }
1032: return (0);
1033: }
1034:
1035: void
1036: dcacnprobe(cp)
1037: struct consdev *cp;
1038: {
1039:
1040: /* locate the major number */
1041: for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
1042: if (cdevsw[dcamajor].d_open == dcaopen)
1043: break;
1044:
1045: /* initialize required fields */
1046: cp->cn_dev = makedev(dcamajor, 0); /* XXX */
1047:
1048: console_scan(dca_console_scan, cp);
1049:
1050: #ifdef KGDB
1051: /* XXX this needs to be fixed. */
1052: if (major(kgdb_dev) == 1) /* XXX */
1053: kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
1054: #endif
1055: }
1056:
1057: /* ARGSUSED */
1058: void
1059: dcacninit(cp)
1060: struct consdev *cp;
1061: {
1062:
1063: /*
1064: * We are not interested by the second console pass.
1065: */
1066: if (consolepass != 0)
1067: return;
1068:
1069: dca_cn = (struct dcadevice *)conaddr;
1070: dcainit(dca_cn, dcadefaultrate);
1071: dcaconsinit = 1;
1072: }
1073:
1074: /* ARGSUSED */
1075: int
1076: dcacngetc(dev)
1077: dev_t dev;
1078: {
1079: u_char stat;
1080: int c, s;
1081:
1082: #ifdef lint
1083: stat = dev; if (stat) return (0);
1084: #endif
1085:
1086: s = splhigh();
1087: while (((stat = dca_cn->dca_lsr) & LSR_RXRDY) == 0)
1088: ;
1089: c = dca_cn->dca_data;
1090: stat = dca_cn->dca_iir;
1091: splx(s);
1092: return (c);
1093: }
1094:
1095: /*
1096: * Console kernel output character routine.
1097: */
1098: /* ARGSUSED */
1099: void
1100: dcacnputc(dev, c)
1101: dev_t dev;
1102: int c;
1103: {
1104: int timo;
1105: u_char stat;
1106: int s = splhigh();
1107:
1108: #ifdef lint
1109: stat = dev; if (stat) return;
1110: #endif
1111:
1112: if (dcaconsinit == 0) {
1113: dcainit(dca_cn, dcadefaultrate);
1114: dcaconsinit = 1;
1115: }
1116: /* wait for any pending transmission to finish */
1117: timo = 50000;
1118: while (((stat = dca_cn->dca_lsr) & LSR_TXRDY) == 0 && --timo)
1119: ;
1120: dca_cn->dca_data = c;
1121: /* wait for this transmission to complete */
1122: timo = 1500000;
1123: while (((stat = dca_cn->dca_lsr) & LSR_TXRDY) == 0 && --timo)
1124: ;
1125: /* clear any interrupts generated by this transmission */
1126: stat = dca_cn->dca_iir;
1127: splx(s);
1128: }
CVSweb