static int test_typematic(void) { enable_keystroke(1); /* * 250ms delay, 8 chars / sec. */ set_typematic(0xf); press_key(1, 1, 1); VERIFY_LPC_CHAR_DELAY("\x01\x01\x01\x01\x01", 650); press_key(1, 1, 0); VERIFY_LPC_CHAR_DELAY("\x81", 300); /* * 500ms delay, 10.9 chars / sec. */ reset_8042(); press_key(1, 1, 1); VERIFY_LPC_CHAR_DELAY("\x01\x01\x01", 650); press_key(1, 1, 0); VERIFY_LPC_CHAR_DELAY("\x81", 200); return EC_SUCCESS; }
/* keyboard interrupt routine */ static int atkbd_intr(keyboard_t *kbd, void *arg) { atkbd_state_t *state = (atkbd_state_t *)kbd->kb_data; int delay[2]; int c; if (!KBD_HAS_DEVICE(kbd)) { /* * The keyboard was not detected before; * it must have been reconnected! */ init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config); KBD_FOUND_DEVICE(kbd); atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); set_typematic(kbd); delay[0] = kbd->kb_delay1; delay[1] = kbd->kb_delay2; atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); } if (state->ks_polling) return 0; if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { /* let the callback function to process the input */ (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, kbd->kb_callback.kc_arg); } else { /* read and discard the input; no one is waiting for input */ do { c = atkbd_read_char(kbd, FALSE); } while (c != NOKEY); } return 0; }
/* some useful control functions */ static int ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) { /* trasnlate LED_XXX bits into the device specific bits */ static u_char ledmap[8] = { 0, 2, 1, 3, 4, 6, 5, 7, }; ukbd_state_t *state = kbd->kb_data; int i; crit_enter(); switch (cmd) { case KDGKBMODE: /* get keyboard mode */ *(int *)arg = state->ks_mode; break; case KDSKBMODE: /* set keyboard mode */ switch (*(int *)arg) { case K_XLATE: if (state->ks_mode != K_XLATE) { /* make lock key state and LED state match */ state->ks_state &= ~LOCK_MASK; state->ks_state |= KBD_LED_VAL(kbd); } /* FALLTHROUGH */ case K_RAW: case K_CODE: if (state->ks_mode != *(int *)arg) { ukbd_clear_state(kbd); state->ks_mode = *(int *)arg; kbd->kb_savemode = state->ks_mode; } break; default: crit_exit(); return EINVAL; } break; case KDGETLED: /* get keyboard LED */ *(int *)arg = KBD_LED_VAL(kbd); break; case KDSETLED: /* set keyboard LED */ /* NOTE: lock key state in ks_state won't be changed */ if (*(int *)arg & ~LOCK_MASK) { crit_exit(); return EINVAL; } i = *(int *)arg; /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ if (state->ks_mode == K_XLATE && kbd->kb_keymap->n_keys > ALTGR_OFFSET) { if (i & ALKED) i |= CLKED; else i &= ~CLKED; } if (KBD_HAS_DEVICE(kbd)) { set_leds(state, ledmap[i & LED_MASK]); /* XXX: error check? */ } KBD_LED_VAL(kbd) = *(int *)arg; break; case KDGKBSTATE: /* get lock key state */ *(int *)arg = state->ks_state & LOCK_MASK; break; case KDSKBSTATE: /* set lock key state */ if (*(int *)arg & ~LOCK_MASK) { crit_exit(); return EINVAL; } state->ks_state &= ~LOCK_MASK; state->ks_state |= *(int *)arg; crit_exit(); /* set LEDs and quit */ return ukbd_ioctl(kbd, KDSETLED, arg); case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ crit_exit(); if (!KBD_HAS_DEVICE(kbd)) { return 0; } if (((int *)arg)[1] < 0) { return EINVAL; } if (((int *)arg)[0] < 0) { return EINVAL; } else if (((int *)arg)[0] == 0) /* fastest possible value */ kbd->kb_delay1 = 200; else kbd->kb_delay1 = ((int *)arg)[0]; kbd->kb_delay2 = ((int *)arg)[1]; return 0; case KDSETRAD: /* set keyboard repeat rate (old interface) */ crit_exit(); return set_typematic(kbd, *(int *)arg); case PIO_KEYMAP: /* set keyboard translation table */ case PIO_KEYMAPENT: /* set keyboard translation table entry */ case PIO_DEADKEYMAP: /* set accent key translation table */ state->ks_accents = 0; /* FALLTHROUGH */ default: crit_exit(); return genkbd_commonioctl(kbd, cmd, arg); #ifdef USB_DEBUG case USB_SETDEBUG: ukbddebug = *(int *)arg; break; #endif } crit_exit(); return 0; }
static status_t keyboard_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) { keyboard_cookie *cookie = (keyboard_cookie *)_cookie; switch (op) { case KB_READ: { if (!sHasKeyboardReader && !cookie->is_debugger) { cookie->is_reader = true; sHasKeyboardReader = true; } else if (!cookie->is_debugger && !cookie->is_reader) return B_BUSY; raw_key_info packet; status_t status = read_keyboard_packet(&packet, cookie->is_debugger); TRACE("ps2: ioctl KB_READ: %s\n", strerror(status)); if (status != B_OK) return status; return user_memcpy(buffer, &packet, sizeof(packet)); } case KB_SET_LEDS: { led_info info; TRACE("ps2: ioctl KB_SET_LEDS\n"); if (user_memcpy(&info, buffer, sizeof(led_info)) < B_OK) return B_BAD_ADDRESS; return set_leds(&info); } case KB_SET_KEY_REPEATING: { TRACE("ps2: ioctl KB_SET_KEY_REPEATING\n"); // 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds // with "ack" (0xFA). return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0, NULL, 0); } case KB_SET_KEY_NONREPEATING: { TRACE("ps2: ioctl KB_SET_KEY_NONREPEATING\n"); // 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack" // (0xFA). return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0, NULL, 0); } case KB_SET_KEY_REPEAT_RATE: { int32 key_repeat_rate; TRACE("ps2: ioctl KB_SET_KEY_REPEAT_RATE\n"); if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate)) != B_OK) return B_BAD_ADDRESS; if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) != B_OK) return B_ERROR; sKeyboardRepeatRate = key_repeat_rate; return B_OK; } case KB_GET_KEY_REPEAT_RATE: { TRACE("ps2: ioctl KB_GET_KEY_REPEAT_RATE\n"); return user_memcpy(buffer, &sKeyboardRepeatRate, sizeof(sKeyboardRepeatRate)); } case KB_SET_KEY_REPEAT_DELAY: { bigtime_t key_repeat_delay; TRACE("ps2: ioctl KB_SET_KEY_REPEAT_DELAY\n"); if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay)) != B_OK) return B_BAD_ADDRESS; if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) != B_OK) return B_ERROR; sKeyboardRepeatDelay = key_repeat_delay; return B_OK; } case KB_GET_KEY_REPEAT_DELAY: { TRACE("ps2: ioctl KB_GET_KEY_REPEAT_DELAY\n"); return user_memcpy(buffer, &sKeyboardRepeatDelay, sizeof(sKeyboardRepeatDelay)); } case KB_GET_KEYBOARD_ID: case KB_SET_CONTROL_ALT_DEL_TIMEOUT: case KB_CANCEL_CONTROL_ALT_DEL: case KB_DELAY_CONTROL_ALT_DEL: INFO("ps2: ioctl 0x%lx not implemented yet, returning B_OK\n", op); return B_OK; case KB_SET_DEBUG_READER: if (sHasDebugReader) return B_BUSY; cookie->is_debugger = true; sHasDebugReader = true; return B_OK; default: INFO("ps2: invalid ioctl 0x%lx\n", op); return B_DEV_INVALID_IOCTL; } }
static int akbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data) { struct adb_kbd_softc *sc; uint16_t r2; int error; sc = (struct adb_kbd_softc *)(kbd); error = 0; switch (cmd) { case KDGKBMODE: *(int *)data = sc->sc_mode; break; case KDSKBMODE: switch (*(int *)data) { case K_XLATE: if (sc->sc_mode != K_XLATE) { /* make lock key state and LED state match */ sc->sc_state &= ~LOCK_MASK; sc->sc_state |= KBD_LED_VAL(kbd); } /* FALLTHROUGH */ case K_RAW: case K_CODE: if (sc->sc_mode != *(int *)data) sc->sc_mode = *(int *)data; break; default: error = EINVAL; break; } break; case KDGETLED: *(int *)data = KBD_LED_VAL(kbd); break; case KDSKBSTATE: if (*(int *)data & ~LOCK_MASK) { error = EINVAL; break; } sc->sc_state &= ~LOCK_MASK; sc->sc_state |= *(int *)data; /* FALLTHROUGH */ case KDSETLED: KBD_LED_VAL(kbd) = *(int *)data; if (!sc->have_led_control) break; r2 = (~0 & 0x04) | 3; if (*(int *)data & NLKED) r2 &= ~1; if (*(int *)data & CLKED) r2 &= ~2; if (*(int *)data & SLKED) r2 &= ~4; adb_send_packet(sc->sc_dev,ADB_COMMAND_LISTEN,2, sizeof(uint16_t),(u_char *)&r2); break; case KDGKBSTATE: *(int *)data = sc->sc_state & LOCK_MASK; break; case KDSETREPEAT: if (!KBD_HAS_DEVICE(kbd)) return 0; if (((int *)data)[1] < 0) return EINVAL; if (((int *)data)[0] < 0) return EINVAL; else if (((int *)data)[0] == 0) /* fastest possible value */ kbd->kb_delay1 = 200; else kbd->kb_delay1 = ((int *)data)[0]; kbd->kb_delay2 = ((int *)data)[1]; break; case KDSETRAD: error = set_typematic(kbd, *(int *)data); break; case PIO_KEYMAP: case OPIO_KEYMAP: case PIO_KEYMAPENT: case PIO_DEADKEYMAP: default: return (genkbd_commonioctl(kbd, cmd, data)); } return (error); }
/* reset and initialize the device */ static int atkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) { keyboard_t *kbd; atkbd_state_t *state; keymap_t *keymap; accentmap_t *accmap; fkeytab_t *fkeymap; int fkeymap_size; int delay[2]; int *data = (int *)arg; /* data[0]: controller, data[1]: irq */ int error, needfree; #ifdef EVDEV_SUPPORT struct evdev_dev *evdev; char phys_loc[8]; #endif /* XXX */ if (unit == ATKBD_DEFAULT) { *kbdp = kbd = &default_kbd; if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) return 0; state = &default_kbd_state; keymap = &default_keymap; accmap = &default_accentmap; fkeymap = default_fkeytab; fkeymap_size = nitems(default_fkeytab); needfree = 0; } else if (*kbdp == NULL) { *kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT | M_ZERO); state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT | M_ZERO); /* NB: these will always be initialized 'cuz !KBD_IS_PROBED */ keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT); accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT); fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT); fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); needfree = 1; if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || (accmap == NULL) || (fkeymap == NULL)) { error = ENOMEM; goto bad; } } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { return 0; } else { kbd = *kbdp; state = (atkbd_state_t *)kbd->kb_data; bzero(state, sizeof(*state)); keymap = kbd->kb_keymap; accmap = kbd->kb_accentmap; fkeymap = kbd->kb_fkeytab; fkeymap_size = kbd->kb_fkeytab_size; needfree = 0; } if (!KBD_IS_PROBED(kbd)) { state->kbdc = atkbdc_open(data[0]); if (state->kbdc == NULL) { error = ENXIO; goto bad; } kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, 0, 0); bcopy(&key_map, keymap, sizeof(key_map)); bcopy(&accent_map, accmap, sizeof(accent_map)); bcopy(fkey_tab, fkeymap, imin(fkeymap_size * sizeof(fkeymap[0]), sizeof(fkey_tab))); kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); kbd->kb_data = (void *)state; if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ if (flags & KB_CONF_FAIL_IF_NO_KBD) { error = ENXIO; goto bad; } } else { KBD_FOUND_DEVICE(kbd); } atkbd_clear_state(kbd); state->ks_mode = K_XLATE; /* * FIXME: set the initial value for lock keys in ks_state * according to the BIOS data? */ KBD_PROBE_DONE(kbd); } if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; if (KBD_HAS_DEVICE(kbd) && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { kbd_unregister(kbd); error = ENXIO; goto bad; } atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); set_typematic(kbd); delay[0] = kbd->kb_delay1; delay[1] = kbd->kb_delay2; atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); #ifdef EVDEV_SUPPORT /* register as evdev provider on first init */ if (state->ks_evdev == NULL) { snprintf(phys_loc, sizeof(phys_loc), "atkbd%d", unit); evdev = evdev_alloc(); evdev_set_name(evdev, "AT keyboard"); evdev_set_phys(evdev, phys_loc); evdev_set_id(evdev, BUS_I8042, PS2_KEYBOARD_VENDOR, PS2_KEYBOARD_PRODUCT, 0); evdev_set_methods(evdev, kbd, &atkbd_evdev_methods); evdev_support_event(evdev, EV_SYN); evdev_support_event(evdev, EV_KEY); evdev_support_event(evdev, EV_LED); evdev_support_event(evdev, EV_REP); evdev_support_all_known_keys(evdev); evdev_support_led(evdev, LED_NUML); evdev_support_led(evdev, LED_CAPSL); evdev_support_led(evdev, LED_SCROLLL); if (evdev_register_mtx(evdev, &Giant)) evdev_free(evdev); else state->ks_evdev = evdev; state->ks_evdev_state = 0; } #endif KBD_INIT_DONE(kbd); } if (!KBD_IS_CONFIGURED(kbd)) { if (kbd_register(kbd) < 0) { error = ENXIO; goto bad; } KBD_CONFIG_DONE(kbd); } return 0; bad: if (needfree) { if (state != NULL) free(state, M_DEVBUF); if (keymap != NULL) free(keymap, M_DEVBUF); if (accmap != NULL) free(accmap, M_DEVBUF); if (fkeymap != NULL) free(fkeymap, M_DEVBUF); if (kbd != NULL) { free(kbd, M_DEVBUF); *kbdp = NULL; /* insure ref doesn't leak to caller */ } } return error; }