Annotation of sys/arch/hp300/dev/apci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: apci.c,v 1.29 2007/01/06 20:09:12 miod Exp $ */
2: /* $NetBSD: apci.c,v 1.9 2000/11/02 00:35:05 eeh Exp $ */
3:
4: /*-
5: * Copyright (c) 1996, 1997, 1999 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * Copyright (c) 1997 Michael Smith. All rights reserved.
42: * Copyright (c) 1982, 1986, 1990, 1993
43: * The Regents of the University of California. All rights reserved.
44: *
45: * Redistribution and use in source and binary forms, with or without
46: * modification, are permitted provided that the following conditions
47: * are met:
48: * 1. Redistributions of source code must retain the above copyright
49: * notice, this list of conditions and the following disclaimer.
50: * 2. Redistributions in binary form must reproduce the above copyright
51: * notice, this list of conditions and the following disclaimer in the
52: * documentation and/or other materials provided with the distribution.
53: * 3. Neither the name of the University nor the names of its contributors
54: * may be used to endorse or promote products derived from this software
55: * without specific prior written permission.
56: *
57: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67: * SUCH DAMAGE.
68: *
69: * @(#)dca.c 8.2 (Berkeley) 1/12/94
70: */
71:
72: /*
73: * Device driver for the APCI 8250-like UARTs found on the Apollo
74: * Utility Chip on HP 9000/400-series workstations.
75: *
76: * There are 4 APCI UARTs on the Frodo ASIC. The first one
77: * is used to communicate with the Domain keyboard. The second
78: * one is the serial console port when the firmware is in Domain/OS
79: * mode, and is mapped to select code 9 by the HP-UX firmware (except
80: * on 425e models).
81: *
82: * We don't bother attaching a tty to the first UART; it lacks modem/flow
83: * control, and is directly connected to the keyboard connector anyhow.
84: */
85:
86: /*
87: * XXX This driver is very similar to the dca driver, and much
88: * XXX more code could be shared. (Currently, no code is shared.)
89: * XXX FIXME!
90: */
91:
92: #include <sys/param.h>
93: #include <sys/systm.h>
94: #include <sys/ioctl.h>
95: #include <sys/proc.h>
96: #include <sys/tty.h>
97: #include <sys/conf.h>
98: #include <sys/file.h>
99: #include <sys/uio.h>
100: #include <sys/kernel.h>
101: #include <sys/syslog.h>
102: #include <sys/device.h>
103: #include <sys/timeout.h>
104:
105: #include <machine/autoconf.h>
106: #include <machine/bus.h>
107: #include <machine/cpu.h>
108: #include <machine/hp300spu.h>
109:
110: #include <dev/cons.h>
111:
112: #include <hp300/dev/dioreg.h> /* to check for dca at 9 */
113: #include <hp300/dev/diovar.h>
114: #include <hp300/dev/diodevs.h>
115:
116: #include <hp300/dev/frodoreg.h>
117: #include <hp300/dev/frodovar.h>
118: #include <hp300/dev/apcireg.h>
119: #include <hp300/dev/apcivar.h>
120: #include <hp300/dev/dcareg.h> /* register bit definitions */
121:
122: #ifdef DDB
123: #include <ddb/db_var.h>
124: #endif
125:
126: struct apci_softc {
127: struct device sc_dev; /* generic device glue */
128: struct isr sc_isr;
129: struct apciregs *sc_apci; /* device registers */
130: struct tty *sc_tty; /* tty glue */
131: struct timeout sc_timeout; /* timeout */
132: int sc_ferr,
133: sc_perr,
134: sc_oflow,
135: sc_toterr; /* stats */
136: int sc_flags;
137: u_char sc_cua; /* callout mode */
138: };
139:
140: /* sc_flags */
141: #define APCI_HASFIFO 0x01 /* unit has a fifo */
142: #define APCI_ISCONSOLE 0x02 /* unit is console */
143: #define APCI_SOFTCAR 0x04 /* soft carrier */
144:
145: int apcimatch(struct device *, void *, void *);
146: void apciattach(struct device *, struct device *, void *);
147:
148: struct cfattach apci_ca = {
149: sizeof(struct apci_softc), apcimatch, apciattach
150: };
151:
152: struct cfdriver apci_cd = {
153: NULL, "apci", DV_TTY
154: };
155:
156: int apciintr(void *);
157: void apcieint(struct apci_softc *, int);
158: void apcimint(struct apci_softc *, u_char);
159: int apciparam(struct tty *, struct termios *);
160: void apcistart(struct tty *);
161: int apcimctl(struct apci_softc *, int, int);
162: void apcitimeout(void *);
163:
164: cdev_decl(apci);
165:
166: #define APCIUNIT(x) (minor(x) & 0x7f)
167: #define APCICUA(x) (minor(x) & 0x80)
168:
169: int apcidefaultrate = TTYDEF_SPEED;
170:
171: /*
172: * Console support.
173: */
174: struct apciregs *apci_cn = NULL; /* console hardware */
175: int apciconsinit; /* has been initialized */
176: int apcimajor; /* our major number */
177:
178: cons_decl(apci);
179:
180: int
181: apcimatch(parent, match, aux)
182: struct device *parent;
183: void *match, *aux;
184: {
185: struct frodo_attach_args *fa = aux;
186:
187: /* Looking for an apci? */
188: if (strcmp(fa->fa_name, apci_cd.cd_name) != 0)
189: return (0);
190:
191: /* Are we checking a valid APCI offset? */
192: switch (fa->fa_offset) {
193: case FRODO_APCI_OFFSET(1):
194: case FRODO_APCI_OFFSET(2):
195: case FRODO_APCI_OFFSET(3):
196: /* Yup, we exist! */
197: return (1);
198: }
199:
200: return (0);
201: }
202:
203: void
204: apciattach(parent, self, aux)
205: struct device *parent, *self;
206: void *aux;
207: {
208: struct apci_softc *sc = (struct apci_softc *)self;
209: struct apciregs *apci;
210: struct frodo_attach_args *fa = aux;
211:
212: sc->sc_apci = apci =
213: (struct apciregs *)IIOV(FRODO_BASE + fa->fa_offset);
214: sc->sc_flags = 0;
215:
216: /* Initialize timeout structure */
217: timeout_set(&sc->sc_timeout, apcitimeout, sc);
218:
219: /* Are we the console? */
220: if (apci == apci_cn) {
221: sc->sc_flags |= APCI_ISCONSOLE;
222: delay(100000);
223:
224: /*
225: * We didn't know which unit this would be during
226: * the console probe, so we have to fixup cn_dev here.
227: */
228: cn_tab->cn_dev = makedev(apcimajor, self->dv_unit);
229: }
230:
231: /* Look for a FIFO. */
232: apci->ap_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
233: delay(100);
234: if ((apci->ap_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
235: sc->sc_flags |= APCI_HASFIFO;
236:
237: /* Establish our interrupt handler. */
238: sc->sc_isr.isr_func = apciintr;
239: sc->sc_isr.isr_arg = sc;
240: sc->sc_isr.isr_priority =
241: (sc->sc_flags & APCI_HASFIFO) ? IPL_TTY : IPL_TTYNOBUF;
242: frodo_intr_establish(parent, fa->fa_line, &sc->sc_isr, self->dv_xname);
243:
244: /* Set soft carrier if requested by operator. */
245: if (self->dv_cfdata->cf_flags)
246: sc->sc_flags |= APCI_SOFTCAR;
247:
248: /*
249: * Need to reset baud rate, etc. of next print, so reset apciconsinit.
250: * Also make sure console is always "hardwired".
251: */
252: if (sc->sc_flags & APCI_ISCONSOLE) {
253: apciconsinit = 0;
254: sc->sc_flags |= APCI_SOFTCAR;
255: printf(": console, ");
256: } else
257: printf(": ");
258:
259: if (sc->sc_flags & APCI_HASFIFO)
260: printf("working fifo\n");
261: else
262: printf("no fifo\n");
263: }
264:
265: /* ARGSUSED */
266: int
267: apciopen(dev, flag, mode, p)
268: dev_t dev;
269: int flag, mode;
270: struct proc *p;
271: {
272: int unit = APCIUNIT(dev);
273: struct apci_softc *sc;
274: struct tty *tp;
275: struct apciregs *apci;
276: u_char code;
277: int s, error = 0;
278:
279: if (unit >= apci_cd.cd_ndevs ||
280: (sc = apci_cd.cd_devs[unit]) == NULL)
281: return (ENXIO);
282:
283: apci = sc->sc_apci;
284:
285: s = spltty();
286: if (sc->sc_tty == NULL) {
287: tp = sc->sc_tty = ttymalloc();
288: } else
289: tp = sc->sc_tty;
290: splx(s);
291:
292: tp->t_oproc = apcistart;
293: tp->t_param = apciparam;
294: tp->t_dev = dev;
295:
296: if ((tp->t_state & TS_ISOPEN) == 0) {
297: /*
298: * Sanity clause: reset the chip on first open.
299: * The chip might be left in an inconsistent state
300: * if it is read inadventently.
301: */
302: apciinit(apci, apcidefaultrate, CFCR_8BITS);
303:
304: tp->t_state |= TS_WOPEN;
305: ttychars(tp);
306: tp->t_iflag = TTYDEF_IFLAG;
307: tp->t_oflag = TTYDEF_OFLAG;
308: tp->t_cflag = TTYDEF_CFLAG;
309: tp->t_lflag = TTYDEF_LFLAG;
310: tp->t_ispeed = tp->t_ospeed = apcidefaultrate;
311:
312: s = spltty();
313:
314: apciparam(tp, &tp->t_termios);
315: ttsetwater(tp);
316:
317: /* Set the FIFO threshold based on the receive speed. */
318: if (sc->sc_flags & APCI_HASFIFO)
319: apci->ap_fifo = FIFO_ENABLE | FIFO_RCV_RST |
320: FIFO_XMT_RST |
321: (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 :
322: FIFO_TRIGGER_14);
323:
324: /* Flush any pending I/O. */
325: while ((apci->ap_iir & IIR_IMASK) == IIR_RXRDY)
326: code = apci->ap_data;
327: } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
328: return (EBUSY);
329: else
330: s = spltty();
331:
332: /* Set the modem control state. */
333: (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMSET);
334:
335: /* Set soft-carrier if so configured. */
336: if ((sc->sc_flags & APCI_SOFTCAR) || APCICUA(dev) ||
337: (apcimctl(sc, 0, DMGET) & MSR_DCD))
338: tp->t_state |= TS_CARR_ON;
339:
340: if (APCICUA(dev)) {
341: if (tp->t_state & TS_ISOPEN) {
342: /* Ah, but someone already is dialed in... */
343: splx(s);
344: return (EBUSY);
345: }
346: sc->sc_cua = 1; /* We go into CUA mode */
347: }
348:
349: /* Wait for carrier if necessary. */
350: if (flag & O_NONBLOCK) {
351: if (!APCICUA(dev) && sc->sc_cua) {
352: /* Opening TTY non-blocking... but the CUA is busy */
353: splx(s);
354: return (EBUSY);
355: }
356: } else {
357: while (sc->sc_cua ||
358: ((tp->t_cflag & CLOCAL) == 0 &&
359: (tp->t_state & TS_CARR_ON) == 0)) {
360: tp->t_state |= TS_WOPEN;
361: error = ttysleep(tp, (caddr_t)&tp->t_rawq,
362: TTIPRI | PCATCH, ttopen, 0);
363: if (!APCICUA(dev) && sc->sc_cua && error == EINTR)
364: continue;
365: if (error) {
366: if (APCICUA(dev))
367: sc->sc_cua = 0;
368: splx(s);
369: return (error);
370: }
371: if (!APCICUA(dev) && sc->sc_cua)
372: continue;
373: }
374: }
375:
376: splx(s);
377:
378: if (error == 0)
379: error = (*linesw[tp->t_line].l_open)(dev, tp);
380:
381: if (error == 0) {
382: /* clear errors, start timeout */
383: sc->sc_ferr = sc->sc_perr = sc->sc_oflow = sc->sc_toterr = 0;
384: timeout_add(&sc->sc_timeout, hz);
385: }
386:
387: return (error);
388: }
389:
390: /* ARGSUSED */
391: int
392: apciclose(dev, flag, mode, p)
393: dev_t dev;
394: int flag, mode;
395: struct proc *p;
396: {
397: struct apci_softc *sc;
398: struct tty *tp;
399: struct apciregs *apci;
400: int unit = APCIUNIT(dev);
401: int s;
402:
403: sc = apci_cd.cd_devs[unit];
404: apci = sc->sc_apci;
405: tp = sc->sc_tty;
406:
407: (*linesw[tp->t_line].l_close)(tp, flag);
408:
409: s = spltty();
410:
411: apci->ap_cfcr &= ~CFCR_SBREAK;
412: apci->ap_ier = 0;
413: if (tp->t_cflag & HUPCL && (sc->sc_flags & APCI_SOFTCAR) == 0) {
414: /* XXX perhaps only clear DTR */
415: (void) apcimctl(sc, 0, DMSET);
416: }
417: tp->t_state &= ~(TS_BUSY | TS_FLUSH);
418: sc->sc_cua = 0;
419: splx(s);
420: ttyclose(tp);
421: #if 0
422: ttyfree(tp);
423: sc->sc_tty = NULL;
424: #endif
425: return (0);
426: }
427:
428: int
429: apciread(dev, uio, flag)
430: dev_t dev;
431: struct uio *uio;
432: int flag;
433: {
434: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
435: struct tty *tp = sc->sc_tty;
436:
437: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
438: }
439:
440: int
441: apciwrite(dev, uio, flag)
442: dev_t dev;
443: struct uio *uio;
444: int flag;
445: {
446: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
447: struct tty *tp = sc->sc_tty;
448:
449: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
450: }
451:
452: struct tty *
453: apcitty(dev)
454: dev_t dev;
455: {
456: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
457:
458: return (sc->sc_tty);
459: }
460:
461: int
462: apciintr(arg)
463: void *arg;
464: {
465: struct apci_softc *sc = arg;
466: struct apciregs *apci = sc->sc_apci;
467: struct tty *tp = sc->sc_tty;
468: u_char iir, lsr, c;
469: int iflowdone = 0, claimed = 0;
470:
471: #define RCVBYTE() \
472: c = apci->ap_data; \
473: if (tp != NULL && (tp->t_state & TS_ISOPEN) != 0) \
474: (*linesw[tp->t_line].l_rint)(c, tp)
475:
476: for (;;) {
477: iir = apci->ap_iir; /* get UART status */
478:
479: switch (iir & IIR_IMASK) {
480: case IIR_RLS:
481: apcieint(sc, apci->ap_lsr);
482: break;
483:
484: case IIR_RXRDY:
485: case IIR_RXTOUT:
486: RCVBYTE();
487: if (sc->sc_flags & APCI_HASFIFO) {
488: while ((lsr = apci->ap_lsr) & LSR_RCV_MASK) {
489: if (lsr == LSR_RXRDY) {
490: RCVBYTE();
491: } else
492: apcieint(sc, lsr);
493: }
494: }
495: if (iflowdone == 0 && tp != NULL &&
496: (tp->t_cflag & CRTS_IFLOW) &&
497: tp->t_rawq.c_cc > (TTYHOG / 2)) {
498: apci->ap_mcr &= ~MCR_RTS;
499: iflowdone = 1;
500: }
501: break;
502:
503: case IIR_TXRDY:
504: if (tp != NULL) {
505: tp->t_state &=~ (TS_BUSY|TS_FLUSH);
506: if (tp->t_line)
507: (*linesw[tp->t_line].l_start)(tp);
508: else
509: apcistart(tp);
510: }
511: break;
512:
513: default:
514: if (iir & IIR_NOPEND)
515: return (claimed);
516: log(LOG_WARNING, "%s: weird interrupt: 0x%x\n",
517: sc->sc_dev.dv_xname, iir);
518: /* FALLTHROUGH */
519:
520: case IIR_MLSC:
521: apcimint(sc, apci->ap_msr);
522: break;
523: }
524:
525: claimed = 1;
526: }
527: }
528:
529: void
530: apcieint(sc, stat)
531: struct apci_softc *sc;
532: int stat;
533: {
534: struct tty *tp = sc->sc_tty;
535: struct apciregs *apci = sc->sc_apci;
536: int c;
537:
538: c = apci->ap_data;
539:
540: #ifdef DDB
541: if ((sc->sc_flags & APCI_ISCONSOLE) && db_console && (stat & LSR_BI)) {
542: Debugger();
543: return;
544: }
545: #endif
546:
547: if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
548: return;
549:
550: if (stat & (LSR_BI | LSR_FE)) {
551: c |= TTY_FE;
552: sc->sc_ferr++;
553: } else if (stat & LSR_PE) {
554: c |= TTY_PE;
555: sc->sc_perr++;
556: } else if (stat & LSR_OE)
557: sc->sc_oflow++;
558: (*linesw[tp->t_line].l_rint)(c, tp);
559: }
560:
561: void
562: apcimint(sc, stat)
563: struct apci_softc *sc;
564: u_char stat;
565: {
566: struct tty *tp = sc->sc_tty;
567: struct apciregs *apci = sc->sc_apci;
568:
569: if (tp == NULL)
570: return;
571:
572: if ((stat & MSR_DDCD) &&
573: (sc->sc_flags & APCI_SOFTCAR) == 0) {
574: if (stat & MSR_DCD)
575: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
576: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
577: apci->ap_mcr &= ~(MCR_DTR | MCR_RTS);
578: }
579:
580: /*
581: * CTS change.
582: * If doing HW output flow control, start/stop output as appropriate.
583: */
584: if ((stat & MSR_DCTS) &&
585: (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
586: if (stat & MSR_CTS) {
587: tp->t_state &=~ TS_TTSTOP;
588: apcistart(tp);
589: } else
590: tp->t_state |= TS_TTSTOP;
591: }
592: }
593:
594: int
595: apciioctl(dev, cmd, data, flag, p)
596: dev_t dev;
597: u_long cmd;
598: caddr_t data;
599: int flag;
600: struct proc *p;
601: {
602: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(dev)];
603: struct tty *tp = sc->sc_tty;
604: struct apciregs *apci = sc->sc_apci;
605: int error;
606:
607: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
608: if (error >= 0)
609: return (error);
610: error = ttioctl(tp, cmd, data, flag, p);
611: if (error >= 0)
612: return (error);
613:
614: switch (cmd) {
615: case TIOCSBRK:
616: apci->ap_cfcr |= CFCR_SBREAK;
617: break;
618:
619: case TIOCCBRK:
620: apci->ap_cfcr &= ~CFCR_SBREAK;
621: break;
622:
623: case TIOCSDTR:
624: (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMBIS);
625: break;
626:
627: case TIOCCDTR:
628: (void) apcimctl(sc, MCR_DTR | MCR_RTS, DMBIC);
629: break;
630:
631: case TIOCMSET:
632: (void) apcimctl(sc, *(int *)data, DMSET);
633: break;
634:
635: case TIOCMBIS:
636: (void) apcimctl(sc, *(int *)data, DMBIS);
637: break;
638:
639: case TIOCMBIC:
640: (void) apcimctl(sc, *(int *)data, DMBIC);
641: break;
642:
643: case TIOCMGET:
644: *(int *)data = apcimctl(sc, 0, DMGET);
645: break;
646:
647: case TIOCGFLAGS: {
648: int bits = 0;
649:
650: if (sc->sc_flags & APCI_SOFTCAR)
651: bits |= TIOCFLAG_SOFTCAR;
652:
653: if (tp->t_cflag & CLOCAL)
654: bits |= TIOCFLAG_CLOCAL;
655:
656: *(int *)data = bits;
657: break;
658: }
659:
660: case TIOCSFLAGS: {
661: int userbits;
662:
663: error = suser(p, 0);
664: if (error)
665: return (EPERM);
666:
667: userbits = *(int *)data;
668:
669: if ((userbits & TIOCFLAG_SOFTCAR) ||
670: (sc->sc_flags & APCI_ISCONSOLE))
671: sc->sc_flags |= APCI_SOFTCAR;
672:
673: if (userbits & TIOCFLAG_CLOCAL)
674: tp->t_cflag |= CLOCAL;
675:
676: break;
677: }
678:
679: default:
680: return (ENOTTY);
681: }
682: return (0);
683: }
684:
685: int
686: apciparam(tp, t)
687: struct tty *tp;
688: struct termios *t;
689: {
690: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(tp->t_dev)];
691: struct apciregs *apci = sc->sc_apci;
692: int cfcr, cflag = t->c_cflag;
693: int ospeed = ttspeedtab(t->c_ospeed, apcispeedtab);
694: int s;
695:
696: /* check requested parameters */
697: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
698: return (EINVAL);
699:
700: switch (cflag & CSIZE) {
701: case CS5:
702: cfcr = CFCR_5BITS;
703: break;
704:
705: case CS6:
706: cfcr = CFCR_6BITS;
707: break;
708:
709: case CS7:
710: cfcr = CFCR_7BITS;
711: break;
712:
713: case CS8:
714: default: /* XXX gcc whines about cfcr being uninitialized... */
715: cfcr = CFCR_8BITS;
716: break;
717: }
718: if (cflag & PARENB) {
719: cfcr |= CFCR_PENAB;
720: if ((cflag & PARODD) == 0)
721: cfcr |= CFCR_PEVEN;
722: }
723: if (cflag & CSTOPB)
724: cfcr |= CFCR_STOPB;
725:
726: s = spltty();
727:
728: if (ospeed == 0)
729: (void) apcimctl(sc, 0, DMSET); /* hang up line */
730:
731: /*
732: * Set the FIFO threshold based on the receive speed, if we
733: * are changing it.
734: */
735: if (tp->t_ispeed != t->c_ispeed) {
736: if (sc->sc_flags & APCI_HASFIFO)
737: apci->ap_fifo = FIFO_ENABLE |
738: (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 :
739: FIFO_TRIGGER_14);
740: }
741:
742: if (ospeed != 0) {
743: apci->ap_cfcr |= CFCR_DLAB;
744: apci->ap_data = ospeed & 0xff;
745: apci->ap_ier = (ospeed >> 8) & 0xff;
746: apci->ap_cfcr = cfcr;
747: } else
748: apci->ap_cfcr = cfcr;
749:
750: /* and copy to tty */
751: tp->t_ispeed = t->c_ispeed;
752: tp->t_ospeed = t->c_ospeed;
753: tp->t_cflag = cflag;
754:
755: apci->ap_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
756:
757: splx(s);
758: return (0);
759: }
760:
761: void
762: apcistart(tp)
763: struct tty *tp;
764: {
765: struct apci_softc *sc = apci_cd.cd_devs[APCIUNIT(tp->t_dev)];
766: struct apciregs *apci = sc->sc_apci;
767: int s, c;
768:
769: s = spltty();
770:
771: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
772: goto out;
773: if (tp->t_outq.c_cc <= tp->t_lowat) {
774: if (tp->t_state & TS_ASLEEP) {
775: tp->t_state &= ~TS_ASLEEP;
776: wakeup((caddr_t)&tp->t_outq);
777: }
778: if (tp->t_outq.c_cc == 0)
779: goto out;
780: selwakeup(&tp->t_wsel);
781: }
782: if (apci->ap_lsr & LSR_TXRDY) {
783: tp->t_state |= TS_BUSY;
784: if (sc->sc_flags & APCI_HASFIFO) {
785: for (c = 0; c < 16 && tp->t_outq.c_cc; ++c)
786: apci->ap_data = getc(&tp->t_outq);
787: } else
788: apci->ap_data = getc(&tp->t_outq);
789: }
790:
791: out:
792: splx(s);
793: }
794:
795: /*
796: * Stop output on a line.
797: */
798: /* ARGSUSED */
799: int
800: apcistop(tp, flag)
801: struct tty *tp;
802: int flag;
803: {
804: int s;
805:
806: s = spltty();
807: if (tp->t_state & TS_BUSY)
808: if ((tp->t_state & TS_TTSTOP) == 0)
809: tp->t_state |= TS_FLUSH;
810: splx(s);
811: return (0);
812: }
813:
814: int
815: apcimctl(sc, bits, how)
816: struct apci_softc *sc;
817: int bits, how;
818: {
819: struct apciregs *apci = sc->sc_apci;
820: int s;
821:
822: s = spltty();
823:
824: switch (how) {
825: case DMSET:
826: apci->ap_mcr = bits;
827: break;
828:
829: case DMBIS:
830: apci->ap_mcr |= bits;
831: break;
832:
833: case DMBIC:
834: apci->ap_mcr &= ~bits;
835: break;
836:
837: case DMGET:
838: bits = apci->ap_msr;
839: break;
840: }
841:
842: splx(s);
843: return (bits);
844: }
845:
846: void
847: apcitimeout(arg)
848: void *arg;
849: {
850: struct apci_softc *sc = arg;
851: int ferr, perr, oflow, s;
852:
853: if (sc->sc_tty == NULL ||
854: (sc->sc_tty->t_state & TS_ISOPEN) == 0)
855: return;
856:
857: /* Log any errors. */
858: if (sc->sc_ferr || sc->sc_perr || sc->sc_oflow) {
859: s = spltty(); /* XXX necessary? */
860: ferr = sc->sc_ferr;
861: perr = sc->sc_perr;
862: oflow = sc->sc_oflow;
863: sc->sc_ferr = sc->sc_perr = sc->sc_oflow = 0;
864: splx(s);
865: sc->sc_toterr += ferr + perr + oflow;
866: log(LOG_WARNING,
867: "%s: %d frame, %d parity, %d overflow, %d total errors\n",
868: sc->sc_dev.dv_xname, ferr, perr, oflow, sc->sc_toterr);
869: }
870:
871: timeout_add(&sc->sc_timeout, hz);
872: }
873:
874: /*
875: * The following routines are required for the APCI to act as the console.
876: */
877:
878: void
879: apcicnprobe(cp)
880: struct consdev *cp;
881: {
882: volatile u_int8_t *frodoregs;
883:
884: /* locate the major number */
885: for (apcimajor = 0; apcimajor < nchrdev; apcimajor++)
886: if (cdevsw[apcimajor].d_open == apciopen)
887: break;
888:
889: /* initialize the required fields */
890: cp->cn_dev = makedev(apcimajor, 0); /* XXX */
891:
892: /*
893: * The APCI can only be a console on a 425e; on other 4xx
894: * models, the "first" serial port is mapped to the DCA
895: * at select code 9. See frodo.c for the autoconfiguration
896: * version of this check.
897: */
898: if (machineid != HP_425 || mmuid != MMUID_425_E)
899: return;
900:
901: /*
902: * Check the service switch. On the 425e, this is a physical
903: * switch, unlike other frodo-based machines, so we can use it
904: * as a serial vs internal video selector, since the PROM can not
905: * be configured for serial console.
906: */
907: frodoregs = (volatile u_int8_t *)IIOV(FRODO_BASE);
908: if (badaddr((caddr_t)frodoregs) == 0 &&
909: !ISSET(frodoregs[FRODO_IISR], FRODO_IISR_SERVICE))
910: cp->cn_pri = CN_REMOTE;
911: else
912: cp->cn_pri = CN_NORMAL;
913:
914: /*
915: * If our priority is higher than the currently-remembered
916: * console, install ourselves.
917: */
918: if (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri) {
919: cn_tab = cp;
920: conscode = CONSCODE_INVALID;
921: }
922: }
923:
924: /* ARGSUSED */
925: void
926: apcicninit(cp)
927: struct consdev *cp;
928: {
929:
930: /*
931: * We are not interested by the second console pass.
932: */
933: if (consolepass != 0)
934: return;
935:
936: apci_cn = (struct apciregs *)IIOV(FRODO_BASE + FRODO_APCI_OFFSET(1));
937: apciinit(apci_cn, apcidefaultrate, CFCR_8BITS);
938: apciconsinit = 1;
939: }
940:
941: /* ARGSUSED */
942: int
943: apcicngetc(dev)
944: dev_t dev;
945: {
946: u_char stat;
947: int c, s;
948:
949: s = splhigh();
950: while (((stat = apci_cn->ap_lsr) & LSR_RXRDY) == 0)
951: ;
952: c = apci_cn->ap_data;
953:
954: /* clear any interrupts generated by this transmission */
955: stat = apci_cn->ap_iir;
956: splx(s);
957: return (c);
958: }
959:
960: /* ARGSUSED */
961: void
962: apcicnputc(dev, c)
963: dev_t dev;
964: int c;
965: {
966: int timo;
967: u_char stat;
968: int s;
969:
970: s = splhigh();
971:
972: if (apciconsinit == 0) {
973: apciinit(apci_cn, apcidefaultrate, CFCR_8BITS);
974: apciconsinit = 1;
975: }
976:
977: /* wait for any pending transmission to finish */
978: timo = 50000;
979: while (((stat = apci_cn->ap_lsr) & LSR_TXRDY) == 0 && --timo)
980: ;
981:
982: apci_cn->ap_data = c & 0xff;
983:
984: /* wait for this transmission to complete */
985: timo = 1500000;
986: while (((stat = apci_cn->ap_lsr) & LSR_TXRDY) == 0 && --timo)
987: ;
988:
989: /* clear any interrupts generated by this transmission */
990: stat = apci_cn->ap_iir;
991: splx(s);
992: }
CVSweb