Annotation of sys/arch/vax/vxt/qsc.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: qsc.c,v 1.1 2006/08/27 16:55:41 miod Exp $ */
2: /*
3: * Copyright (c) 2006 Miodrag Vallat.
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice, this permission notice, and the disclaimer below
8: * appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: /*
19: * Mach Operating System
20: * Copyright (c) 1993-1991 Carnegie Mellon University
21: * All Rights Reserved.
22: *
23: * Permission to use, copy, modify and distribute this software and its
24: * documentation is hereby granted, provided that both the copyright
25: * notice and this permission notice appear in all copies of the
26: * software, derivative works or modified versions, and any portions
27: * thereof, and that both notices appear in supporting documentation.
28: *
29: * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
30: * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
31: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
32: *
33: * Carnegie Mellon requests users of this software to return to
34: *
35: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
36: * School of Computer Science
37: * Carnegie Mellon University
38: * Pittsburgh PA 15213-3890
39: *
40: * any improvements or extensions that they make and grant Carnegie the
41: * rights to redistribute these changes.
42: */
43:
44: #include <sys/param.h>
45: #include <sys/ioctl.h>
46: #include <sys/proc.h>
47: #include <sys/tty.h>
48: #include <sys/systm.h>
49: #include <sys/device.h>
50: #include <sys/syslog.h>
51: #include <sys/conf.h>
52:
53: #include <machine/bus.h>
54: #include <machine/nexus.h>
55: #include <machine/sid.h>
56:
57: #include <dev/cons.h>
58:
59: #include <vax/vxt/vxtbusvar.h>
60:
61: #include <vax/vxt/qscreg.h>
62: #include <vax/vxt/qscvar.h>
63:
64: #ifdef DDB
65: #include <machine/cpu.h>
66: #include <ddb/db_var.h>
67: #endif
68:
69: #include "qsckbd.h"
70: #include "qscms.h"
71:
72: struct cfdriver qsc_cd = {
73: NULL, "qsc", DV_TTY
74: };
75:
76: /* console storage */
77: struct qsc_sv_reg qsccn_sv;
78:
79: /* prototypes */
80: cdev_decl(qsc);
81: cons_decl(qsc);
82: int qscintr(void *);
83: int qscparam(struct tty *, struct termios *);
84: void qscrint(struct qscsoftc *, u_int);
85: int qscspeed(int);
86: void qscstart(struct tty *);
87: struct tty *qsctty(dev_t);
88: void qscxint(struct qscsoftc *, u_int);
89:
90: /*
91: * Registers are mapped as the least-significant byte of 32-bit
92: * addresses. The following macros hide this.
93: */
94:
95: #define qsc_readp(sc, reg) \
96: bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, 4 * (reg))
97: #define qsc_read(sc, line, reg) \
98: bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, \
99: (sc)->sc_regaddr[line][reg])
100: #define qsc_writep(sc, reg, val) \
101: bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, 4 * (reg), (val))
102: #define qsc_write(sc, line, reg, val) \
103: bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, \
104: (sc)->sc_regaddr[line][reg], (val))
105:
106: #define SC_LINE(dev) (minor(dev))
107:
108: /*
109: * Attachment glue.
110: */
111:
112: int qsc_match(struct device *parent, void *self, void *aux);
113: void qsc_attach(struct device *parent, struct device *self, void *aux);
114: int qsc_print(void *, const char *);
115:
116: struct cfattach qsc_ca = {
117: sizeof(struct qscsoftc), qsc_match, qsc_attach
118: };
119:
120: int
121: qsc_match(struct device *parent, void *cf, void *aux)
122: {
123: struct bp_conf *bp = aux;
124:
125: if (strcmp(bp->type, qsc_cd.cd_name) == 0)
126: return (1);
127: return (0);
128: }
129:
130: void
131: qsc_attach(struct device *parent, struct device *self, void *aux)
132: {
133: extern struct vax_bus_space vax_mem_bus_space;
134: struct qscsoftc *sc = (struct qscsoftc *)self;
135: bus_space_handle_t ioh;
136: u_int line, pair, reg;
137: #if NQSCKBD > 0 || NQSCMS > 0
138: struct qsc_attach_args qa;
139: #endif
140:
141: sc->sc_iot = &vax_mem_bus_space;
142: if (bus_space_map(sc->sc_iot, QSCADDR, VAX_NBPG, 0, &ioh) != 0) {
143: printf(": can't map registers!\n");
144: return;
145: }
146: sc->sc_ioh = ioh;
147:
148: if (cn_tab->cn_putc == qsccnputc) {
149: sc->sc_console = 1;
150: printf(": console");
151: }
152:
153: /*
154: * Initialize line-specific data (register addresses)
155: */
156:
157: for (line = 0; line < SC_NLINES; line++) {
158: sc->sc_regaddr[line][SC_MR] = line * 8 + SC_MRA;
159: sc->sc_regaddr[line][SC_CSR] = line * 8 + SC_CSRA;
160: sc->sc_regaddr[line][SC_CR] = line * 8 + SC_CRA;
161: sc->sc_regaddr[line][SC_TXFIFO] = line * 8 + SC_TXFIFOA;
162:
163: sc->sc_regaddr[line][SC_IOPCR] = (line < 2 ? 0 : 0x10) +
164: (line & 1) + SC_IOPCRA;
165:
166: sc->sc_regaddr[line][SC_ACR] = (line < 2 ? 0 : 0x10) + SC_ACRAB;
167: sc->sc_regaddr[line][SC_IMR] = (line < 2 ? 0 : 0x10) + SC_IMRAB;
168: sc->sc_regaddr[line][SC_OPR] = (line < 2 ? 0 : 0x10) + SC_OPRAB;
169: }
170: for (line = 0; line < SC_NLINES; line++)
171: for (reg = 0; reg < SC_LOGICAL; reg++)
172: sc->sc_regaddr[line][reg] =
173: 0 + 4 * sc->sc_regaddr[line][reg];
174:
175: /*
176: * Initialize all lines.
177: */
178: sc->sc_sv_reg = sc->sc_console ? &qsccn_sv : &sc->sc_sv_reg_storage;
179: for (line = 0; line < SC_NLINES; line++) {
180: /* do not reinitialize the console line... */
181: if (sc->sc_console && line == QSC_LINE_SERIAL)
182: continue;
183:
184: sc->sc_sv_reg->sv_mr1[line] =
185: (line == 3 ? ODDPAR | PAREN : PARDIS) | RXRTS | CL8;
186: sc->sc_sv_reg->sv_mr2[line] = /* TXCTS | */ SB1;
187: sc->sc_sv_reg->sv_csr[line] = line < 2 ? BD9600 : BD4800;
188: sc->sc_sv_reg->sv_cr[line] = TXEN | RXEN;
189:
190: pair = line >> 1;
191:
192: if (sc->sc_console && pair == (QSC_LINE_SERIAL >> 1))
193: continue;
194:
195: /* Start out with Tx and RX interrupts disabled */
196: sc->sc_sv_reg->sv_imr[pair] = 0;
197: }
198:
199: for (line = 0; line < SC_NLINES; line++) {
200: /* do not reset the console line... */
201: if (sc->sc_console && line == QSC_LINE_SERIAL)
202: continue;
203:
204: qsc_write(sc, line, SC_CR, RXRESET | TXDIS | RXDIS);
205: DELAY(1);
206: qsc_write(sc, line, SC_CR, TXRESET | TXDIS | RXDIS);
207: DELAY(1);
208: qsc_write(sc, line, SC_CR, ERRRESET | TXDIS | RXDIS);
209: DELAY(1);
210: qsc_write(sc, line, SC_CR, BRKINTRESET | TXDIS | RXDIS);
211: DELAY(1);
212: qsc_write(sc, line, SC_CR, MRZERO | TXDIS | RXDIS);
213: DELAY(1);
214:
215: qsc_write(sc, line, SC_MR, 0);
216: qsc_write(sc, line, SC_MR, sc->sc_sv_reg->sv_mr1[line]);
217: qsc_write(sc, line, SC_MR, sc->sc_sv_reg->sv_mr2[line]);
218: qsc_write(sc, line, SC_CSR, sc->sc_sv_reg->sv_csr[line]);
219: qsc_write(sc, line, SC_CR, sc->sc_sv_reg->sv_cr[line]);
220: DELAY(1);
221: }
222:
223: for (pair = 0; pair < SC_NLINES / 2; pair++)
224: qsc_write(sc, pair << 1, SC_IMR,
225: sc->sc_sv_reg->sv_imr[pair]);
226:
227: for (line = 0; line < SC_NLINES; line++) {
228: sc->sc_tty[line] = NULL;
229: sc->sc_swflags[line] = 0;
230: }
231: if (sc->sc_console)
232: sc->sc_swflags[QSC_LINE_SERIAL] |= TIOCFLAG_SOFTCAR;
233:
234: printf("\n");
235:
236: /*
237: * Configure interrupts. We are bidding in 2681 mode for now.
238: */
239:
240: qsc_writep(sc, SC_ICR, 0x00);
241: for (line = SC_BIDCRA; line <= SC_BIDCRD; line++)
242: qsc_writep(sc, line, 0x00);
243: qsc_writep(sc, SC_IVR, VXT_INTRVEC >> 2);
244:
245: vxtbus_intr_establish(self->dv_xname, IPL_TTY, qscintr, sc);
246:
247: /*
248: * Attach subdevices, and enable RX and TX interrupts on their lines
249: * if successful.
250: */
251: #if NQSCKBD > 0
252: /* keyboard */
253: qa.qa_line = QSC_LINE_KEYBOARD;
254: qa.qa_console = !sc->sc_console;
255: qa.qa_hook = &sc->sc_hook[QSC_LINE_KEYBOARD];
256: if (config_found(self, &qa, qsc_print) != NULL)
257: sc->sc_sv_reg->sv_imr[QSC_LINE_KEYBOARD >> 1] |= IRXRDYA;
258: #endif
259: #if NQSCMS > 0
260: /* mouse */
261: qa.qa_line = QSC_LINE_MOUSE;
262: qa.qa_console = 0;
263: qa.qa_hook = &sc->sc_hook[QSC_LINE_MOUSE];
264: if (config_found(self, &qa, qsc_print) != NULL)
265: sc->sc_sv_reg->sv_imr[QSC_LINE_MOUSE >> 1] |= IRXRDYB;
266: #endif
267:
268: for (pair = 0; pair < SC_NLINES / 2; pair++)
269: qsc_write(sc, pair << 1, SC_IMR,
270: sc->sc_sv_reg->sv_imr[pair]);
271:
272: sc->sc_rdy = 1;
273: }
274:
275: /* speed tables */
276: const struct qsc_s {
277: int kspeed;
278: int dspeed;
279: } qsc_speeds[] = {
280: { B0, 0 }, /* 0 baud, special HUP condition */
281: { B50, NOBAUD }, /* 50 baud, not implemented */
282: { B75, BD75 }, /* 75 baud */
283: { B110, BD110 }, /* 110 baud */
284: { B134, BD134 }, /* 134.5 baud */
285: { B150, BD150 }, /* 150 baud */
286: { B200, NOBAUD }, /* 200 baud, not implemented */
287: { B300, BD300 }, /* 300 baud */
288: { B600, BD600 }, /* 600 baud */
289: { B1200, BD1200 }, /* 1200 baud */
290: { B1800, BD1800 }, /* 1800 baud */
291: { B2400, BD2400 }, /* 2400 baud */
292: { B4800, BD4800 }, /* 4800 baud */
293: { B9600, BD9600 }, /* 9600 baud */
294: { B19200, BD19200 }, /* 19200 baud */
295: { -1, NOBAUD }, /* anything more is uncivilized */
296: };
297:
298: int
299: qscspeed(int speed)
300: {
301: const struct qsc_s *ds;
302:
303: for (ds = qsc_speeds; ds->kspeed != -1; ds++)
304: if (ds->kspeed == speed)
305: return ds->dspeed;
306:
307: return NOBAUD;
308: }
309:
310: struct tty *
311: qsctty(dev_t dev)
312: {
313: u_int line;
314: struct qscsoftc *sc;
315:
316: line = SC_LINE(dev);
317: if (qsc_cd.cd_ndevs == 0 || line >= SC_NLINES)
318: return (NULL);
319:
320: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
321: if (sc == NULL)
322: return (NULL);
323:
324: return sc->sc_tty[line];
325: }
326:
327: void
328: qscstart(struct tty *tp)
329: {
330: struct qscsoftc *sc;
331: dev_t dev;
332: int s;
333: u_int line;
334: int c, tries;
335:
336: if ((tp->t_state & TS_ISOPEN) == 0)
337: return;
338:
339: dev = tp->t_dev;
340: line = SC_LINE(dev);
341: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
342:
343: s = spltty();
344:
345: if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
346: goto bail;
347:
348: if (tp->t_outq.c_cc <= tp->t_lowat) {
349: if (tp->t_state & TS_ASLEEP) {
350: tp->t_state &= ~TS_ASLEEP;
351: wakeup((caddr_t)&tp->t_outq);
352: }
353: selwakeup(&tp->t_wsel);
354: if (tp->t_outq.c_cc == 0)
355: goto bail;
356: }
357:
358: tp->t_state |= TS_BUSY;
359: while (tp->t_outq.c_cc != 0) {
360:
361: /* load transmitter until it is full */
362: for (tries = 10000; tries != 0; tries --)
363: if (qsc_read(sc, line, SC_SR) & TXRDY)
364: break;
365:
366: if (tries == 0) {
367: timeout_add(&tp->t_rstrt_to, 1);
368: tp->t_state |= TS_TIMEOUT;
369: break;
370: } else {
371: c = getc(&tp->t_outq);
372:
373: qsc_write(sc, line, SC_TXFIFO, c & 0xff);
374:
375: sc->sc_sv_reg->sv_imr[line >> 1] |=
376: line & 1 ? ITXRDYB : ITXRDYA;
377: qsc_write(sc, line, SC_IMR,
378: sc->sc_sv_reg->sv_imr[line >> 1]);
379: }
380: }
381: tp->t_state &= ~TS_BUSY;
382:
383: bail:
384: splx(s);
385: }
386:
387: int
388: qscstop(struct tty *tp, int flag)
389: {
390: int s;
391:
392: s = spltty();
393: if (tp->t_state & TS_BUSY) {
394: if ((tp->t_state & TS_TTSTOP) == 0)
395: tp->t_state |= TS_FLUSH;
396: }
397: splx(s);
398:
399: return 0;
400: }
401:
402: int
403: qscioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
404: {
405: int error;
406: u_int line;
407: struct tty *tp;
408: struct qscsoftc *sc;
409:
410: line = SC_LINE(dev);
411: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
412:
413: tp = sc->sc_tty[line];
414: if (tp == NULL)
415: return (ENXIO);
416:
417: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
418: if (error >= 0)
419: return(error);
420:
421: error = ttioctl(tp, cmd, data, flag, p);
422: if (error >= 0)
423: return(error);
424:
425: switch (cmd) {
426: case TIOCGFLAGS:
427: *(int *)data = sc->sc_swflags[line];
428: break;
429: case TIOCSFLAGS:
430: error = suser(p, 0);
431: if (error != 0)
432: return (EPERM);
433:
434: sc->sc_swflags[line] = *(int *)data &
435: /* only allow valid flags */
436: (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
437: break;
438: default:
439: return (ENOTTY);
440: }
441:
442: return (0);
443: }
444:
445: int
446: qscparam(struct tty *tp, struct termios *t)
447: {
448: int flags;
449: u_int line, pair;
450: int speeds;
451: u_int8_t mr1, mr2;
452: struct qscsoftc *sc;
453: dev_t dev;
454:
455: dev = tp->t_dev;
456: line = SC_LINE(dev);
457: pair = line >> 1;
458: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
459:
460: tp->t_ispeed = t->c_ispeed;
461: tp->t_ospeed = t->c_ospeed;
462: tp->t_cflag = t->c_cflag;
463:
464: flags = tp->t_flags;
465:
466: /* disable Tx and Rx */
467: if (sc->sc_console == 0 || line != QSC_LINE_SERIAL) {
468: if (line & 1)
469: sc->sc_sv_reg->sv_imr[pair] &= ~(ITXRDYB | IRXRDYB);
470: else
471: sc->sc_sv_reg->sv_imr[pair] &= ~(ITXRDYA | IRXRDYA);
472: qsc_write(sc, line, SC_IMR, sc->sc_sv_reg->sv_imr[pair]);
473:
474: /* set baudrate */
475: speeds = qscspeed(tp->t_ispeed);
476: if (speeds == NOBAUD)
477: speeds = DEFBAUD;
478: qsc_write(sc, line, SC_CSR, speeds);
479: sc->sc_sv_reg->sv_csr[line] = speeds;
480:
481: /* get saved mode registers and clear set up parameters */
482: mr1 = sc->sc_sv_reg->sv_mr1[line];
483: mr1 &= ~(CLMASK | PARTYPEMASK | PARMODEMASK);
484:
485: mr2 = sc->sc_sv_reg->sv_mr2[line];
486: mr2 &= ~SBMASK;
487:
488: /* set up character size */
489: switch (t->c_cflag & CSIZE) {
490: case CL8:
491: mr1 |= CL8;
492: break;
493: case CL7:
494: mr1 |= CL7;
495: break;
496: case CL6:
497: mr1 |= CL6;
498: break;
499: case CL5:
500: mr1 |= CL5;
501: break;
502: }
503:
504: /* set up stop bits */
505: if (tp->t_ospeed == B110)
506: mr2 |= SB2;
507: else
508: mr2 |= SB1;
509:
510: /* set up parity */
511: if (t->c_cflag & PARENB) {
512: mr1 |= PAREN;
513: if (t->c_cflag & PARODD)
514: mr1 |= ODDPAR;
515: else
516: mr1 |= EVENPAR;
517: } else
518: mr1 |= PARDIS;
519:
520: if (sc->sc_sv_reg->sv_mr1[line] != mr1 ||
521: sc->sc_sv_reg->sv_mr2[line] != mr2) {
522: /* write mode registers to duart */
523: qsc_write(sc, line, SC_CR, MRONE);
524: DELAY(1);
525: qsc_write(sc, line, SC_MR, mr1);
526: qsc_write(sc, line, SC_MR, mr2);
527:
528: /* save changed mode registers */
529: sc->sc_sv_reg->sv_mr1[line] = mr1;
530: sc->sc_sv_reg->sv_mr2[line] = mr2;
531: }
532: }
533:
534: /* enable transmitter? */
535: if (tp->t_state & TS_BUSY) {
536: sc->sc_sv_reg->sv_imr[pair] |= line & 1 ? ITXRDYB : ITXRDYA;
537: }
538:
539: /* re-enable the receiver */
540: sc->sc_sv_reg->sv_imr[pair] |= line & 1 ? IRXRDYB : IRXRDYA;
541: qsc_write(sc, line, SC_IMR, sc->sc_sv_reg->sv_imr[pair]);
542:
543: return (0);
544: }
545:
546: int
547: qscopen(dev_t dev, int flag, int mode, struct proc *p)
548: {
549: int s;
550: u_int line;
551: struct qscsoftc *sc;
552: struct tty *tp;
553:
554: line = SC_LINE(dev);
555: if (qsc_cd.cd_ndevs == 0 || line >= SC_NLINES)
556: return (ENXIO);
557: /* Line B is not wired... */
558: if (line == QSC_LINE_DEAD)
559: return (ENXIO);
560: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
561: if (sc == NULL)
562: return (ENXIO);
563:
564: /* if some other device is using the line, it's not available */
565: if (sc->sc_hook[line].fn != NULL)
566: return (ENXIO);
567:
568: s = spltty();
569: if (sc->sc_tty[line] != NULL)
570: tp = sc->sc_tty[line];
571: else
572: tp = sc->sc_tty[line] = ttymalloc();
573:
574: tp->t_oproc = qscstart;
575: tp->t_param = qscparam;
576: tp->t_dev = dev;
577:
578: if ((tp->t_state & TS_ISOPEN) == 0) {
579: ttychars(tp);
580:
581: if (tp->t_ispeed == 0) {
582: tp->t_iflag = TTYDEF_IFLAG;
583: tp->t_oflag = TTYDEF_OFLAG;
584: tp->t_lflag = TTYDEF_LFLAG;
585: tp->t_ispeed = tp->t_ospeed = B9600;
586: if (sc->sc_console && line == QSC_LINE_SERIAL) {
587: /* console is 8N1 */
588: tp->t_cflag = (CREAD | CS8 | HUPCL);
589: } else {
590: tp->t_cflag = TTYDEF_CFLAG;
591: }
592: }
593:
594: if (sc->sc_swflags[line] & TIOCFLAG_CLOCAL)
595: tp->t_cflag |= CLOCAL;
596: if (sc->sc_swflags[line] & TIOCFLAG_CRTSCTS)
597: tp->t_cflag |= CRTSCTS;
598: if (sc->sc_swflags[line] & TIOCFLAG_MDMBUF)
599: tp->t_cflag |= MDMBUF;
600:
601: qscparam(tp, &tp->t_termios);
602: ttsetwater(tp);
603:
604: tp->t_state |= TS_CARR_ON;
605: } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
606: splx(s);
607: return (EBUSY);
608: }
609:
610: /*
611: * Reset the tty pointer, as there could have been a dialout
612: * use of the tty with a dialin open waiting.
613: */
614: tp->t_dev = dev;
615: splx(s);
616: return ((*linesw[tp->t_line].l_open)(dev, tp));
617: }
618:
619: int
620: qscclose(dev_t dev, int flag, int mode, struct proc *p)
621: {
622: struct tty *tp;
623: struct qscsoftc *sc;
624: u_int line;
625:
626: line = SC_LINE(dev);
627: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
628:
629: tp = sc->sc_tty[line];
630: (*linesw[tp->t_line].l_close)(tp, flag);
631: ttyclose(tp);
632:
633: return (0);
634: }
635:
636: int
637: qscread(dev_t dev, struct uio *uio, int flag)
638: {
639: u_int line;
640: struct tty *tp;
641: struct qscsoftc *sc;
642:
643: line = SC_LINE(dev);
644: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
645:
646: tp = sc->sc_tty[line];
647: if (tp == NULL)
648: return (ENXIO);
649: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
650: }
651:
652: int
653: qscwrite(dev_t dev, struct uio *uio, int flag)
654: {
655: u_int line;
656: struct tty *tp;
657: struct qscsoftc *sc;
658:
659: line = SC_LINE(dev);
660: sc = (struct qscsoftc *)qsc_cd.cd_devs[0];
661:
662: tp = sc->sc_tty[line];
663: if (tp == NULL)
664: return (ENXIO);
665: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
666: }
667:
668: void
669: qscrint(struct qscsoftc *sc, u_int line)
670: {
671: struct tty *tp;
672: int data;
673: unsigned char sr;
674: int overrun = 0;
675:
676: tp = sc->sc_tty[line];
677:
678: /* read status reg */
679: while ((sr = qsc_read(sc, line, SC_SR)) & RXRDY) {
680: /* read data and reset receiver */
681: data = qsc_read(sc, line, SC_RXFIFO);
682:
683: if (sr & RBRK) {
684: /* clear break state */
685: qsc_write(sc, line, SC_CR, BRKINTRESET);
686: DELAY(1);
687: qsc_write(sc, line, SC_CR, ERRRESET);
688: DELAY(1);
689: continue;
690: }
691:
692: if ((sr & ROVRN) && cold == 0 && overrun == 0) {
693: log(LOG_WARNING, "%s line %d: receiver overrun\n",
694: sc->sc_dev.dv_xname, line);
695: overrun = 1;
696: }
697:
698: if (sr & FRERR)
699: data |= TTY_FE;
700: if (sr & PERR)
701: data |= TTY_PE;
702:
703: /* clear error state */
704: if (sr & (ROVRN | FRERR | PERR)) {
705: qsc_write(sc, line, SC_CR, ERRRESET);
706: DELAY(1);
707: }
708:
709: if (sc->sc_hook[line].fn != NULL) {
710: if ((data & TTY_ERRORMASK) != 0 ||
711: (*sc->sc_hook[line].fn)(sc->sc_hook[line].arg, data))
712: continue;
713: }
714:
715: if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0 &&
716: (sc->sc_console == 0 || line != QSC_LINE_SERIAL)) {
717: continue;
718: }
719:
720: /* no errors */
721: #if defined(DDB)
722: if (tp->t_dev == cn_tab->cn_dev) {
723: int j = kdbrint(data);
724:
725: if (j == 1)
726: continue;
727:
728: if (j == 2)
729: (*linesw[tp->t_line].l_rint)(27, tp);
730: }
731: #endif
732: (*linesw[tp->t_line].l_rint)(data, tp);
733: }
734: }
735:
736: void
737: qscxint(struct qscsoftc *sc, u_int line)
738: {
739: struct tty *tp;
740: u_int pair;
741:
742: tp = sc->sc_tty[line];
743:
744: if ((tp->t_state & (TS_ISOPEN|TS_WOPEN))==0)
745: goto out;
746:
747: if (tp->t_state & TS_BUSY) {
748: tp->t_state &= ~(TS_BUSY | TS_FLUSH);
749: qscstart(tp);
750: if (tp->t_state & TS_BUSY) {
751: /* do not disable transmitter, yet */
752: return;
753: }
754: }
755: out:
756:
757: /* disable transmitter */
758: pair = line >> 1;
759: sc->sc_sv_reg->sv_imr[pair] &= line & 1 ? ~ITXRDYB : ~ITXRDYA;
760: qsc_write(sc, line, SC_IMR, sc->sc_sv_reg->sv_imr[pair]);
761: }
762:
763: int
764: qscintr(void *arg)
765: {
766: struct qscsoftc *sc = arg;
767: u_int8_t isr[SC_NLINES >> 1], curisr;
768: u_int pair, line;
769: int rc = 0;
770:
771: for (pair = 0; pair < SC_NLINES >> 1; pair++) {
772: line = pair << 1;
773:
774: /* read interrupt status register and mask with imr */
775: isr[pair] = curisr = qsc_read(sc, line, SC_ISR);
776: curisr &= sc->sc_sv_reg->sv_imr[pair];
777: if (curisr == 0)
778: continue;
779:
780: rc = 1;
781:
782: if (curisr & IRXRDYA)
783: qscrint(sc, line);
784: if (curisr & ITXRDYA)
785: qscxint(sc, line);
786: if (curisr & IBRKA) {
787: qsc_write(sc, line, SC_CR, BRKINTRESET);
788: DELAY(1);
789: }
790:
791: if (curisr & IRXRDYB)
792: qscrint(sc, line + 1);
793: if (curisr & ITXRDYB)
794: qscxint(sc, line + 1);
795: if (curisr & IBRKB) {
796: qsc_write(sc, line + 1, SC_CR, BRKINTRESET);
797: DELAY(1);
798: }
799: }
800:
801: return (rc);
802: }
803:
804: /*
805: * Console interface routines.
806: */
807:
808: vaddr_t qsc_cnregs;
809: #define qsc_cnread(reg) \
810: *(volatile u_int8_t *)(qsc_cnregs + 4 * (reg))
811: #define qsc_cnwrite(reg, val) \
812: *(volatile u_int8_t *)(qsc_cnregs + 4 * (reg)) = (val)
813:
814: void
815: qsccnprobe(struct consdev *cp)
816: {
817: int maj;
818: extern int getmajor(void *);
819: extern vaddr_t iospace;
820:
821: if (vax_boardtype != VAX_BTYP_VXT)
822: return;
823:
824: /* locate the major number */
825: if ((maj = getmajor(qscopen)) < 0)
826: return;
827:
828: qsc_cnregs = iospace;
829: ioaccess(iospace, QSCADDR, 1);
830:
831: cp->cn_dev = makedev(maj, QSC_LINE_SERIAL);
832: cp->cn_pri = vax_confdata & 2 ? CN_NORMAL : CN_REMOTE;
833: }
834:
835: void
836: qsccninit(cp)
837: struct consdev *cp;
838: {
839: qsccn_sv.sv_mr1[QSC_LINE_SERIAL] = PARDIS | RXRTS | CL8;
840: qsccn_sv.sv_mr2[QSC_LINE_SERIAL] = /* TXCTS | */ SB1;
841: qsccn_sv.sv_csr[QSC_LINE_SERIAL] = BD9600;
842: qsccn_sv.sv_cr[QSC_LINE_SERIAL] = TXEN | RXEN;
843: qsccn_sv.sv_imr[QSC_LINE_SERIAL] = 0;
844:
845: qsc_cnwrite(SC_CRA, RXRESET | TXDIS | RXDIS);
846: DELAY(1);
847: qsc_cnwrite(SC_CRA, TXRESET | TXDIS | RXDIS);
848: DELAY(1);
849: qsc_cnwrite(SC_CRA, ERRRESET | TXDIS | RXDIS);
850: DELAY(1);
851: qsc_cnwrite(SC_CRA, BRKINTRESET | TXDIS | RXDIS);
852: DELAY(1);
853: qsc_cnwrite(SC_CRA, MRZERO | TXDIS | RXDIS);
854: DELAY(1);
855:
856: qsc_cnwrite(SC_MRA, 0);
857: qsc_cnwrite(SC_MRA, qsccn_sv.sv_mr1[QSC_LINE_SERIAL]);
858: qsc_cnwrite(SC_MRA, qsccn_sv.sv_mr2[QSC_LINE_SERIAL]);
859: qsc_cnwrite(SC_CSRA, qsccn_sv.sv_csr[QSC_LINE_SERIAL]);
860: qsc_cnwrite(SC_CRA, qsccn_sv.sv_cr[QSC_LINE_SERIAL]);
861: DELAY(1);
862:
863: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL]);
864: qsc_cnwrite(SC_IMRCD, 0);
865: }
866:
867: int
868: qsccngetc(dev_t dev)
869: {
870: unsigned char sr; /* status reg of line a/b */
871: u_char c; /* received character */
872: int s;
873:
874: s = spltty();
875:
876: /* disable interrupts for this line and enable receiver */
877: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL] & ~ITXRDYA);
878: qsc_cnwrite(SC_CRA, RXEN);
879: DELAY(1);
880:
881: for (;;) {
882: /* read status reg */
883: sr = qsc_cnread(SC_SRA);
884:
885: /* receiver interrupt handler*/
886: if (sr & RXRDY) {
887: /* read character from line */
888: c = qsc_cnread(SC_RXFIFOA);
889:
890: /* check break condition */
891: if (sr & RBRK) {
892: /* clear break state */
893: qsc_cnwrite(SC_CRA, BRKINTRESET);
894: DELAY(1);
895: qsc_cnwrite(SC_CRA, ERRRESET);
896: DELAY(1);
897: break;
898: }
899:
900: if (sr & (FRERR | PERR | ROVRN)) {
901: /* clear error state */
902: qsc_cnwrite(SC_CRA, ERRRESET);
903: DELAY(1);
904: } else {
905: break;
906: }
907: }
908: }
909:
910: /* restore the previous state */
911: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL]);
912: qsc_cnwrite(SC_CRA, qsccn_sv.sv_cr[QSC_LINE_SERIAL]);
913:
914: splx(s);
915:
916: return ((int)c);
917: }
918:
919: void
920: qsccnputc(dev_t dev, int c)
921: {
922: int s;
923:
924: if (mfpr(PR_MAPEN) == 0)
925: return;
926:
927: s = spltty();
928:
929: /* disable interrupts for this line and enable transmitter */
930: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL] & ~ITXRDYA);
931: qsc_cnwrite(SC_CRA, TXEN);
932: DELAY(1);
933:
934: while ((qsc_cnread(SC_SRA) & TXRDY) == 0)
935: ;
936: qsc_cnwrite(SC_TXFIFOA, c);
937:
938: /* wait for transmitter to empty */
939: while ((qsc_cnread(SC_SRA) & TXEMT) == 0)
940: ;
941:
942: /* restore the previous state */
943: qsc_cnwrite(SC_IMRAB, qsccn_sv.sv_imr[QSC_LINE_SERIAL]);
944: qsc_cnwrite(SC_CRA, qsccn_sv.sv_cr[QSC_LINE_SERIAL]);
945: DELAY(1);
946:
947: splx(s);
948: }
949:
950: void
951: qsccnpollc(dev, pollflag)
952: dev_t dev;
953: int pollflag;
954: {
955: }
956:
957: /*
958: * Keyboard and mouse helper routines
959: */
960:
961: #if NQSCKBD > 0 || NQSCMS > 0
962: int
963: qsc_print(void *aux, const char *name)
964: {
965: struct qsc_attach_args *qa = aux;
966:
967: if (name != NULL)
968: printf(qa->qa_line == QSC_LINE_KEYBOARD ?
969: "lkkbd at %s" : "lkms at %s", name);
970: else
971: printf(" line %d", qa->qa_line);
972:
973: return (UNCONF);
974: }
975:
976: int
977: qscgetc(u_int line)
978: {
979: bus_addr_t craddr;
980: struct qscsoftc *sc = NULL;
981: int s;
982: u_int8_t sr, imr, imrmask, cr, c;
983:
984: s = spltty();
985:
986: craddr = line == QSC_LINE_KEYBOARD ? SC_CRC : SC_CRD;
987: imrmask = line & 1 ? ~IRXRDYB : ~IRXRDYA;
988: imr = sc != NULL ? sc->sc_sv_reg->sv_imr[line / 2] : 0;
989: cr = sc != NULL ? sc->sc_sv_reg->sv_cr[line] : 0;
990:
991: /* disable interrupts for this line and enable receiver */
992: qsc_cnwrite(SC_IMRCD, imr & imrmask);
993: qsc_cnwrite(craddr, RXEN);
994: DELAY(1);
995:
996: for (;;) {
997: /* read status reg */
998: sr = qsc_cnread(line == QSC_LINE_KEYBOARD ? SC_SRC : SC_SRD);
999:
1000: /* receiver interrupt handler*/
1001: if (sr & RXRDY) {
1002: /* read character from line */
1003: c = qsc_cnread(line == QSC_LINE_KEYBOARD ?
1004: SC_RXFIFOC : SC_RXFIFOD);
1005:
1006: /* check break condition */
1007: if (sr & RBRK) {
1008: /* clear break state */
1009: qsc_cnwrite(craddr, BRKINTRESET);
1010: DELAY(1);
1011: qsc_cnwrite(craddr, ERRRESET);
1012: DELAY(1);
1013: break;
1014: }
1015:
1016: if (sr & (FRERR | PERR | ROVRN)) {
1017: /* clear error state */
1018: qsc_cnwrite(craddr, ERRRESET);
1019: DELAY(1);
1020: } else {
1021: break;
1022: }
1023: }
1024: }
1025:
1026: /* restore the previous state */
1027: qsc_cnwrite(SC_IMRCD, imr);
1028: qsc_cnwrite(craddr, cr);
1029: DELAY(1);
1030:
1031: splx(s);
1032:
1033: return ((int)c);
1034: }
1035:
1036: void
1037: qscputc(u_int line, int c)
1038: {
1039: bus_addr_t craddr;
1040: struct qscsoftc *sc = NULL;
1041: int s;
1042: u_int8_t imr, imrmask, cr;
1043:
1044: s = spltty();
1045:
1046: if (qsc_cd.cd_ndevs != 0 &&
1047: (sc = (struct qscsoftc *)qsc_cd.cd_devs[0]) != NULL)
1048: if (sc->sc_rdy == 0)
1049: sc = NULL;
1050:
1051: craddr = line == QSC_LINE_KEYBOARD ? SC_CRC : SC_CRD;
1052: imrmask = line & 1 ? ~ITXRDYB : ~ITXRDYA;
1053: imr = sc != NULL ? sc->sc_sv_reg->sv_imr[line / 2] : 0;
1054: cr = sc != NULL ? sc->sc_sv_reg->sv_cr[line] : 0;
1055:
1056: /* disable interrupts for this line and enable transmitter */
1057: qsc_cnwrite(SC_IMRCD, imr & imrmask);
1058: qsc_cnwrite(craddr, TXEN);
1059: DELAY(1);
1060:
1061: while ((qsc_cnread(line == QSC_LINE_KEYBOARD ? SC_SRC : SC_SRD) &
1062: TXRDY) == 0)
1063: ;
1064: qsc_cnwrite(line == QSC_LINE_KEYBOARD ? SC_TXFIFOC : SC_TXFIFOD, c);
1065:
1066: /* wait for transmitter to empty */
1067: while ((qsc_cnread(line == QSC_LINE_KEYBOARD ? SC_SRC : SC_SRD) &
1068: TXEMT) == 0)
1069: ;
1070:
1071: /* restore the previous state */
1072: qsc_cnwrite(SC_IMRCD, imr);
1073: qsc_cnwrite(craddr, cr);
1074: DELAY(1);
1075:
1076: splx(s);
1077: }
1078: #endif
CVSweb