/* * Set the keyboard LED's. * * Automatically translates from ioctl/softc format to the * actual keyboard register format */ int setleds(struct akbd_softc *sc, u_char leds) { int addr; short cmd; u_char buffer[9]; addr = sc->adbaddr; buffer[0] = 0; cmd = ADBTALK(addr, 2); if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0) return (EIO); leds = ~leds & 0x07; buffer[2] &= 0xf8; buffer[2] |= leds; cmd = ADBLISTEN(addr, 2); adb_op_sync((Ptr)buffer, cmd); /* talk R2 */ cmd = ADBTALK(addr, 2); if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0) return (EIO); if ((buffer[2] & 0xf8) != leds) return (EIO); else return (0); }
/* * Set the keyboard LED's. * * Automatically translates from ioctl/softc format to the * actual keyboard register format */ static void adbkbd_set_leds(void *cookie, int leds) { struct adbkbd_softc *sc = cookie; int aleds; short cmd; uint8_t buffer[2]; DPRINTF("adbkbd_set_leds: %02x\n", leds); if ((leds & 0x07) == (sc->sc_leds & 0x07)) return; if (sc->sc_have_led_control) { aleds = (~leds & 0x04) | 3; if (leds & 1) aleds &= ~2; if (leds & 2) aleds &= ~1; buffer[0] = 0xff; buffer[1] = aleds | 0xf8; cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2); sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, buffer); } sc->sc_leds = leds & 7; }
/* * initialize extended mouse - probes devices as * described in _Inside Macintosh, Devices_. */ void extdms_init(int totaladbs) { ADBDataBlock adbdata; int adbindex, adbaddr, count; short cmd; u_char buffer[9]; for (adbindex = 1; adbindex <= totaladbs; adbindex++) { /* Get the ADB information */ adbaddr = GetIndADB(&adbdata, adbindex); if (adbdata.origADBAddr == ADBADDR_MS && (adbdata.devType == ADBMS_USPEED || adbdata.devType == ADBMS_UCONTOUR)) { /* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */ cmd = ADBLISTEN(adbaddr, 1); /* * To setup the MicroSpeed or the Contour, it appears * that we can send the following command to the mouse * and then expect data back in the form: * buffer[0] = 4 (bytes) * buffer[1], buffer[2] as std. mouse * buffer[3] = buffer[4] = 0xff when no buttons * are down. When button N down, bit N is clear. * buffer[4]'s locking mask enables a * click to toggle the button down state--sort of * like the "Easy Access" shift/control/etc. keys. * buffer[3]'s alternative speed mask enables using * different speed when the corr. button is down */ buffer[0] = 4; buffer[1] = 0x00; /* Alternative speed */ buffer[2] = 0x00; /* speed = maximum */ buffer[3] = 0x10; /* enable extended protocol, * lower bits = alt. speed mask * = 0000b */ buffer[4] = 0x07; /* Locking mask = 0000b, * enable buttons = 0111b */ extdms_done = 0; ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); while (!extdms_done) /* busy wait until done */; } if (adbdata.origADBAddr == ADBADDR_MS && (adbdata.devType == ADBMS_100DPI || adbdata.devType == ADBMS_200DPI)) { /* found a mouse */ cmd = ADBTALK(adbaddr, 3); extdms_done = 0; ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); /* Wait until done, but no more than 2 secs */ count = 40000; while (!extdms_done && count-- > 0) delay(50); if (!extdms_done) { #ifdef ADB_DEBUG if (adb_debug) printf("adb: extdms_init timed out\n"); #endif return; } /* Attempt to initialize Extended Mouse Protocol */ buffer[2] = '\004'; /* make handler ID 4 */ extdms_done = 0; cmd = ADBLISTEN(adbaddr, 3); ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); while (!extdms_done) /* busy wait until done */; /* * Check to see if successful, if not * try to initialize it as other types */ cmd = ADBTALK(adbaddr, 3); extdms_done = 0; ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); while (!extdms_done) /* busy wait until done */; if (buffer[2] != ADBMS_EXTENDED) { /* Attempt to initialize as an A3 mouse */ buffer[2] = 0x03; /* make handler ID 3 */ extdms_done = 0; cmd = ADBLISTEN(adbaddr, 3); ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); while (!extdms_done) /* busy wait until done */; /* * Check to see if successful, if not * try to initialize it as other types */ cmd = ADBTALK(adbaddr, 3); extdms_done = 0; ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); while (!extdms_done) /* busy wait until done */; if (buffer[2] == ADBMS_MSA3) { /* Initialize as above */ cmd = ADBLISTEN(adbaddr, 2); /* listen 2 */ buffer[0] = 3; buffer[1] = 0x00; /* Irrelevant, buffer has 0x77 */ buffer[2] = 0x07; /* * enable 3 button mode = 0111b, * speed = normal */ extdms_done = 0; ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&extdms_done, cmd); while (!extdms_done) /* busy wait until done */; } else { /* No special support for this mouse */ } } } } }
static void adbkbd_attach(device_t parent, device_t self, void *aux) { struct adbkbd_softc *sc = device_private(self); struct adb_attach_args *aaa = aux; short cmd; struct wskbddev_attach_args a; #if NWSMOUSE > 0 struct wsmousedev_attach_args am; #endif uint8_t buffer[2]; sc->sc_dev = self; sc->sc_ops = aaa->ops; sc->sc_adbdev = aaa->dev; sc->sc_adbdev->cookie = sc; sc->sc_adbdev->handler = adbkbd_handler; sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0); sc->sc_leds = 0; /* initially off */ sc->sc_have_led_control = 0; /* * If this is != 0 then pushing the power button will not immadiately * send a shutdown event to sysmon but instead require another key * press within 5 seconds with a gap of at least two seconds. The * reason to do this is the fact that some PowerBook keyboards, * like the 2400, 3400 and original G3 have their power buttons * right next to the backspace key and it's extremely easy to hit * it by accident. * On most other keyboards the power button is sufficiently far out * of the way so we don't need this. */ sc->sc_power_button_delay = 0; sc->sc_msg_len = 0; sc->sc_poll = 0; sc->sc_capslock = 0; sc->sc_trans[1] = 103; /* F11 */ sc->sc_trans[2] = 111; /* F12 */ /* * Most ADB keyboards send 0x7f 0x7f when the power button is pressed. * Some older PowerBooks, like the 3400c, will send a single scancode * 0x7e instead. Unfortunately Fn-Command on some more recent *Books * sends the same scancode, so by default sc_power is set to a value * that can't occur as a scancode and only set to 0x7e on hardware that * needs it */ sc->sc_power = 0xffff; sc->sc_timestamp = 0; sc->sc_emul_usb = FALSE; aprint_normal(" addr %d: ", sc->sc_adbdev->current_addr); switch (sc->sc_adbdev->handler_id) { case ADB_STDKBD: aprint_normal("standard keyboard\n"); break; case ADB_ISOKBD: aprint_normal("standard keyboard (ISO layout)\n"); break; case ADB_EXTKBD: cmd = ADBTALK(sc->sc_adbdev->current_addr, 1); sc->sc_msg_len = 0; sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); adbkbd_wait(sc, 10); /* Ignore Logitech MouseMan/Trackman pseudo keyboard */ /* XXX needs testing */ if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) { aprint_normal("Mouseman (non-EMP) pseudo keyboard\n"); return; } else if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x21) { aprint_normal("Trackman (non-EMP) pseudo keyboard\n"); return; } else { aprint_normal("extended keyboard\n"); adbkbd_initleds(sc); } break; case ADB_EXTISOKBD: aprint_normal("extended keyboard (ISO layout)\n"); adbkbd_initleds(sc); break; case ADB_KBDII: aprint_normal("keyboard II\n"); break; case ADB_ISOKBDII: aprint_normal("keyboard II (ISO layout)\n"); break; case ADB_PBKBD: aprint_normal("PowerBook keyboard\n"); sc->sc_power = 0x7e; sc->sc_power_button_delay = 1; break; case ADB_PBISOKBD: aprint_normal("PowerBook keyboard (ISO layout)\n"); sc->sc_power = 0x7e; sc->sc_power_button_delay = 1; break; case ADB_ADJKPD: aprint_normal("adjustable keypad\n"); break; case ADB_ADJKBD: aprint_normal("adjustable keyboard\n"); break; case ADB_ADJISOKBD: aprint_normal("adjustable keyboard (ISO layout)\n"); break; case ADB_ADJJAPKBD: aprint_normal("adjustable keyboard (Japanese layout)\n"); break; case ADB_PBEXTISOKBD: aprint_normal("PowerBook extended keyboard (ISO layout)\n"); sc->sc_power_button_delay = 1; sc->sc_power = 0x7e; break; case ADB_PBEXTJAPKBD: aprint_normal("PowerBook extended keyboard (Japanese layout)\n"); sc->sc_power_button_delay = 1; sc->sc_power = 0x7e; break; case ADB_JPKBDII: aprint_normal("keyboard II (Japanese layout)\n"); break; case ADB_PBEXTKBD: aprint_normal("PowerBook extended keyboard\n"); sc->sc_power_button_delay = 1; sc->sc_power = 0x7e; break; case ADB_DESIGNKBD: aprint_normal("extended keyboard\n"); adbkbd_initleds(sc); break; case ADB_PBJPKBD: aprint_normal("PowerBook keyboard (Japanese layout)\n"); sc->sc_power_button_delay = 1; sc->sc_power = 0x7e; break; case ADB_PBG3KBD: aprint_normal("PowerBook G3 keyboard\n"); break; case ADB_PBG3JPKBD: aprint_normal("PowerBook G3 keyboard (Japanese layout)\n"); break; case ADB_IBOOKKBD: aprint_normal("iBook keyboard\n"); break; default: aprint_normal("mapped device (%d)\n", sc->sc_adbdev->handler_id); break; } /* * try to switch to extended protocol * as in, tell the keyboard to distinguish between left and right * Shift, Control and Alt keys */ cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 3); buffer[0] = sc->sc_adbdev->current_addr; buffer[1] = 3; sc->sc_msg_len = 0; sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, buffer); adbkbd_wait(sc, 10); cmd = ADBTALK(sc->sc_adbdev->current_addr, 3); sc->sc_msg_len = 0; sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); adbkbd_wait(sc, 10); if ((sc->sc_msg_len == 4) && (sc->sc_buffer[3] == 3)) { aprint_verbose_dev(sc->sc_dev, "extended protocol enabled\n"); } if (adbkbd_is_console && (adbkbd_console_attached == 0)) { wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata); adbkbd_console_attached = 1; a.console = 1; } else { a.console = 0; } a.keymap = &adbkbd_keymapdata; a.accessops = &adbkbd_accessops; a.accesscookie = sc; sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); #ifdef ADBKBD_EMUL_USB sc->sc_emul_usb = TRUE; wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb, 128); #endif /* ADBKBD_EMUL_USB */ #if NWSMOUSE > 0 /* attach the mouse device */ am.accessops = &adbkms_accessops; am.accesscookie = sc; sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &am, wsmousedevprint); #endif adbkbd_setup_sysctl(sc); /* finally register the power button */ sysmon_task_queue_init(); memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev); sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) aprint_error_dev(sc->sc_dev, "unable to register power button with sysmon\n"); }