Annotation of sys/arch/sparc64/dev/z8530kbd.c, Revision 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