Annotation of sys/arch/sparc64/dev/z8530kbd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: z8530kbd.c,v 1.19 2007/05/25 21:27:15 krw Exp $ */
2: /* $NetBSD: z8530tty.c,v 1.77 2001/05/30 15:24:24 lukem Exp $ */
3:
4: /*-
5: * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999
6: * Charles M. Hannum. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by Charles M. Hannum.
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: /*
35: * Copyright (c) 1994 Gordon W. Ross
36: * Copyright (c) 1992, 1993
37: * The Regents of the University of California. All rights reserved.
38: *
39: * This software was developed by the Computer Systems Engineering group
40: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
41: * contributed to Berkeley.
42: *
43: * All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Lawrence Berkeley Laboratory.
47: *
48: * Redistribution and use in source and binary forms, with or without
49: * modification, are permitted provided that the following conditions
50: * are met:
51: * 1. Redistributions of source code must retain the above copyright
52: * notice, this list of conditions and the following disclaimer.
53: * 2. Redistributions in binary form must reproduce the above copyright
54: * notice, this list of conditions and the following disclaimer in the
55: * documentation and/or other materials provided with the distribution.
56: * 3. Neither the name of the University nor the names of its contributors
57: * may be used to endorse or promote products derived from this software
58: * without specific prior written permission.
59: *
60: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70: * SUCH DAMAGE.
71: *
72: * @(#)zs.c 8.1 (Berkeley) 7/19/93
73: */
74:
75: /*
76: * Zilog Z8530 Dual UART driver (tty interface)
77: *
78: * This is the "slave" driver that will be attached to
79: * the "zsc" driver for plain "tty" async. serial lines.
80: *
81: * Credits, history:
82: *
83: * The original version of this code was the sparc/dev/zs.c driver
84: * as distributed with the Berkeley 4.4 Lite release. Since then,
85: * Gordon Ross reorganized the code into the current parent/child
86: * driver scheme, separating the Sun keyboard and mouse support
87: * into independent child drivers.
88: *
89: * RTS/CTS flow-control support was a collaboration of:
90: * Gordon Ross <gwr@netbsd.org>,
91: * Bill Studenmund <wrstuden@loki.stanford.edu>
92: * Ian Dall <Ian.Dall@dsto.defence.gov.au>
93: *
94: * The driver was massively overhauled in November 1997 by Charles Hannum,
95: * fixing *many* bugs, and substantially improving performance.
96: */
97:
98: #include <sys/param.h>
99: #include <sys/systm.h>
100: #include <sys/proc.h>
101: #include <sys/device.h>
102: #include <sys/conf.h>
103: #include <sys/file.h>
104: #include <sys/ioctl.h>
105: #include <sys/malloc.h>
106: #include <sys/tty.h>
107: #include <sys/time.h>
108: #include <sys/kernel.h>
109: #include <sys/syslog.h>
110:
111: #include <machine/autoconf.h>
112:
113: #include <dev/wscons/wsconsio.h>
114: #include <dev/wscons/wskbdvar.h>
115:
116: #include <dev/sun/sunkbdreg.h>
117: #include <dev/sun/sunkbdvar.h>
118:
119: #include <sparc64/dev/z8530reg.h>
120: #include <machine/z8530var.h>
121:
122: #include <dev/cons.h>
123:
124: /*
125: * How many input characters we can buffer.
126: * The port-specific var.h may override this.
127: * Note: must be a power of two!
128: */
129: #ifndef ZSKBD_RING_SIZE
130: #define ZSKBD_RING_SIZE 2048
131: #endif
132:
133: struct cfdriver zskbd_cd = {
134: NULL, "zskbd", DV_TTY
135: };
136:
137: /*
138: * Make this an option variable one can patch.
139: * But be warned: this must be a power of 2!
140: */
141: u_int zskbd_rbuf_size = ZSKBD_RING_SIZE;
142:
143: /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
144: u_int zskbd_rbuf_hiwat = (ZSKBD_RING_SIZE * 1) / 4;
145: u_int zskbd_rbuf_lowat = (ZSKBD_RING_SIZE * 3) / 4;
146:
147: struct zskbd_softc {
148: struct sunkbd_softc sc_base;
149:
150: struct zs_chanstate *zst_cs;
151:
152: struct timeout zst_diag_ch;
153:
154: u_int zst_overflows,
155: zst_floods,
156: zst_errors;
157:
158: int zst_hwflags, /* see z8530var.h */
159: zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
160:
161: u_int zst_r_hiwat,
162: zst_r_lowat;
163: u_char *volatile zst_rbget,
164: *volatile zst_rbput;
165: volatile u_int zst_rbavail;
166: u_char *zst_rbuf,
167: *zst_ebuf;
168:
169: /*
170: * The transmit byte count and address are used for pseudo-DMA
171: * output in the hardware interrupt code. PDMA can be suspended
172: * to get pending changes done; heldtbc is used for this. It can
173: * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
174: */
175: u_char *zst_tba; /* transmit buffer address */
176: u_int zst_tbc, /* transmit byte count */
177: zst_heldtbc; /* held tbc while xmission stopped */
178:
179: u_char zst_tbuf[ZSKBD_RING_SIZE];
180: u_char *zst_tbeg, *zst_tend, *zst_tbp;
181:
182: /* Flags to communicate with zskbd_softint() */
183: volatile u_char zst_rx_flags, /* receiver blocked */
184: #define RX_TTY_BLOCKED 0x01
185: #define RX_TTY_OVERFLOWED 0x02
186: #define RX_IBUF_BLOCKED 0x04
187: #define RX_IBUF_OVERFLOWED 0x08
188: #define RX_ANY_BLOCK 0x0f
189: zst_tx_busy, /* working on an output chunk */
190: zst_tx_done, /* done with one output chunk */
191: zst_tx_stopped, /* H/W level stop (lost CTS) */
192: zst_st_check, /* got a status interrupt */
193: zst_rx_ready;
194:
195: /* PPS signal on DCD, with or without inkernel clock disciplining */
196: u_char zst_ppsmask; /* pps signal mask */
197: u_char zst_ppsassert; /* pps leading edge */
198: u_char zst_ppsclear; /* pps trailing edge */
199: };
200:
201: /* Definition of the driver for autoconfig. */
202: static int zskbd_match(struct device *, void *, void *);
203: static void zskbd_attach(struct device *, struct device *, void *);
204:
205: struct cfattach zskbd_ca = {
206: sizeof(struct zskbd_softc), zskbd_match, zskbd_attach
207: };
208:
209: struct zsops zsops_kbd;
210:
211: static void zs_modem(struct zskbd_softc *, int);
212: static void zs_hwiflow(struct zskbd_softc *);
213: static void zs_maskintr(struct zskbd_softc *);
214:
215: struct zskbd_softc *zskbd_device_lookup(struct cfdriver *, int);
216:
217: /* Low-level routines. */
218: static void zskbd_rxint(struct zs_chanstate *);
219: static void zskbd_stint(struct zs_chanstate *, int);
220: static void zskbd_txint(struct zs_chanstate *);
221: static void zskbd_softint(struct zs_chanstate *);
222: static void zskbd_diag(void *);
223:
224: int zskbd_init(struct zskbd_softc *);
225: void zskbd_putc(struct zskbd_softc *, u_int8_t);
226: void zskbd_raw(struct zskbd_softc *, u_int8_t);
227:
228: /* wskbd glue */
229: void zskbd_cngetc(void *, u_int *, int *);
230: void zskbd_cnpollc(void *, int);
231:
232: void zsstart_tx(struct zskbd_softc *);
233: int zsenqueue_tx(void *, u_int8_t *, u_int);
234:
235: struct wskbd_consops zskbd_consops = {
236: zskbd_cngetc,
237: zskbd_cnpollc
238: };
239:
240: #define ZSKBDUNIT(x) (minor(x) & 0x7ffff)
241:
242: struct zskbd_softc *
243: zskbd_device_lookup(cf, unit)
244: struct cfdriver *cf;
245: int unit;
246: {
247: return (struct zskbd_softc *)device_lookup(cf, unit);
248: }
249:
250: /*
251: * zskbd_match: how is this zs channel configured?
252: */
253: int
254: zskbd_match(parent, vcf, aux)
255: struct device *parent;
256: void *vcf;
257: void *aux;
258: {
259: struct cfdata *cf = vcf;
260: struct zsc_attach_args *args = aux;
261: int ret;
262:
263: /* If we're not looking for a keyboard, just exit */
264: if (strcmp(args->type, "keyboard") != 0)
265: return (0);
266:
267: ret = 10;
268:
269: /* Exact match is better than wildcard. */
270: if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel)
271: ret += 2;
272:
273: /* This driver accepts wildcard. */
274: if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT)
275: ret += 1;
276:
277: return (ret);
278: }
279:
280: void
281: zskbd_attach(parent, self, aux)
282: struct device *parent, *self;
283: void *aux;
284:
285: {
286: struct zsc_softc *zsc = (void *)parent;
287: struct zskbd_softc *zst = (void *)self;
288: struct sunkbd_softc *ss = (void *)self;
289: struct cfdata *cf = self->dv_cfdata;
290: struct zsc_attach_args *args = aux;
291: struct wskbddev_attach_args a;
292: struct zs_chanstate *cs;
293: int channel, s, tty_unit, console = 0;
294: dev_t dev;
295:
296: ss->sc_sendcmd = zsenqueue_tx;
297: timeout_set(&ss->sc_bellto, sunkbd_bellstop, zst);
298:
299: timeout_set(&zst->zst_diag_ch, zskbd_diag, zst);
300:
301: zst->zst_tbp = zst->zst_tba = zst->zst_tbeg = zst->zst_tbuf;
302: zst->zst_tend = zst->zst_tbeg + ZSKBD_RING_SIZE;
303:
304: tty_unit = ss->sc_dev.dv_unit;
305: channel = args->channel;
306: cs = zsc->zsc_cs[channel];
307: cs->cs_private = zst;
308: cs->cs_ops = &zsops_kbd;
309:
310: zst->zst_cs = cs;
311: zst->zst_swflags = cf->cf_flags; /* softcar, etc. */
312: zst->zst_hwflags = args->hwflags;
313: dev = makedev(zs_major, tty_unit);
314:
315: if (zst->zst_swflags)
316: printf(" flags 0x%x", zst->zst_swflags);
317:
318: /*
319: * Check whether we serve as a console device.
320: * XXX - split console input/output channels aren't
321: * supported yet on /dev/console
322: */
323: if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) {
324: if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) {
325: args->consdev->cn_dev = dev;
326: cn_tab->cn_pollc = wskbd_cnpollc;
327: cn_tab->cn_getc = wskbd_cngetc;
328: }
329: cn_tab->cn_dev = dev;
330: console = 1;
331: }
332:
333: zst->zst_rbuf = malloc(zskbd_rbuf_size << 1, M_DEVBUF, M_WAITOK);
334: zst->zst_ebuf = zst->zst_rbuf + (zskbd_rbuf_size << 1);
335: /* Disable the high water mark. */
336: zst->zst_r_hiwat = 0;
337: zst->zst_r_lowat = 0;
338: zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf;
339: zst->zst_rbavail = zskbd_rbuf_size;
340:
341: /* if there are no enable/disable functions, assume the device
342: is always enabled */
343: if (!cs->enable)
344: cs->enabled = 1;
345:
346: /*
347: * Hardware init
348: */
349: if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
350: /* Call zsparam similar to open. */
351:
352: /* Wait a while for previous console output to complete */
353: DELAY(10000);
354: } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) {
355: /* Not the console; may need reset. */
356: int reset;
357:
358: reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET;
359: s = splzs();
360: zs_write_reg(cs, 9, reset);
361: splx(s);
362: }
363:
364: /*
365: * Probe for a keyboard.
366: * If one is found, turn on receiver and status interrupts.
367: * We defer the actual write of the register to zsparam(),
368: * but we must make sure status interrupts are turned on by
369: * the time zsparam() reads the initial rr0 state.
370: */
371: if (zskbd_init(zst)) {
372: SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
373: zs_write_reg(cs, 1, cs->cs_creg[1]);
374:
375: /* Make sure DTR is on now. */
376: s = splzs();
377: zs_modem(zst, 1);
378: splx(s);
379: } else {
380: /* Will raise DTR in open. */
381: s = splzs();
382: zs_modem(zst, 0);
383: splx(s);
384:
385: return;
386: }
387:
388: ss->sc_click =
389: strcmp(getpropstring(optionsnode, "keyboard-click?"), "true") == 0;
390: sunkbd_setclick(ss, ss->sc_click);
391:
392: a.console = console;
393: if (ISTYPE5(ss->sc_layout)) {
394: a.keymap = &sunkbd5_keymapdata;
395: #ifndef SUNKBD5_LAYOUT
396: if (ss->sc_layout < MAXSUNLAYOUT &&
397: sunkbd_layouts[ss->sc_layout] != -1)
398: sunkbd5_keymapdata.layout =
399: sunkbd_layouts[ss->sc_layout];
400: #endif
401: } else {
402: a.keymap = &sunkbd_keymapdata;
403: #ifndef SUNKBD_LAYOUT
404: if (ss->sc_layout < MAXSUNLAYOUT &&
405: sunkbd_layouts[ss->sc_layout] != -1)
406: sunkbd_keymapdata.layout =
407: sunkbd_layouts[ss->sc_layout];
408: #endif
409: }
410: a.accessops = &sunkbd_accessops;
411: a.accesscookie = zst;
412:
413: if (console)
414: wskbd_cnattach(&zskbd_consops, zst, a.keymap);
415:
416: ss->sc_wskbddev = config_found(self, &a, wskbddevprint);
417: }
418:
419: int
420: zskbd_init(zst)
421: struct zskbd_softc *zst;
422: {
423: struct sunkbd_softc *ss = (void *)zst;
424: struct zs_chanstate *cs = zst->zst_cs;
425: int s, tries;
426: u_int8_t v3, v4, v5, rr0;
427:
428: /* setup for 1200n81 */
429: if (zs_set_speed(cs, 1200)) { /* set 1200bps */
430: printf(": failed to set baudrate\n");
431: return 0;
432: }
433: if (zs_set_modes(cs, CS8 | CLOCAL)) {
434: printf(": failed to set modes\n");
435: return 0;
436: }
437:
438: s = splzs();
439:
440: zs_maskintr(zst);
441:
442: v3 = cs->cs_preg[3]; /* set 8 bit chars */
443: v5 = cs->cs_preg[5];
444: CLR(v3, ZSWR3_RXSIZE);
445: CLR(v5, ZSWR5_TXSIZE);
446: SET(v3, ZSWR3_RX_8);
447: SET(v5, ZSWR5_TX_8);
448: cs->cs_preg[3] = v3;
449: cs->cs_preg[5] = v5;
450:
451: v4 = cs->cs_preg[4]; /* no parity 1 stop */
452: CLR(v4, ZSWR4_SBMASK | ZSWR4_PARMASK);
453: SET(v4, ZSWR4_ONESB | ZSWR4_EVENP);
454: cs->cs_preg[4] = v4;
455:
456: if (!cs->cs_heldchange) {
457: if (zst->zst_tx_busy) {
458: zst->zst_heldtbc = zst->zst_tbc;
459: zst->zst_tbc = 0;
460: cs->cs_heldchange = 1;
461: } else
462: zs_loadchannelregs(cs);
463: }
464:
465: /*
466: * Hardware flow control is disabled, turn off the buffer water
467: * marks and unblock any soft flow control state. Otherwise, enable
468: * the water marks.
469: */
470: zst->zst_r_hiwat = 0;
471: zst->zst_r_lowat = 0;
472: if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
473: CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED);
474: zst->zst_rx_ready = 1;
475: cs->cs_softreq = 1;
476: }
477: if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
478: CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
479: zs_hwiflow(zst);
480: }
481:
482: /*
483: * Force a recheck of the hardware carrier and flow control status,
484: * since we may have changed which bits we're looking at.
485: */
486: zskbd_stint(cs, 1);
487:
488: splx(s);
489:
490: /*
491: * Hardware flow control is disabled, unblock any hard flow control
492: * state.
493: */
494: if (zst->zst_tx_stopped) {
495: zst->zst_tx_stopped = 0;
496: zsstart_tx(zst);
497: }
498:
499: zskbd_softint(cs);
500:
501: /* Ok, start the reset sequence... */
502:
503: s = splhigh();
504:
505: for (tries = 5; tries != 0; tries--) {
506: int ltries;
507:
508: ss->sc_leds = 0;
509: ss->sc_layout = -1;
510:
511: /* Send reset request */
512: zskbd_putc(zst, SKBD_CMD_RESET);
513:
514: ltries = 1000;
515: while (--ltries > 0) {
516: rr0 = *cs->cs_reg_csr;
517: if (rr0 & ZSRR0_RX_READY) {
518: sunkbd_raw(ss, *cs->cs_reg_data);
519: if (ss->sc_kbdstate == SKBD_STATE_RESET)
520: break;
521: }
522: DELAY(1000);
523: }
524: if (ltries == 0)
525: continue;
526:
527: /* Wait for reset to finish. */
528: ltries = 1000;
529: while (--ltries > 0) {
530: rr0 = *cs->cs_reg_csr;
531: if (rr0 & ZSRR0_RX_READY) {
532: sunkbd_raw(ss, *cs->cs_reg_data);
533: if (ss->sc_kbdstate == SKBD_STATE_GETKEY)
534: break;
535: }
536: DELAY(1000);
537: }
538: if (ltries == 0)
539: continue;
540:
541:
542: /* Send layout request */
543: zskbd_putc(zst, SKBD_CMD_LAYOUT);
544:
545: ltries = 1000;
546: while (--ltries > 0) {
547: rr0 = *cs->cs_reg_csr;
548: if (rr0 & ZSRR0_RX_READY) {
549: sunkbd_raw(ss, *cs->cs_reg_data);
550: if (ss->sc_layout != -1)
551: break;
552: }
553: DELAY(1000);
554: }
555: if (ltries == 0)
556: continue;
557: break;
558: }
559: if (tries == 0)
560: printf(": no keyboard\n");
561: else
562: printf(": layout %d\n", ss->sc_layout);
563: splx(s);
564:
565: return tries;
566: }
567:
568: void
569: zskbd_putc(zst, c)
570: struct zskbd_softc *zst;
571: u_int8_t c;
572: {
573: u_int8_t rr0;
574: int s;
575:
576: s = splhigh();
577: do {
578: rr0 = *zst->zst_cs->cs_reg_csr;
579: } while ((rr0 & ZSRR0_TX_READY) == 0);
580: *zst->zst_cs->cs_reg_data = c;
581: delay(2);
582: splx(s);
583: }
584:
585: int
586: zsenqueue_tx(v, str, len)
587: void *v;
588: u_int8_t *str;
589: u_int len;
590: {
591: struct zskbd_softc *zst = v;
592: int s;
593: u_int i;
594:
595: s = splzs();
596: if (zst->zst_tbc + len > ZSKBD_RING_SIZE)
597: return (-1);
598: zst->zst_tbc += len;
599: for (i = 0; i < len; i++) {
600: *zst->zst_tbp = str[i];
601: if (++zst->zst_tbp == zst->zst_tend)
602: zst->zst_tbp = zst->zst_tbeg;
603: }
604: splx(s);
605: zsstart_tx(zst);
606: return (0);
607: }
608:
609: void
610: zsstart_tx(zst)
611: struct zskbd_softc *zst;
612: {
613: struct zs_chanstate *cs = zst->zst_cs;
614: int s, s1;
615:
616: s = spltty();
617:
618: if (zst->zst_tx_stopped)
619: goto out;
620: if (zst->zst_tbc == 0)
621: goto out;
622:
623: s1 = splzs();
624:
625: zst->zst_tx_busy = 1;
626:
627: if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
628: SET(cs->cs_preg[1], ZSWR1_TIE);
629: cs->cs_creg[1] = cs->cs_preg[1];
630: zs_write_reg(cs, 1, cs->cs_creg[1]);
631: }
632:
633: zs_write_data(cs, *zst->zst_tba);
634:
635: zst->zst_tbc--;
636: if (++zst->zst_tba == zst->zst_tend)
637: zst->zst_tba = zst->zst_tbeg;
638:
639: splx(s1);
640:
641: out:
642: splx(s);
643: }
644:
645: /*
646: * Compute interrupt enable bits and set in the pending bits. Called both
647: * in zsparam() and when PPS (pulse per second timing) state changes.
648: * Must be called at splzs().
649: */
650: static void
651: zs_maskintr(zst)
652: struct zskbd_softc *zst;
653: {
654: struct zs_chanstate *cs = zst->zst_cs;
655: int tmp15;
656:
657: cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd;
658: if (zst->zst_ppsmask != 0)
659: cs->cs_rr0_mask |= cs->cs_rr0_pps;
660: tmp15 = cs->cs_preg[15];
661: if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD))
662: SET(tmp15, ZSWR15_DCD_IE);
663: else
664: CLR(tmp15, ZSWR15_DCD_IE);
665: if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS))
666: SET(tmp15, ZSWR15_CTS_IE);
667: else
668: CLR(tmp15, ZSWR15_CTS_IE);
669: cs->cs_preg[15] = tmp15;
670: }
671:
672:
673: /*
674: * Raise or lower modem control (DTR/RTS) signals. If a character is
675: * in transmission, the change is deferred.
676: */
677: static void
678: zs_modem(zst, onoff)
679: struct zskbd_softc *zst;
680: int onoff;
681: {
682: struct zs_chanstate *cs = zst->zst_cs;
683:
684: if (cs->cs_wr5_dtr == 0)
685: return;
686:
687: if (onoff)
688: SET(cs->cs_preg[5], cs->cs_wr5_dtr);
689: else
690: CLR(cs->cs_preg[5], cs->cs_wr5_dtr);
691:
692: if (!cs->cs_heldchange) {
693: if (zst->zst_tx_busy) {
694: zst->zst_heldtbc = zst->zst_tbc;
695: zst->zst_tbc = 0;
696: cs->cs_heldchange = 1;
697: } else
698: zs_loadchannelregs(cs);
699: }
700: }
701:
702: /*
703: * Internal version of zshwiflow
704: * called at splzs
705: */
706: static void
707: zs_hwiflow(zst)
708: struct zskbd_softc *zst;
709: {
710: struct zs_chanstate *cs = zst->zst_cs;
711:
712: if (cs->cs_wr5_rts == 0)
713: return;
714:
715: if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) {
716: CLR(cs->cs_preg[5], cs->cs_wr5_rts);
717: CLR(cs->cs_creg[5], cs->cs_wr5_rts);
718: } else {
719: SET(cs->cs_preg[5], cs->cs_wr5_rts);
720: SET(cs->cs_creg[5], cs->cs_wr5_rts);
721: }
722: zs_write_reg(cs, 5, cs->cs_creg[5]);
723: }
724:
725:
726: /****************************************************************
727: * Interface to the lower layer (zscc)
728: ****************************************************************/
729:
730: #define integrate
731: integrate void zskbd_rxsoft(struct zskbd_softc *);
732: integrate void zskbd_txsoft(struct zskbd_softc *);
733: integrate void zskbd_stsoft(struct zskbd_softc *);
734: /*
735: * receiver ready interrupt.
736: * called at splzs
737: */
738: static void
739: zskbd_rxint(cs)
740: struct zs_chanstate *cs;
741: {
742: struct zskbd_softc *zst = cs->cs_private;
743: u_char *put, *end;
744: u_int cc;
745: u_char rr0, rr1, c;
746:
747: end = zst->zst_ebuf;
748: put = zst->zst_rbput;
749: cc = zst->zst_rbavail;
750:
751: while (cc > 0) {
752: /*
753: * First read the status, because reading the received char
754: * destroys the status of this char.
755: */
756: rr1 = zs_read_reg(cs, 1);
757: c = zs_read_data(cs);
758:
759: if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
760: /* Clear the receive error. */
761: zs_write_csr(cs, ZSWR0_RESET_ERRORS);
762: }
763:
764: put[0] = c;
765: put[1] = rr1;
766: put += 2;
767: if (put >= end)
768: put = zst->zst_rbuf;
769: cc--;
770:
771: rr0 = zs_read_csr(cs);
772: if (!ISSET(rr0, ZSRR0_RX_READY))
773: break;
774: }
775:
776: /*
777: * Current string of incoming characters ended because
778: * no more data was available or we ran out of space.
779: * Schedule a receive event if any data was received.
780: * If we're out of space, turn off receive interrupts.
781: */
782: zst->zst_rbput = put;
783: zst->zst_rbavail = cc;
784: if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) {
785: zst->zst_rx_ready = 1;
786: cs->cs_softreq = 1;
787: }
788:
789: /*
790: * See if we are in danger of overflowing a buffer. If
791: * so, use hardware flow control to ease the pressure.
792: */
793: if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) &&
794: cc < zst->zst_r_hiwat) {
795: SET(zst->zst_rx_flags, RX_IBUF_BLOCKED);
796: zs_hwiflow(zst);
797: }
798:
799: /*
800: * If we're out of space, disable receive interrupts
801: * until the queue has drained a bit.
802: */
803: if (!cc) {
804: SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
805: CLR(cs->cs_preg[1], ZSWR1_RIE);
806: cs->cs_creg[1] = cs->cs_preg[1];
807: zs_write_reg(cs, 1, cs->cs_creg[1]);
808: }
809: }
810:
811: /*
812: * transmitter ready interrupt. (splzs)
813: */
814: static void
815: zskbd_txint(cs)
816: struct zs_chanstate *cs;
817: {
818: struct zskbd_softc *zst = cs->cs_private;
819:
820: /*
821: * If we've delayed a parameter change, do it now, and restart
822: * output.
823: */
824: if (cs->cs_heldchange) {
825: zs_loadchannelregs(cs);
826: cs->cs_heldchange = 0;
827: zst->zst_tbc = zst->zst_heldtbc;
828: zst->zst_heldtbc = 0;
829: }
830:
831: /* Output the next character in the buffer, if any. */
832: if (zst->zst_tbc > 0) {
833: zs_write_data(cs, *zst->zst_tba);
834: zst->zst_tbc--;
835: if (++zst->zst_tba == zst->zst_tend)
836: zst->zst_tba = zst->zst_tbeg;
837: } else {
838: /* Disable transmit completion interrupts if necessary. */
839: if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
840: CLR(cs->cs_preg[1], ZSWR1_TIE);
841: cs->cs_creg[1] = cs->cs_preg[1];
842: zs_write_reg(cs, 1, cs->cs_creg[1]);
843: }
844: if (zst->zst_tx_busy) {
845: zst->zst_tx_busy = 0;
846: zst->zst_tx_done = 1;
847: cs->cs_softreq = 1;
848: }
849: }
850: }
851:
852: /*
853: * status change interrupt. (splzs)
854: */
855: static void
856: zskbd_stint(cs, force)
857: struct zs_chanstate *cs;
858: int force;
859: {
860: struct zskbd_softc *zst = cs->cs_private;
861: u_char rr0, delta;
862:
863: rr0 = zs_read_csr(cs);
864: zs_write_csr(cs, ZSWR0_RESET_STATUS);
865:
866: /*
867: * Check here for console break, so that we can abort
868: * even when interrupts are locking up the machine.
869: */
870: if (!force)
871: delta = rr0 ^ cs->cs_rr0;
872: else
873: delta = cs->cs_rr0_mask;
874: cs->cs_rr0 = rr0;
875:
876: if (ISSET(delta, cs->cs_rr0_mask)) {
877: SET(cs->cs_rr0_delta, delta);
878:
879: /*
880: * Stop output immediately if we lose the output
881: * flow control signal or carrier detect.
882: */
883: if (ISSET(~rr0, cs->cs_rr0_mask)) {
884: zst->zst_tbc = 0;
885: zst->zst_heldtbc = 0;
886: }
887:
888: zst->zst_st_check = 1;
889: cs->cs_softreq = 1;
890: }
891: }
892:
893: void
894: zskbd_diag(arg)
895: void *arg;
896: {
897: struct zskbd_softc *zst = arg;
898: struct sunkbd_softc *ss = arg;
899: int overflows, floods;
900: int s;
901:
902: s = splzs();
903: overflows = zst->zst_overflows;
904: zst->zst_overflows = 0;
905: floods = zst->zst_floods;
906: zst->zst_floods = 0;
907: zst->zst_errors = 0;
908: splx(s);
909:
910: log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
911: ss->sc_dev.dv_xname,
912: overflows, overflows == 1 ? "" : "s",
913: floods, floods == 1 ? "" : "s");
914: }
915:
916: integrate void
917: zskbd_rxsoft(zst)
918: struct zskbd_softc *zst;
919: {
920: struct sunkbd_softc *ss = (void *)zst;
921: struct zs_chanstate *cs = zst->zst_cs;
922: u_char *get, *end;
923: u_int cc, scc, type;
924: u_char rr1;
925: int code, value;
926: int s;
927:
928: end = zst->zst_ebuf;
929: get = zst->zst_rbget;
930: scc = cc = zskbd_rbuf_size - zst->zst_rbavail;
931:
932: if (cc == zskbd_rbuf_size) {
933: zst->zst_floods++;
934: if (zst->zst_errors++ == 0)
935: timeout_add(&zst->zst_diag_ch, 60 * hz);
936: }
937:
938: while (cc) {
939: code = get[0];
940: rr1 = get[1];
941: if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) {
942: if (ISSET(rr1, ZSRR1_DO)) {
943: zst->zst_overflows++;
944: if (zst->zst_errors++ == 0)
945: timeout_add(&zst->zst_diag_ch, 60 * hz);
946: }
947: if (ISSET(rr1, ZSRR1_FE))
948: SET(code, TTY_FE);
949: if (ISSET(rr1, ZSRR1_PE))
950: SET(code, TTY_PE);
951: }
952:
953: sunkbd_decode(code, &type, &value);
954: wskbd_input(ss->sc_wskbddev, type, value);
955:
956: get += 2;
957: if (get >= end)
958: get = zst->zst_rbuf;
959: cc--;
960: }
961:
962: if (cc != scc) {
963: zst->zst_rbget = get;
964: s = splzs();
965: cc = zst->zst_rbavail += scc - cc;
966: /* Buffers should be ok again, release possible block. */
967: if (cc >= zst->zst_r_lowat) {
968: if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) {
969: CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED);
970: SET(cs->cs_preg[1], ZSWR1_RIE);
971: cs->cs_creg[1] = cs->cs_preg[1];
972: zs_write_reg(cs, 1, cs->cs_creg[1]);
973: }
974: if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) {
975: CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED);
976: zs_hwiflow(zst);
977: }
978: }
979: splx(s);
980: }
981: }
982:
983: integrate void
984: zskbd_txsoft(zst)
985: struct zskbd_softc *zst;
986: {
987: }
988:
989: integrate void
990: zskbd_stsoft(zst)
991: struct zskbd_softc *zst;
992: {
993: struct zs_chanstate *cs = zst->zst_cs;
994: u_char rr0, delta;
995: int s;
996:
997: s = splzs();
998: rr0 = cs->cs_rr0;
999: delta = cs->cs_rr0_delta;
1000: cs->cs_rr0_delta = 0;
1001: splx(s);
1002:
1003: if (ISSET(delta, cs->cs_rr0_cts)) {
1004: /* Block or unblock output according to flow control. */
1005: if (ISSET(rr0, cs->cs_rr0_cts))
1006: zst->zst_tx_stopped = 0;
1007: else
1008: zst->zst_tx_stopped = 1;
1009: }
1010: }
1011:
1012: /*
1013: * Software interrupt. Called at zssoft
1014: *
1015: * The main job to be done here is to empty the input ring
1016: * by passing its contents up to the tty layer. The ring is
1017: * always emptied during this operation, therefore the ring
1018: * must not be larger than the space after "high water" in
1019: * the tty layer, or the tty layer might drop our input.
1020: *
1021: * Note: an "input blockage" condition is assumed to exist if
1022: * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
1023: */
1024: static void
1025: zskbd_softint(cs)
1026: struct zs_chanstate *cs;
1027: {
1028: struct zskbd_softc *zst = cs->cs_private;
1029: int s;
1030:
1031: s = spltty();
1032:
1033: if (zst->zst_rx_ready) {
1034: zst->zst_rx_ready = 0;
1035: zskbd_rxsoft(zst);
1036: }
1037:
1038: if (zst->zst_st_check) {
1039: zst->zst_st_check = 0;
1040: zskbd_stsoft(zst);
1041: }
1042:
1043: if (zst->zst_tx_done) {
1044: zst->zst_tx_done = 0;
1045: zskbd_txsoft(zst);
1046: }
1047:
1048: splx(s);
1049: }
1050:
1051: struct zsops zsops_kbd = {
1052: zskbd_rxint, /* receive char available */
1053: zskbd_stint, /* external/status */
1054: zskbd_txint, /* xmit buffer empty */
1055: zskbd_softint, /* process software interrupt */
1056: };
1057:
1058: void
1059: zskbd_cnpollc(v, on)
1060: void *v;
1061: int on;
1062: {
1063: extern int swallow_zsintrs;
1064:
1065: if (on)
1066: swallow_zsintrs++;
1067: else
1068: swallow_zsintrs--;
1069: }
1070:
1071: void
1072: zskbd_cngetc(v, type, data)
1073: void *v;
1074: u_int *type;
1075: int *data;
1076: {
1077: struct zskbd_softc *zst = v;
1078: int s;
1079: u_int8_t c, rr0;
1080:
1081: s = splhigh();
1082: do {
1083: rr0 = *zst->zst_cs->cs_reg_csr;
1084: } while ((rr0 & ZSRR0_RX_READY) == 0);
1085:
1086: c = *zst->zst_cs->cs_reg_data;
1087: splx(s);
1088:
1089: switch (c) {
1090: case SKBD_RSP_IDLE:
1091: *type = WSCONS_EVENT_ALL_KEYS_UP;
1092: *data = 0;
1093: break;
1094: default:
1095: *type = (c & 0x80) ?
1096: WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
1097: *data = c & 0x7f;
1098: break;
1099: }
1100: }
CVSweb