/* * Called after the loop has been unplugged. We simply force detach of * all our children. */ void hilempty(struct hil_softc *sc) { u_int8_t db; int id, s; u_int oldmaxdev; s = splhil(); /* * Wait for the loop to be stable. */ for (;;) { if (send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db) == 0) { if (db & (LPS_CONFFAIL | LPS_CONFGOOD)) break; } else { db = LPS_CONFFAIL; break; } } if (db & LPS_CONFFAIL) { sc->sc_maxdev = 0; } else { db = 0; send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db); oldmaxdev = sc->sc_maxdev; sc->sc_maxdev = db & LPS_DEVMASK; if (sc->sc_maxdev != 0) { /* * The loop was not unplugged after all, but its * configuration has changed. */ hilconfig(sc, oldmaxdev); return; } } /* * Now detach all hil devices. */ for (id = sc->sc_maxdev + 1; id < NHILD; id++) { if (sc->sc_devices[id] != NULL) config_detach((struct device *)sc->sc_devices[id], DETACH_FORCE); sc->sc_devices[id] = NULL; } sc->sc_cmdbp = sc->sc_cmdbuf; splx(s); }
void hil_set_poll(struct hil_softc *sc, int on) { if (on) { pollon(sc); } else { hil_process_pending(sc); send_hil_cmd(sc, HIL_INTON, NULL, 0, NULL); } }
u_char read_bbc_reg(int reg) { u_char data = reg; if (bbcaddr) { #if 0 send_hil_cmd(bbcaddr, BBC_SET_REG, &data, 1, NULL); send_hil_cmd(bbcaddr, BBC_READ_REG, NULL, 0, &data); #else HILWAIT(bbcaddr); bbcaddr->hil_cmd = BBC_SET_REG; HILWAIT(bbcaddr); bbcaddr->hil_data = data; HILWAIT(bbcaddr); bbcaddr->hil_cmd = BBC_READ_REG; HILDATAWAIT(bbcaddr); data = bbcaddr->hil_data; #endif } return(data); }
/* * Called after the loop has reconfigured. Here we need to: * - determine how many devices are on the loop * (some may have been added or removed) * - make sure all keyboards are in raw mode * * Note that our device state is now potentially invalid as * devices may no longer be where they were. What we should * do here is either track where the devices went and move * state around accordingly... * * Note that it is necessary that we operate the loop with the keyboards * in raw mode: they won't cause the loop to generate an NMI if the * ``reset'' key combination is pressed, and we do not handle the hil * NMI interrupt... */ void hilconfig(struct hil_softc *sc, u_int knowndevs) { struct hil_attach_args ha; u_int8_t db; int id, s; s = splhil(); /* * Determine how many devices are on the loop. */ db = 0; send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db); sc->sc_maxdev = db & LPS_DEVMASK; #ifdef HILDEBUG printf("%s: %d device(s)\n", sc->sc_dev.dv_xname, sc->sc_maxdev); #endif /* * Put all keyboards in raw mode now. */ db = 0; send_hil_cmd(sc, HIL_WRITEKBDSADR, &db, 1, NULL); /* * If the loop grew, attach new devices. */ for (id = knowndevs + 1; id <= sc->sc_maxdev; id++) { int len; const struct hildevice *hd; if (send_device_cmd(sc, id, HIL_IDENTIFY) != 0) { printf("%s: no answer from device %d\n", sc->sc_dev.dv_xname, id); continue; } len = sc->sc_cmdbp - sc->sc_cmdbuf; if (len == 0) { #ifdef HILDEBUG printf("%s: no device at code %d\n", sc->sc_dev.dv_xname, id); #endif continue; } /* Identify and attach device */ for (hd = hildevs; hd->minid >= 0; hd++) if (sc->sc_cmdbuf[0] >= hd->minid && sc->sc_cmdbuf[0] <= hd->maxid) { ha.ha_console = *sc->sc_console; ha.ha_code = id; ha.ha_type = hd->type; ha.ha_descr = hd->descr; ha.ha_infolen = len; bcopy(sc->sc_cmdbuf, ha.ha_info, len); sc->sc_devices[id] = (struct hildev_softc *) config_found_sm(&sc->sc_dev, &ha, hildevprint, hilsubmatch); #if NHILKBD > 0 /* * If we just attached a keyboard as console, * console choice is not indeterminate anymore. */ if (sc->sc_devices[id] != NULL && ha.ha_type == HIL_DEVICE_KEYBOARD && ha.ha_console != 0) *sc->sc_console = 1; #endif } } /* * Detach remaining devices, if the loop has shrunk. */ for (id = sc->sc_maxdev + 1; id < NHILD; id++) { if (sc->sc_devices[id] != NULL) config_detach((struct device *)sc->sc_devices[id], DETACH_FORCE); sc->sc_devices[id] = NULL; } sc->sc_cmdbp = sc->sc_cmdbuf; splx(s); }
/* * Same as above, but in polled mode: return data as it gets seen, instead * of buffering it. */ int hil_process_poll(struct hil_softc *sc, u_int8_t stat, u_int8_t c) { u_int8_t db; switch ((stat >> HIL_SSHIFT) & HIL_SMASK) { case HIL_STATUS: if (c & HIL_ERROR) { sc->sc_cmddone = 1; switch (c) { case HIL_RECONFIG: /* * Remember that a configuration event * occurred; it will be processed upon * leaving polled mode... */ sc->sc_pending = HIL_PENDING_RECONFIG; /* * However, the keyboard will come back as * cooked, and we rely on it being in raw * mode. So, put it back in raw mode right * now. */ db = 0; send_hil_cmd(sc, HIL_WRITEKBDSADR, &db, 1, NULL); break; case HIL_UNPLUGGED: /* * Remember that an unplugged event * occured; it will be processed upon * leaving polled mode... */ sc->sc_pending = HIL_PENDING_UNPLUGGED; break; } break; } if (c & HIL_COMMAND) { if (!(c & HIL_POLLDATA)) { /* End of command */ sc->sc_cmdending = 1; } sc->sc_actdev = 0; } else { if (c & HIL_POLLDATA) { /* Start of polled data */ sc->sc_actdev = (c & HIL_DEVMASK); sc->sc_pollbp = sc->sc_pollbuf; } else { /* Start of command - should not happen */ if (sc->sc_cmddev == (c & HIL_DEVMASK)) { sc->sc_cmdbp = sc->sc_cmdbuf; sc->sc_actdev = 0; } } } break; case HIL_DATA: if (sc->sc_actdev != 0) /* Collecting poll data */ return 1; else { if (sc->sc_cmddev != 0) { /* Discarding cmd data */ if (sc->sc_cmdending) { sc->sc_cmddone = 1; sc->sc_cmdending = 0; } } } break; } return 0; }
void hil_attach_deferred(void *v) { struct hil_softc *sc = v; int tries; u_int8_t db; sc->sc_status = HIL_STATUS_BUSY; /* * Initialize the loop: reconfigure, don't report errors, * put keyboard in cooked mode, and enable autopolling. */ db = LPC_RECONF | LPC_KBDCOOK | LPC_NOERROR | LPC_AUTOPOLL; send_hil_cmd(sc, HIL_WRITELPCTRL, &db, 1, NULL); /* * Delay one second for reconfiguration and then read the * data to clear the interrupt (if the loop reconfigured). */ DELAY(1000000); if (bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_STAT) & HIL_DATA_RDY) { db = bus_space_read_1(sc->sc_bst, sc->sc_bsh, HILP_DATA); DELAY(1); } /* * The HIL loop may have reconfigured. If so we proceed on, * if not we loop a few times until a successful reconfiguration * is reported back to us. If the HIL loop is still lost after a * few seconds, give up. */ for (tries = 10; tries != 0; tries--) { if (send_hil_cmd(sc, HIL_READLPSTAT, NULL, 0, &db) == 0) { if (db & (LPS_CONFFAIL | LPS_CONFGOOD)) break; } #ifdef HILDEBUG printf("%s: loop not ready, retrying...\n", sc->sc_dev.dv_xname); #endif DELAY(1000000); } if (tries == 0 || (db & LPS_CONFFAIL)) { printf("%s: no devices\n", sc->sc_dev.dv_xname); sc->sc_pending = 0; if (tries == 0) return; } /* * Create asynchronous loop event handler thread. */ if (kthread_create(hil_thread, sc, &sc->sc_thread, "%s", sc->sc_dev.dv_xname) != 0) { printf("%s: unable to create event thread\n", sc->sc_dev.dv_xname); return; } /* * Enable loop interrupts. */ send_hil_cmd(sc, HIL_INTON, NULL, 0, NULL); /* * Reconfigure if necessary */ sc->sc_status = HIL_STATUS_READY; hil_process_pending(sc); }