Annotation of sys/dev/hil/hil.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hil.c,v 1.23 2006/12/16 20:07:13 miod Exp $ */
! 2: /*
! 3: * Copyright (c) 2003, 2004, Miodrag Vallat.
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 23: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 25: * POSSIBILITY OF SUCH DAMAGE.
! 26: *
! 27: */
! 28:
! 29: /*
! 30: * Copyright (c) 1988 University of Utah.
! 31: * Copyright (c) 1990, 1993
! 32: * The Regents of the University of California. All rights reserved.
! 33: *
! 34: * This code is derived from software contributed to Berkeley by
! 35: * the Systems Programming Group of the University of Utah Computer
! 36: * Science Department.
! 37: *
! 38: * Redistribution and use in source and binary forms, with or without
! 39: * modification, are permitted provided that the following conditions
! 40: * are met:
! 41: * 1. Redistributions of source code must retain the above copyright
! 42: * notice, this list of conditions and the following disclaimer.
! 43: * 2. Redistributions in binary form must reproduce the above copyright
! 44: * notice, this list of conditions and the following disclaimer in the
! 45: * documentation and/or other materials provided with the distribution.
! 46: * 3. Neither the name of the University nor the names of its contributors
! 47: * may be used to endorse or promote products derived from this software
! 48: * without specific prior written permission.
! 49: *
! 50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 60: * SUCH DAMAGE.
! 61: *
! 62: * from: Utah $Hdr: hil.c 1.38 92/01/21$
! 63: *
! 64: * @(#)hil.c 8.2 (Berkeley) 1/12/94
! 65: */
! 66:
! 67: #include <sys/param.h>
! 68: #include <sys/systm.h>
! 69: #include <sys/conf.h>
! 70: #include <sys/device.h>
! 71: #include <sys/file.h>
! 72: #include <sys/ioctl.h>
! 73: #include <sys/kernel.h>
! 74: #include <sys/proc.h>
! 75: #include <sys/kthread.h>
! 76:
! 77: #include <machine/autoconf.h>
! 78: #include <machine/bus.h>
! 79: #include <machine/cpu.h>
! 80:
! 81: #include <dev/hil/hilreg.h>
! 82: #include <dev/hil/hilvar.h>
! 83: #include <dev/hil/hildevs.h>
! 84: #include <dev/hil/hildevs_data.h>
! 85:
! 86: #include "hilkbd.h"
! 87:
! 88: /*
! 89: * splhigh is extremely conservative but insures atomic operation,
! 90: * splvm (clock only interrupts) seems to be good enough in practice.
! 91: */
! 92: #define splhil splvm
! 93:
! 94: struct cfdriver hil_cd = {
! 95: NULL, "hil", DV_DULL
! 96: };
! 97:
! 98: void hilconfig(struct hil_softc *, u_int);
! 99: void hilempty(struct hil_softc *);
! 100: int hilsubmatch(struct device *, void *, void *);
! 101: void hil_process_int(struct hil_softc *, u_int8_t, u_int8_t);
! 102: int hil_process_poll(struct hil_softc *, u_int8_t, u_int8_t);
! 103: void hil_thread(void *);
! 104: int send_device_cmd(struct hil_softc *sc, u_int device, u_int cmd);
! 105: void polloff(struct hil_softc *);
! 106: void pollon(struct hil_softc *);
! 107:
! 108: static int hilwait(struct hil_softc *);
! 109: static int hildatawait(struct hil_softc *);
! 110:
! 111: #define hil_process_pending(sc) wakeup(&(sc)->sc_pending)
! 112:
! 113: static __inline int
! 114: hilwait(struct hil_softc *sc)
! 115: {
! 116: int cnt;
! 117:
! 118: for (cnt = 50000; cnt != 0; cnt--) {
! 119: DELAY(1);
! 120: if ((bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) &
! 121: HIL_BUSY) == 0)
! 122: break;
! 123: }
! 124:
! 125: return (cnt);
! 126: }
! 127:
! 128: static __inline int
! 129: hildatawait(struct hil_softc *sc)
! 130: {
! 131: int cnt;
! 132:
! 133: for (cnt = 50000; cnt != 0; cnt--) {
! 134: DELAY(1);
! 135: if ((bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) &
! 136: HIL_DATA_RDY) != 0)
! 137: break;
! 138: }
! 139:
! 140: return (cnt);
! 141: }
! 142:
! 143: /*
! 144: * Common HIL bus attachment
! 145: */
! 146:
! 147: void
! 148: hil_attach(struct hil_softc *sc, int *hil_is_console)
! 149: {
! 150: printf("\n");
! 151:
! 152: /*
! 153: * Initialize loop information
! 154: */
! 155: sc->sc_cmdending = 0;
! 156: sc->sc_actdev = sc->sc_cmddev = 0;
! 157: sc->sc_cmddone = 0;
! 158: sc->sc_cmdbp = sc->sc_cmdbuf;
! 159: sc->sc_pollbp = sc->sc_pollbuf;
! 160: sc->sc_console = hil_is_console;
! 161: }
! 162:
! 163: /*
! 164: * HIL subdevice attachment
! 165: */
! 166:
! 167: int
! 168: hildevprint(void *aux, const char *pnp)
! 169: {
! 170: struct hil_attach_args *ha = aux;
! 171:
! 172: if (pnp != NULL) {
! 173: printf("\"%s\" at %s id %x",
! 174: ha->ha_descr, pnp, ha->ha_id);
! 175: }
! 176: printf(" code %d", ha->ha_code);
! 177: if (pnp == NULL) {
! 178: printf(": %s", ha->ha_descr);
! 179: }
! 180:
! 181: return (UNCONF);
! 182: }
! 183:
! 184: int
! 185: hilsubmatch(struct device *parent, void *vcf, void *aux)
! 186: {
! 187: struct hil_attach_args *ha = aux;
! 188: struct cfdata *cf = vcf;
! 189:
! 190: if (cf->cf_loc[0] != -1 &&
! 191: cf->cf_loc[0] != ha->ha_code)
! 192: return (0);
! 193:
! 194: return ((*cf->cf_attach->ca_match)(parent, vcf, aux));
! 195: }
! 196:
! 197: void
! 198: hil_attach_deferred(void *v)
! 199: {
! 200: struct hil_softc *sc = v;
! 201: int tries;
! 202: u_int8_t db;
! 203:
! 204: sc->sc_status = HIL_STATUS_BUSY;
! 205:
! 206: /*
! 207: * Initialize the loop: reconfigure, don't report errors,
! 208: * put keyboard in cooked mode, and enable autopolling.
! 209: */
! 210: db = LPC_RECONF | LPC_KBDCOOK | LPC_NOERROR | LPC_AUTOPOLL;
! 211: send_hil_cmd(sc, HIL_WRITELPCTRL, &db, 1, NULL);
! 212:
! 213: /*
! 214: * Delay one second for reconfiguration and then read the
! 215: * data to clear the interrupt (if the loop reconfigured).
! 216: */
! 217: DELAY(1000000);
! 218: if (bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) &
! 219: HIL_DATA_RDY) {
! 220: db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
! 221: DELAY(1);
! 222: }
! 223:
! 224: /*
! 225: * The HIL loop may have reconfigured. If so we proceed on,
! 226: * if not we loop a few times until a successful reconfiguration
! 227: * is reported back to us. If the HIL loop is still lost after a
! 228: * few seconds, give up.
! 229: */
! 230: for (tries = 10; tries != 0; tries--) {
! 231: if (send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db) == 0) {
! 232: if (db & (LPS_CONFFAIL | LPS_CONFGOOD))
! 233: break;
! 234: }
! 235:
! 236: #ifdef HILDEBUG
! 237: printf("%s: loop not ready, retrying...\n",
! 238: sc->sc_dev.dv_xname);
! 239: #endif
! 240:
! 241: DELAY(1000000);
! 242: }
! 243:
! 244: if (tries == 0 || (db & LPS_CONFFAIL)) {
! 245: printf("%s: no devices\n", sc->sc_dev.dv_xname);
! 246: sc->sc_pending = 0;
! 247: if (tries == 0)
! 248: return;
! 249: }
! 250:
! 251: /*
! 252: * Create asynchronous loop event handler thread.
! 253: */
! 254: if (kthread_create(hil_thread, sc, &sc->sc_thread,
! 255: "%s", sc->sc_dev.dv_xname) != 0) {
! 256: printf("%s: unable to create event thread\n",
! 257: sc->sc_dev.dv_xname);
! 258: return;
! 259: }
! 260:
! 261: /*
! 262: * Enable loop interrupts.
! 263: */
! 264: send_hil_cmd(sc, HIL_INTON, NULL, 0, NULL);
! 265:
! 266: /*
! 267: * Reconfigure if necessary
! 268: */
! 269: sc->sc_status = HIL_STATUS_READY;
! 270: hil_process_pending(sc);
! 271: }
! 272:
! 273: /*
! 274: * Asynchronous event processing
! 275: */
! 276:
! 277: int
! 278: hil_intr(void *v)
! 279: {
! 280: struct hil_softc *sc = v;
! 281: u_int8_t c, stat;
! 282:
! 283: if (cold)
! 284: return (0);
! 285:
! 286: stat = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT);
! 287:
! 288: /*
! 289: * This should never happen if the interrupt comes from the
! 290: * loop.
! 291: */
! 292: if ((stat & HIL_DATA_RDY) == 0)
! 293: return (0); /* not for us */
! 294:
! 295: c = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
! 296: HILP_DATA); /* clears interrupt */
! 297: DELAY(1);
! 298:
! 299: hil_process_int(sc, stat, c);
! 300:
! 301: if (sc->sc_status != HIL_STATUS_BUSY)
! 302: hil_process_pending(sc);
! 303:
! 304: return (1);
! 305: }
! 306:
! 307: void
! 308: hil_process_int(struct hil_softc *sc, u_int8_t stat, u_int8_t c)
! 309: {
! 310: struct hildev_softc *dev;
! 311:
! 312: switch ((stat >> HIL_SSHIFT) & HIL_SMASK) {
! 313: case HIL_STATUS:
! 314: if (c & HIL_ERROR) {
! 315: sc->sc_cmddone = 1;
! 316: switch (c) {
! 317: case HIL_RECONFIG:
! 318: sc->sc_pending = HIL_PENDING_RECONFIG;
! 319: break;
! 320: case HIL_UNPLUGGED:
! 321: sc->sc_pending = HIL_PENDING_UNPLUGGED;
! 322: break;
! 323: }
! 324: break;
! 325: }
! 326: if (c & HIL_COMMAND) {
! 327: if (c & HIL_POLLDATA) { /* End of data */
! 328: dev = sc->sc_devices[sc->sc_actdev];
! 329: if (dev != NULL && dev->sc_fn != NULL)
! 330: dev->sc_fn(dev,
! 331: sc->sc_pollbp - sc->sc_pollbuf,
! 332: sc->sc_pollbuf);
! 333: } else { /* End of command */
! 334: sc->sc_cmdending = 1;
! 335: }
! 336: sc->sc_actdev = 0;
! 337: } else {
! 338: if (c & HIL_POLLDATA) { /* Start of polled data */
! 339: sc->sc_actdev = (c & HIL_DEVMASK);
! 340: sc->sc_pollbp = sc->sc_pollbuf;
! 341: } else { /* Start of command */
! 342: if (sc->sc_cmddev == (c & HIL_DEVMASK)) {
! 343: sc->sc_cmdbp = sc->sc_cmdbuf;
! 344: sc->sc_actdev = 0;
! 345: }
! 346: }
! 347: }
! 348: break;
! 349: case HIL_DATA:
! 350: if (sc->sc_actdev != 0) /* Collecting poll data */
! 351: *sc->sc_pollbp++ = c;
! 352: else {
! 353: if (sc->sc_cmddev != 0) { /* Collecting cmd data */
! 354: if (sc->sc_cmdending) {
! 355: sc->sc_cmddone = 1;
! 356: sc->sc_cmdending = 0;
! 357: } else
! 358: *sc->sc_cmdbp++ = c;
! 359: }
! 360: }
! 361: break;
! 362: }
! 363: }
! 364:
! 365: /*
! 366: * Same as above, but in polled mode: return data as it gets seen, instead
! 367: * of buffering it.
! 368: */
! 369: int
! 370: hil_process_poll(struct hil_softc *sc, u_int8_t stat, u_int8_t c)
! 371: {
! 372: u_int8_t db;
! 373:
! 374: switch ((stat >> HIL_SSHIFT) & HIL_SMASK) {
! 375: case HIL_STATUS:
! 376: if (c & HIL_ERROR) {
! 377: sc->sc_cmddone = 1;
! 378: switch (c) {
! 379: case HIL_RECONFIG:
! 380: /*
! 381: * Remember that a configuration event
! 382: * occurred; it will be processed upon
! 383: * leaving polled mode...
! 384: */
! 385: sc->sc_pending = HIL_PENDING_RECONFIG;
! 386: /*
! 387: * However, the keyboard will come back as
! 388: * cooked, and we rely on it being in raw
! 389: * mode. So, put it back in raw mode right
! 390: * now.
! 391: */
! 392: db = 0;
! 393: send_hil_cmd(sc, HIL_WRITEKBDSADR, &db,
! 394: 1, NULL);
! 395: break;
! 396: case HIL_UNPLUGGED:
! 397: /*
! 398: * Remember that an unplugged event
! 399: * occured; it will be processed upon
! 400: * leaving polled mode...
! 401: */
! 402: sc->sc_pending = HIL_PENDING_UNPLUGGED;
! 403: break;
! 404: }
! 405: break;
! 406: }
! 407: if (c & HIL_COMMAND) {
! 408: if (!(c & HIL_POLLDATA)) {
! 409: /* End of command */
! 410: sc->sc_cmdending = 1;
! 411: }
! 412: sc->sc_actdev = 0;
! 413: } else {
! 414: if (c & HIL_POLLDATA) {
! 415: /* Start of polled data */
! 416: sc->sc_actdev = (c & HIL_DEVMASK);
! 417: sc->sc_pollbp = sc->sc_pollbuf;
! 418: } else {
! 419: /* Start of command - should not happen */
! 420: if (sc->sc_cmddev == (c & HIL_DEVMASK)) {
! 421: sc->sc_cmdbp = sc->sc_cmdbuf;
! 422: sc->sc_actdev = 0;
! 423: }
! 424: }
! 425: }
! 426: break;
! 427: case HIL_DATA:
! 428: if (sc->sc_actdev != 0) /* Collecting poll data */
! 429: return 1;
! 430: else {
! 431: if (sc->sc_cmddev != 0) { /* Discarding cmd data */
! 432: if (sc->sc_cmdending) {
! 433: sc->sc_cmddone = 1;
! 434: sc->sc_cmdending = 0;
! 435: }
! 436: }
! 437: }
! 438: break;
! 439: }
! 440:
! 441: return 0;
! 442: }
! 443:
! 444: void
! 445: hil_thread(void *arg)
! 446: {
! 447: struct hil_softc *sc = arg;
! 448: int s;
! 449:
! 450: for (;;) {
! 451: s = splhil();
! 452: if (sc->sc_pending == 0) {
! 453: splx(s);
! 454: (void)tsleep(&sc->sc_pending, PWAIT, "hil_event", 0);
! 455: continue;
! 456: }
! 457:
! 458: switch (sc->sc_pending) {
! 459: case HIL_PENDING_RECONFIG:
! 460: sc->sc_pending = 0;
! 461: hilconfig(sc, sc->sc_maxdev);
! 462: break;
! 463: case HIL_PENDING_UNPLUGGED:
! 464: sc->sc_pending = 0;
! 465: hilempty(sc);
! 466: break;
! 467: }
! 468: }
! 469: }
! 470:
! 471: /*
! 472: * Called after the loop has reconfigured. Here we need to:
! 473: * - determine how many devices are on the loop
! 474: * (some may have been added or removed)
! 475: * - make sure all keyboards are in raw mode
! 476: *
! 477: * Note that our device state is now potentially invalid as
! 478: * devices may no longer be where they were. What we should
! 479: * do here is either track where the devices went and move
! 480: * state around accordingly...
! 481: *
! 482: * Note that it is necessary that we operate the loop with the keyboards
! 483: * in raw mode: they won't cause the loop to generate an NMI if the
! 484: * ``reset'' key combination is pressed, and we do not handle the hil
! 485: * NMI interrupt...
! 486: */
! 487: void
! 488: hilconfig(struct hil_softc *sc, u_int knowndevs)
! 489: {
! 490: struct hil_attach_args ha;
! 491: u_int8_t db;
! 492: int id, s;
! 493:
! 494: s = splhil();
! 495:
! 496: /*
! 497: * Determine how many devices are on the loop.
! 498: */
! 499: db = 0;
! 500: send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db);
! 501: sc->sc_maxdev = db & LPS_DEVMASK;
! 502: #ifdef HILDEBUG
! 503: printf("%s: %d device(s)\n", sc->sc_dev.dv_xname, sc->sc_maxdev);
! 504: #endif
! 505:
! 506: /*
! 507: * Put all keyboards in raw mode now.
! 508: */
! 509: db = 0;
! 510: send_hil_cmd(sc, HIL_WRITEKBDSADR, &db, 1, NULL);
! 511:
! 512: /*
! 513: * If the loop grew, attach new devices.
! 514: */
! 515: for (id = knowndevs + 1; id <= sc->sc_maxdev; id++) {
! 516: int len;
! 517: const struct hildevice *hd;
! 518:
! 519: if (send_device_cmd(sc, id, HIL_IDENTIFY) != 0) {
! 520: printf("%s: no answer from device %d\n",
! 521: sc->sc_dev.dv_xname, id);
! 522: continue;
! 523: }
! 524:
! 525: len = sc->sc_cmdbp - sc->sc_cmdbuf;
! 526: if (len == 0) {
! 527: #ifdef HILDEBUG
! 528: printf("%s: no device at code %d\n",
! 529: sc->sc_dev.dv_xname, id);
! 530: #endif
! 531: continue;
! 532: }
! 533:
! 534: /* Identify and attach device */
! 535: for (hd = hildevs; hd->minid >= 0; hd++)
! 536: if (sc->sc_cmdbuf[0] >= hd->minid &&
! 537: sc->sc_cmdbuf[0] <= hd->maxid) {
! 538:
! 539: ha.ha_console = *sc->sc_console;
! 540: ha.ha_code = id;
! 541: ha.ha_type = hd->type;
! 542: ha.ha_descr = hd->descr;
! 543: ha.ha_infolen = len;
! 544: bcopy(sc->sc_cmdbuf, ha.ha_info, len);
! 545:
! 546: sc->sc_devices[id] = (struct hildev_softc *)
! 547: config_found_sm(&sc->sc_dev, &ha, hildevprint,
! 548: hilsubmatch);
! 549:
! 550: #if NHILKBD > 0
! 551: /*
! 552: * If we just attached a keyboard as console,
! 553: * console choice is not indeterminate anymore.
! 554: */
! 555: if (sc->sc_devices[id] != NULL &&
! 556: ha.ha_type == HIL_DEVICE_KEYBOARD &&
! 557: ha.ha_console != 0)
! 558: *sc->sc_console = 1;
! 559: #endif
! 560: }
! 561: }
! 562:
! 563: /*
! 564: * Detach remaining devices, if the loop has shrunk.
! 565: */
! 566: for (id = sc->sc_maxdev + 1; id < NHILD; id++) {
! 567: if (sc->sc_devices[id] != NULL)
! 568: config_detach((struct device *)sc->sc_devices[id],
! 569: DETACH_FORCE);
! 570: sc->sc_devices[id] = NULL;
! 571: }
! 572:
! 573: sc->sc_cmdbp = sc->sc_cmdbuf;
! 574:
! 575: splx(s);
! 576: }
! 577:
! 578: /*
! 579: * Called after the loop has been unplugged. We simply force detach of
! 580: * all our children.
! 581: */
! 582: void
! 583: hilempty(struct hil_softc *sc)
! 584: {
! 585: u_int8_t db;
! 586: int id, s;
! 587: u_int oldmaxdev;
! 588:
! 589: s = splhil();
! 590:
! 591: /*
! 592: * Wait for the loop to be stable.
! 593: */
! 594: for (;;) {
! 595: if (send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db) == 0) {
! 596: if (db & (LPS_CONFFAIL | LPS_CONFGOOD))
! 597: break;
! 598: } else {
! 599: db = LPS_CONFFAIL;
! 600: break;
! 601: }
! 602: }
! 603:
! 604: if (db & LPS_CONFFAIL) {
! 605: sc->sc_maxdev = 0;
! 606: } else {
! 607: db = 0;
! 608: send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db);
! 609: oldmaxdev = sc->sc_maxdev;
! 610: sc->sc_maxdev = db & LPS_DEVMASK;
! 611:
! 612: if (sc->sc_maxdev != 0) {
! 613: /*
! 614: * The loop was not unplugged after all, but its
! 615: * configuration has changed.
! 616: */
! 617: hilconfig(sc, oldmaxdev);
! 618: return;
! 619: }
! 620: }
! 621:
! 622: /*
! 623: * Now detach all hil devices.
! 624: */
! 625: for (id = sc->sc_maxdev + 1; id < NHILD; id++) {
! 626: if (sc->sc_devices[id] != NULL)
! 627: config_detach((struct device *)sc->sc_devices[id],
! 628: DETACH_FORCE);
! 629: sc->sc_devices[id] = NULL;
! 630: }
! 631:
! 632: sc->sc_cmdbp = sc->sc_cmdbuf;
! 633:
! 634: splx(s);
! 635: }
! 636:
! 637: /*
! 638: * Low level routines which actually talk to the 8042 chip.
! 639: */
! 640:
! 641: /*
! 642: * Send a command to the 8042 with zero or more bytes of data.
! 643: * If rdata is non-null, wait for and return a byte of data.
! 644: */
! 645: int
! 646: send_hil_cmd(struct hil_softc *sc, u_int cmd, u_int8_t *data, u_int dlen,
! 647: u_int8_t *rdata)
! 648: {
! 649: u_int8_t status;
! 650: int s;
! 651:
! 652: s = splhil();
! 653:
! 654: if (hilwait(sc) == 0) {
! 655: #ifdef HILDEBUG
! 656: printf("%s: no answer from the loop\n", sc->sc_dev.dv_xname);
! 657: #endif
! 658: splx(s);
! 659: return (EBUSY);
! 660: }
! 661:
! 662: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, cmd);
! 663: while (dlen--) {
! 664: hilwait(sc);
! 665: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, *data++);
! 666: DELAY(1);
! 667: }
! 668: if (rdata) {
! 669: do {
! 670: if (hildatawait(sc) == 0) {
! 671: #ifdef HILDEBUG
! 672: printf("%s: no answer from the loop\n",
! 673: sc->sc_dev.dv_xname);
! 674: #endif
! 675: break;
! 676: }
! 677: status = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
! 678: HILP_STAT);
! 679: *rdata = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
! 680: HILP_DATA);
! 681: DELAY(1);
! 682: } while (((status >> HIL_SSHIFT) & HIL_SMASK) != HIL_68K);
! 683: }
! 684: splx(s);
! 685: return (0);
! 686: }
! 687:
! 688: /*
! 689: * Send a command to a device on the loop.
! 690: * Since only one command can be active on the loop at any time,
! 691: * we must ensure that we are not interrupted during this process.
! 692: * Hence we mask interrupts to prevent potential access from most
! 693: * interrupt routines and turn off auto-polling to disable the
! 694: * internally generated poll commands.
! 695: * Needs to be called at splhil().
! 696: */
! 697: int
! 698: send_device_cmd(struct hil_softc *sc, u_int device, u_int cmd)
! 699: {
! 700: u_int8_t status, c;
! 701: int rc = 0;
! 702:
! 703: polloff(sc);
! 704:
! 705: sc->sc_cmdbp = sc->sc_cmdbuf;
! 706: sc->sc_cmddev = device;
! 707:
! 708: if (hilwait(sc) == 0) {
! 709: #ifdef HILDEBUG
! 710: printf("%s: no answer from device %d\n",
! 711: sc->sc_dev.dv_xname, device);
! 712: #endif
! 713: rc = EBUSY;
! 714: goto out;
! 715: }
! 716:
! 717: /*
! 718: * Transfer the command and device info to the chip
! 719: */
! 720: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_STARTCMD);
! 721: hilwait(sc);
! 722: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, 8 + device);
! 723: hilwait(sc);
! 724: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, cmd);
! 725: hilwait(sc);
! 726: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, HIL_TIMEOUT);
! 727:
! 728: /*
! 729: * Trigger the command and wait for completion
! 730: */
! 731: hilwait(sc);
! 732: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_TRIGGER);
! 733: sc->sc_cmddone = 0;
! 734: do {
! 735: if (hildatawait(sc) == 0) {
! 736: #ifdef HILDEBUG
! 737: printf("%s: no answer from device %d\n",
! 738: sc->sc_dev.dv_xname, device);
! 739: #endif
! 740: rc = EBUSY;
! 741: break;
! 742: }
! 743: status = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT);
! 744: c = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
! 745: DELAY(1);
! 746: hil_process_int(sc, status, c);
! 747: } while (sc->sc_cmddone == 0);
! 748: out:
! 749: sc->sc_cmddev = 0;
! 750:
! 751: pollon(sc);
! 752: return (rc);
! 753: }
! 754:
! 755: int
! 756: send_hildev_cmd(struct hildev_softc *dev, u_int cmd,
! 757: u_int8_t *outbuf, u_int *outlen)
! 758: {
! 759: struct hil_softc *sc = (struct hil_softc *)dev->sc_dev.dv_parent;
! 760: int s, rc;
! 761:
! 762: s = splhil();
! 763:
! 764: if ((rc = send_device_cmd(sc, dev->sc_code, cmd)) == 0) {
! 765: /*
! 766: * Return the command response in the buffer if necessary
! 767: */
! 768: if (outbuf != NULL && outlen != NULL) {
! 769: *outlen = min(*outlen, sc->sc_cmdbp - sc->sc_cmdbuf);
! 770: bcopy(sc->sc_cmdbuf, outbuf, *outlen);
! 771: }
! 772: }
! 773:
! 774: splx(s);
! 775: return (rc);
! 776: }
! 777:
! 778: /*
! 779: * Turn auto-polling off and on.
! 780: */
! 781: void
! 782: polloff(struct hil_softc *sc)
! 783: {
! 784: u_int8_t db;
! 785:
! 786: if (hilwait(sc) == 0)
! 787: return;
! 788:
! 789: /*
! 790: * Turn off auto repeat
! 791: */
! 792: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_SETARR);
! 793: hilwait(sc);
! 794: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, 0);
! 795:
! 796: /*
! 797: * Turn off auto-polling
! 798: */
! 799: hilwait(sc);
! 800: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_READLPCTRL);
! 801: hildatawait(sc);
! 802: db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
! 803: db &= ~LPC_AUTOPOLL;
! 804: hilwait(sc);
! 805: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_WRITELPCTRL);
! 806: hilwait(sc);
! 807: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, db);
! 808:
! 809: /*
! 810: * Must wait until polling is really stopped
! 811: */
! 812: do {
! 813: hilwait(sc);
! 814: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_READBUSY);
! 815: hildatawait(sc);
! 816: db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
! 817: } while (db & BSY_LOOPBUSY);
! 818:
! 819: sc->sc_cmddone = 0;
! 820: sc->sc_cmddev = 0;
! 821: }
! 822:
! 823: void
! 824: pollon(struct hil_softc *sc)
! 825: {
! 826: u_int8_t db;
! 827:
! 828: if (hilwait(sc) == 0)
! 829: return;
! 830:
! 831: /*
! 832: * Turn on auto polling
! 833: */
! 834: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_READLPCTRL);
! 835: hildatawait(sc);
! 836: db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
! 837: db |= LPC_AUTOPOLL;
! 838: hilwait(sc);
! 839: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_WRITELPCTRL);
! 840: hilwait(sc);
! 841: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, db);
! 842:
! 843: /*
! 844: * Turn off auto repeat - we emulate this through wscons
! 845: */
! 846: hilwait(sc);
! 847: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_CMD, HIL_SETARR);
! 848: hilwait(sc);
! 849: bus_space_write_1(sc->sc_bst, sc->sc_bsh, HILP_DATA, 0);
! 850: DELAY(1);
! 851: }
! 852:
! 853: void
! 854: hil_set_poll(struct hil_softc *sc, int on)
! 855: {
! 856: if (on) {
! 857: pollon(sc);
! 858: } else {
! 859: hil_process_pending(sc);
! 860: send_hil_cmd(sc, HIL_INTON, NULL, 0, NULL);
! 861: }
! 862: }
! 863:
! 864: int
! 865: hil_poll_data(struct hildev_softc *dev, u_int8_t *stat, u_int8_t *data)
! 866: {
! 867: struct hil_softc *sc = (struct hil_softc *)dev->sc_dev.dv_parent;
! 868: u_int8_t s, c;
! 869:
! 870: s = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT);
! 871: if ((s & HIL_DATA_RDY) == 0)
! 872: return -1;
! 873:
! 874: c = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA);
! 875: DELAY(1);
! 876:
! 877: if (hil_process_poll(sc, s, c)) {
! 878: /* Discard any data not for us */
! 879: if (sc->sc_actdev == dev->sc_code) {
! 880: *stat = s;
! 881: *data = c;
! 882: return 0;
! 883: }
! 884: }
! 885:
! 886: return -1;
! 887: }
CVSweb