Annotation of sys/arch/sparc64/dev/comkbd_ebus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: comkbd_ebus.c,v 1.18 2005/11/11 16:44:51 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 26: * POSSIBILITY OF SUCH DAMAGE.
! 27: *
! 28: * Effort sponsored in part by the Defense Advanced Research Projects
! 29: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 30: * Materiel Command, USAF, under agreement number F30602-01-2-0537.
! 31: *
! 32: */
! 33:
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/proc.h>
! 37: #include <sys/device.h>
! 38: #include <sys/conf.h>
! 39: #include <sys/file.h>
! 40: #include <sys/ioctl.h>
! 41: #include <sys/malloc.h>
! 42: #include <sys/tty.h>
! 43: #include <sys/time.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/syslog.h>
! 46:
! 47: #include <machine/bus.h>
! 48: #include <machine/autoconf.h>
! 49: #include <machine/openfirm.h>
! 50:
! 51: #include <sparc64/dev/ebusreg.h>
! 52: #include <sparc64/dev/ebusvar.h>
! 53:
! 54: #include <dev/wscons/wsconsio.h>
! 55: #include <dev/wscons/wskbdvar.h>
! 56:
! 57: #include <dev/sun/sunkbdreg.h>
! 58: #include <dev/sun/sunkbdvar.h>
! 59:
! 60: #include <dev/ic/comreg.h>
! 61: #include <dev/ic/comvar.h>
! 62: #include <dev/ic/ns16550reg.h>
! 63:
! 64: #include <dev/cons.h>
! 65:
! 66: #define COMK_RX_RING 64
! 67: #define COMK_TX_RING 64
! 68:
! 69: struct comkbd_softc {
! 70: struct sunkbd_softc sc_base;
! 71:
! 72: bus_space_tag_t sc_iot; /* bus tag */
! 73: bus_space_handle_t sc_ioh; /* bus handle */
! 74: void *sc_ih, *sc_si; /* interrupt vectors */
! 75:
! 76: u_int sc_rxcnt;
! 77: u_int8_t sc_rxbuf[COMK_RX_RING];
! 78: u_int8_t *sc_rxbeg, *sc_rxend, *sc_rxget, *sc_rxput;
! 79:
! 80: u_int sc_txcnt;
! 81: u_int8_t sc_txbuf[COMK_TX_RING];
! 82: u_int8_t *sc_txbeg, *sc_txend, *sc_txget, *sc_txput;
! 83:
! 84: u_int8_t sc_ier;
! 85: };
! 86:
! 87: #define COM_WRITE(sc,r,v) \
! 88: bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
! 89: #define COM_READ(sc,r) \
! 90: bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (r))
! 91:
! 92: int comkbd_match(struct device *, void *, void *);
! 93: void comkbd_attach(struct device *, struct device *, void *);
! 94: int comkbd_iskbd(int);
! 95:
! 96: /* wskbd glue */
! 97: void comkbd_cnpollc(void *, int);
! 98: void comkbd_cngetc(void *, u_int *, int *);
! 99:
! 100: /* internals */
! 101: int comkbd_enqueue(void *, u_int8_t *, u_int);
! 102: int comkbd_init(struct comkbd_softc *);
! 103: void comkbd_putc(struct comkbd_softc *, u_int8_t);
! 104: int comkbd_intr(void *);
! 105: void comkbd_soft(void *);
! 106:
! 107: struct cfattach comkbd_ca = {
! 108: sizeof(struct comkbd_softc), comkbd_match, comkbd_attach
! 109: };
! 110:
! 111: struct cfdriver comkbd_cd = {
! 112: NULL, "comkbd", DV_DULL
! 113: };
! 114:
! 115: const char *comkbd_names[] = {
! 116: "su",
! 117: "su_pnp",
! 118: NULL
! 119: };
! 120:
! 121: struct wskbd_consops comkbd_consops = {
! 122: comkbd_cngetc,
! 123: comkbd_cnpollc
! 124: };
! 125:
! 126: int
! 127: comkbd_iskbd(node)
! 128: int node;
! 129: {
! 130: if (OF_getproplen(node, "keyboard") == 0)
! 131: return (10);
! 132: return (0);
! 133: }
! 134:
! 135: int
! 136: comkbd_match(parent, match, aux)
! 137: struct device *parent;
! 138: void *match;
! 139: void *aux;
! 140: {
! 141: struct ebus_attach_args *ea = aux;
! 142: int i;
! 143:
! 144: for (i = 0; comkbd_names[i]; i++)
! 145: if (strcmp(ea->ea_name, comkbd_names[i]) == 0)
! 146: return (comkbd_iskbd(ea->ea_node));
! 147:
! 148: if (strcmp(ea->ea_name, "serial") == 0) {
! 149: char compat[80];
! 150:
! 151: if ((i = OF_getproplen(ea->ea_node, "compatible")) &&
! 152: OF_getprop(ea->ea_node, "compatible", compat,
! 153: sizeof(compat)) == i) {
! 154: if (strcmp(compat, "su16550") == 0 ||
! 155: strcmp(compat, "su") == 0)
! 156: return (comkbd_iskbd(ea->ea_node));
! 157: }
! 158: }
! 159: return (0);
! 160: }
! 161:
! 162: void
! 163: comkbd_attach(parent, self, aux)
! 164: struct device *parent, *self;
! 165: void *aux;
! 166: {
! 167: struct comkbd_softc *sc = (void *)self;
! 168: struct sunkbd_softc *ss = (void *)sc;
! 169: struct ebus_attach_args *ea = aux;
! 170: struct wskbddev_attach_args a;
! 171: int console;
! 172:
! 173: ss->sc_sendcmd = comkbd_enqueue;
! 174: timeout_set(&ss->sc_bellto, sunkbd_bellstop, sc);
! 175:
! 176: sc->sc_iot = ea->ea_memtag;
! 177:
! 178: sc->sc_rxget = sc->sc_rxput = sc->sc_rxbeg = sc->sc_rxbuf;
! 179: sc->sc_rxend = sc->sc_rxbuf + COMK_RX_RING;
! 180: sc->sc_rxcnt = 0;
! 181:
! 182: sc->sc_txget = sc->sc_txput = sc->sc_txbeg = sc->sc_txbuf;
! 183: sc->sc_txend = sc->sc_txbuf + COMK_TX_RING;
! 184: sc->sc_txcnt = 0;
! 185:
! 186: console = (ea->ea_node == OF_instance_to_package(OF_stdin()));
! 187:
! 188: sc->sc_si = softintr_establish(IPL_TTY, comkbd_soft, sc);
! 189: if (sc->sc_si == NULL) {
! 190: printf(": can't get soft intr\n");
! 191: return;
! 192: }
! 193:
! 194: /* Use prom address if available, otherwise map it. */
! 195: if (ea->ea_nvaddrs && bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
! 196: BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) == 0) {
! 197: sc->sc_iot = ea->ea_memtag;
! 198: } else if (ebus_bus_map(ea->ea_memtag, 0,
! 199: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
! 200: ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
! 201: sc->sc_iot = ea->ea_memtag;
! 202: } else if (ebus_bus_map(ea->ea_iotag, 0,
! 203: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
! 204: ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
! 205: sc->sc_iot = ea->ea_iotag;
! 206: } else {
! 207: printf(": can't map register space\n");
! 208: return;
! 209: }
! 210:
! 211: sc->sc_ih = bus_intr_establish(sc->sc_iot,
! 212: ea->ea_intrs[0], IPL_TTY, 0, comkbd_intr, sc, self->dv_xname);
! 213: if (sc->sc_ih == NULL) {
! 214: printf(": can't get hard intr\n");
! 215: return;
! 216: }
! 217:
! 218: if (comkbd_init(sc) == 0) {
! 219: return;
! 220: }
! 221:
! 222: ss->sc_click =
! 223: strcmp(getpropstring(optionsnode, "keyboard-click?"), "true") == 0;
! 224: sunkbd_setclick(ss, ss->sc_click);
! 225:
! 226: a.console = console;
! 227: if (ISTYPE5(ss->sc_layout)) {
! 228: a.keymap = &sunkbd5_keymapdata;
! 229: #ifndef SUNKBD5_LAYOUT
! 230: if (ss->sc_layout < MAXSUNLAYOUT &&
! 231: sunkbd_layouts[ss->sc_layout] != -1)
! 232: sunkbd5_keymapdata.layout =
! 233: sunkbd_layouts[ss->sc_layout];
! 234: #endif
! 235: } else {
! 236: a.keymap = &sunkbd_keymapdata;
! 237: #ifndef SUNKBD_LAYOUT
! 238: if (ss->sc_layout < MAXSUNLAYOUT &&
! 239: sunkbd_layouts[ss->sc_layout] != -1)
! 240: sunkbd_keymapdata.layout =
! 241: sunkbd_layouts[ss->sc_layout];
! 242: #endif
! 243: }
! 244: a.accessops = &sunkbd_accessops;
! 245: a.accesscookie = sc;
! 246:
! 247: if (console) {
! 248: cn_tab->cn_dev = makedev(77, ss->sc_dev.dv_unit); /* XXX */
! 249: cn_tab->cn_pollc = wskbd_cnpollc;
! 250: cn_tab->cn_getc = wskbd_cngetc;
! 251: wskbd_cnattach(&comkbd_consops, sc, a.keymap);
! 252: sc->sc_ier = IER_ETXRDY | IER_ERXRDY;
! 253: COM_WRITE(sc, com_ier, sc->sc_ier);
! 254: COM_READ(sc, com_iir);
! 255: COM_WRITE(sc, com_mcr, MCR_IENABLE | MCR_DTR | MCR_RTS);
! 256: }
! 257:
! 258: ss->sc_wskbddev = config_found(self, &a, wskbddevprint);
! 259: }
! 260:
! 261: void
! 262: comkbd_cnpollc(vsc, on)
! 263: void *vsc;
! 264: int on;
! 265: {
! 266: }
! 267:
! 268: void
! 269: comkbd_cngetc(v, type, data)
! 270: void *v;
! 271: u_int *type;
! 272: int *data;
! 273: {
! 274: struct comkbd_softc *sc = v;
! 275: int s;
! 276: u_int8_t c;
! 277:
! 278: s = splhigh();
! 279: while (1) {
! 280: if (COM_READ(sc, com_lsr) & LSR_RXRDY)
! 281: break;
! 282: }
! 283: c = COM_READ(sc, com_data);
! 284: COM_READ(sc, com_iir);
! 285: splx(s);
! 286:
! 287: sunkbd_decode(c, type, data);
! 288: }
! 289:
! 290: void
! 291: comkbd_putc(sc, c)
! 292: struct comkbd_softc *sc;
! 293: u_int8_t c;
! 294: {
! 295: int s, timo;
! 296:
! 297: s = splhigh();
! 298:
! 299: timo = 150000;
! 300: while (--timo) {
! 301: if (COM_READ(sc, com_lsr) & LSR_TXRDY)
! 302: break;
! 303: }
! 304:
! 305: COM_WRITE(sc, com_data, c);
! 306: bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, COM_NPORTS,
! 307: BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
! 308:
! 309: timo = 150000;
! 310: while (--timo) {
! 311: if (COM_READ(sc, com_lsr) & LSR_TXRDY)
! 312: break;
! 313: }
! 314:
! 315: splx(s);
! 316: }
! 317:
! 318: int
! 319: comkbd_enqueue(v, buf, buflen)
! 320: void *v;
! 321: u_int8_t *buf;
! 322: u_int buflen;
! 323: {
! 324: struct comkbd_softc *sc = v;
! 325: int s;
! 326: u_int i;
! 327:
! 328: s = spltty();
! 329:
! 330: /* See if there is room... */
! 331: if ((sc->sc_txcnt + buflen) > COMK_TX_RING) {
! 332: splx(s);
! 333: return (-1);
! 334: }
! 335:
! 336: for (i = 0; i < buflen; i++) {
! 337: *sc->sc_txget = *buf;
! 338: buf++;
! 339: sc->sc_txcnt++;
! 340: sc->sc_txget++;
! 341: if (sc->sc_txget == sc->sc_txend)
! 342: sc->sc_txget = sc->sc_txbeg;
! 343: }
! 344:
! 345: comkbd_soft(sc);
! 346:
! 347: splx(s);
! 348: return (0);
! 349: }
! 350:
! 351: void
! 352: comkbd_soft(vsc)
! 353: void *vsc;
! 354: {
! 355: struct comkbd_softc *sc = vsc;
! 356: struct sunkbd_softc *ss = (void *)sc;
! 357: u_int type;
! 358: int value;
! 359: u_int8_t c;
! 360:
! 361: while (sc->sc_rxcnt) {
! 362: c = *sc->sc_rxget;
! 363: if (++sc->sc_rxget == sc->sc_rxend)
! 364: sc->sc_rxget = sc->sc_rxbeg;
! 365: sc->sc_rxcnt--;
! 366: sunkbd_decode(c, &type, &value);
! 367: wskbd_input(ss->sc_wskbddev, type, value);
! 368: }
! 369:
! 370: if (sc->sc_txcnt) {
! 371: c = sc->sc_ier | IER_ETXRDY;
! 372: if (c != sc->sc_ier) {
! 373: COM_WRITE(sc, com_ier, c);
! 374: sc->sc_ier = c;
! 375: }
! 376: if (COM_READ(sc, com_lsr) & LSR_TXRDY) {
! 377: sc->sc_txcnt--;
! 378: COM_WRITE(sc, com_data, *sc->sc_txput);
! 379: if (++sc->sc_txput == sc->sc_txend)
! 380: sc->sc_txput = sc->sc_txbeg;
! 381: }
! 382: }
! 383: }
! 384:
! 385: int
! 386: comkbd_intr(vsc)
! 387: void *vsc;
! 388: {
! 389: struct comkbd_softc *sc = vsc;
! 390: u_int8_t iir, lsr, data;
! 391: int needsoft = 0;
! 392:
! 393: /* Nothing to do */
! 394: iir = COM_READ(sc, com_iir);
! 395: if (iir & IIR_NOPEND)
! 396: return (0);
! 397:
! 398: for (;;) {
! 399: lsr = COM_READ(sc, com_lsr);
! 400: if (lsr & LSR_RXRDY) {
! 401: needsoft = 1;
! 402:
! 403: do {
! 404: data = COM_READ(sc, com_data);
! 405: if (sc->sc_rxcnt != COMK_RX_RING) {
! 406: *sc->sc_rxput = data;
! 407: if (++sc->sc_rxput == sc->sc_rxend)
! 408: sc->sc_rxput = sc->sc_rxbeg;
! 409: sc->sc_rxcnt++;
! 410: }
! 411: lsr = COM_READ(sc, com_lsr);
! 412: } while (lsr & LSR_RXRDY);
! 413: }
! 414:
! 415: if (lsr & LSR_TXRDY) {
! 416: if (sc->sc_txcnt == 0) {
! 417: /* Nothing further to send */
! 418: sc->sc_ier &= ~IER_ETXRDY;
! 419: COM_WRITE(sc, com_ier, sc->sc_ier);
! 420: } else
! 421: needsoft = 1;
! 422: }
! 423:
! 424: iir = COM_READ(sc, com_iir);
! 425: if (iir & IIR_NOPEND)
! 426: break;
! 427: }
! 428:
! 429: if (needsoft)
! 430: softintr_schedule(sc->sc_si);
! 431:
! 432: return (1);
! 433: }
! 434:
! 435: int
! 436: comkbd_init(sc)
! 437: struct comkbd_softc *sc;
! 438: {
! 439: struct sunkbd_softc *ss = (void *)sc;
! 440: u_int8_t stat, c;
! 441: int tries;
! 442:
! 443: for (tries = 5; tries != 0; tries--) {
! 444: int ltries;
! 445:
! 446: ss->sc_leds = 0;
! 447: ss->sc_layout = -1;
! 448:
! 449: /* Send reset request */
! 450: comkbd_putc(sc, SKBD_CMD_RESET);
! 451:
! 452: ltries = 1000;
! 453: while (--ltries > 0) {
! 454: stat = COM_READ(sc,com_lsr);
! 455: if (stat & LSR_RXRDY) {
! 456: c = COM_READ(sc, com_data);
! 457:
! 458: sunkbd_raw(ss, c);
! 459: if (ss->sc_kbdstate == SKBD_STATE_RESET)
! 460: break;
! 461: }
! 462: DELAY(1000);
! 463: }
! 464: if (ltries == 0)
! 465: continue;
! 466:
! 467: /* Wait for reset to finish. */
! 468: ltries = 1000;
! 469: while (--ltries > 0) {
! 470: stat = COM_READ(sc, com_lsr);
! 471: if (stat & LSR_RXRDY) {
! 472: c = COM_READ(sc, com_data);
! 473: sunkbd_raw(ss, c);
! 474: if (ss->sc_kbdstate == SKBD_STATE_GETKEY)
! 475: break;
! 476: }
! 477: DELAY(1000);
! 478: }
! 479: if (ltries == 0)
! 480: continue;
! 481:
! 482:
! 483: /* Send layout request */
! 484: comkbd_putc(sc, SKBD_CMD_LAYOUT);
! 485:
! 486: ltries = 1000;
! 487: while (--ltries > 0) {
! 488: stat = COM_READ(sc, com_lsr);
! 489: if (stat & LSR_RXRDY) {
! 490: c = COM_READ(sc, com_data);
! 491: sunkbd_raw(ss, c);
! 492: if (ss->sc_layout != -1)
! 493: break;
! 494: }
! 495: DELAY(1000);
! 496: }
! 497: if (ltries != 0)
! 498: break;
! 499: }
! 500: if (tries == 0)
! 501: printf(": no keyboard\n");
! 502: else
! 503: printf(": layout %d\n", ss->sc_layout);
! 504:
! 505: return tries;
! 506: }
CVSweb