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;
}
Example #2
0
/* 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;
}
Example #3
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;
}
Example #4
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;
	}
}
Example #5
0
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);
}
Example #6
0
/* 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;
}