Exemplo n.º 1
0
/* read char from the keyboard */
static u_int
ukbd_read_char(keyboard_t *kbd, int wait)
{
	ukbd_state_t *state;
	u_int action;
	int usbcode;
	int keycode;
#ifdef UKBD_EMULATE_ATSCANCODE
	int scancode;
#endif

	state = (ukbd_state_t *)kbd->kb_data;
next_code:
	/* do we have a composed char to return? */
	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
		action = state->ks_composed_char;
		state->ks_composed_char = 0;
		if (action > UCHAR_MAX) {
			return ERRKEY;
		}
		return action;
	}

#ifdef UKBD_EMULATE_ATSCANCODE
	/* do we have a pending raw scan code? */
	if (state->ks_mode == K_RAW) {
		if (state->ks_buffered_char[0]) {
			scancode = state->ks_buffered_char[0];
			if (scancode & SCAN_PREFIX) {
				state->ks_buffered_char[0] =
					scancode & ~SCAN_PREFIX;
				return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
			} else {
				state->ks_buffered_char[0] =
					state->ks_buffered_char[1];
				state->ks_buffered_char[1] = 0;
				return scancode;
			}
		}
	}
#endif /* UKBD_EMULATE_ATSCANCODE */

	/* see if there is something in the keyboard port */
	/* XXX */
	usbcode = ukbd_getc(state, wait);
	if (usbcode == -1) {
		return NOKEY;
	}
	++kbd->kb_count;

#ifdef UKBD_EMULATE_ATSCANCODE
	/* USB key index -> key code -> AT scan code */
	keycode = ukbd_trtab[KEY_INDEX(usbcode)];
	if (keycode == NN) {
		return NOKEY;
	}

	/* return an AT scan code for the K_RAW mode */
	if (state->ks_mode == K_RAW) {
		scancode = keycode2scancode(keycode, state->ks_ndata.modifiers,
					    usbcode & KEY_RELEASE);
		if (scancode & SCAN_PREFIX) {
			if (scancode & SCAN_PREFIX_CTL) {
				state->ks_buffered_char[0] =
					0x1d | (scancode & SCAN_RELEASE);
				state->ks_buffered_char[1] =
					scancode & ~SCAN_PREFIX;
			} else if (scancode & SCAN_PREFIX_SHIFT) {
				state->ks_buffered_char[0] =
					0x2a | (scancode & SCAN_RELEASE);
				state->ks_buffered_char[1] =
					scancode & ~SCAN_PREFIX_SHIFT;
			} else {
				state->ks_buffered_char[0] =
					scancode & ~SCAN_PREFIX;
				state->ks_buffered_char[1] = 0;
			}
			return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
		}
		return scancode;
	}
#else /* !UKBD_EMULATE_ATSCANCODE */
	/* return the byte as is for the K_RAW mode */
	if (state->ks_mode == K_RAW) {
		return usbcode;
	}

	/* USB key index -> key code */
	keycode = ukbd_trtab[KEY_INDEX(usbcode)];
	if (keycode == NN) {
		return NOKEY;
	}
#endif /* UKBD_EMULATE_ATSCANCODE */

	switch (keycode) {
	case 0x38:	/* left alt (compose key) */
		if (usbcode & KEY_RELEASE) {
			if (state->ks_flags & COMPOSE) {
				state->ks_flags &= ~COMPOSE;
				if (state->ks_composed_char > UCHAR_MAX)
					state->ks_composed_char = 0;
			}
		} else {
			if (!(state->ks_flags & COMPOSE)) {
				state->ks_flags |= COMPOSE;
				state->ks_composed_char = 0;
			}
		}
		break;
	/* XXX: I don't like these... */
	case 0x5c:	/* print screen */
		if (state->ks_flags & ALTS)
			keycode = 0x54;	/* sysrq */
		break;
	case 0x68:	/* pause/break */
		if (state->ks_flags & CTLS)
			keycode = 0x6c;	/* break */
		break;
	}

	/* return the key code in the K_CODE mode */
	if (usbcode & KEY_RELEASE)
		keycode |= SCAN_RELEASE;
	if (state->ks_mode == K_CODE) {
		return keycode;
	}

	/* compose a character code */
	if (state->ks_flags & COMPOSE) {
		switch (keycode) {
		/* key pressed, process it */
		case 0x47: case 0x48: case 0x49:	/* keypad 7,8,9 */
			state->ks_composed_char *= 10;
			state->ks_composed_char += keycode - 0x40;
			if (state->ks_composed_char > UCHAR_MAX) {
				return ERRKEY;
			}
			goto next_code;
		case 0x4B: case 0x4C: case 0x4D:	/* keypad 4,5,6 */
			state->ks_composed_char *= 10;
			state->ks_composed_char += keycode - 0x47;
			if (state->ks_composed_char > UCHAR_MAX) {
				return ERRKEY;
			}
			goto next_code;
		case 0x4F: case 0x50: case 0x51:	/* keypad 1,2,3 */
			state->ks_composed_char *= 10;
			state->ks_composed_char += keycode - 0x4E;
			if (state->ks_composed_char > UCHAR_MAX) {
				return ERRKEY;
			}
			goto next_code;
		case 0x52:				/* keypad 0 */
			state->ks_composed_char *= 10;
			if (state->ks_composed_char > UCHAR_MAX) {
				return ERRKEY;
			}
			goto next_code;

		/* key released, no interest here */
		case SCAN_RELEASE | 0x47:
		case SCAN_RELEASE | 0x48:
		case SCAN_RELEASE | 0x49:		/* keypad 7,8,9 */
		case SCAN_RELEASE | 0x4B:
		case SCAN_RELEASE | 0x4C:
		case SCAN_RELEASE | 0x4D:		/* keypad 4,5,6 */
		case SCAN_RELEASE | 0x4F:
		case SCAN_RELEASE | 0x50:
		case SCAN_RELEASE | 0x51:		/* keypad 1,2,3 */
		case SCAN_RELEASE | 0x52:		/* keypad 0 */
			goto next_code;

		case 0x38:				/* left alt key */
			break;

		default:
			if (state->ks_composed_char > 0) {
				state->ks_flags &= ~COMPOSE;
				state->ks_composed_char = 0;
				return ERRKEY;
			}
			break;
		}
	}

	/* keycode to key action */
	action = genkbd_keyaction(kbd, SCAN_CHAR(keycode),
				  keycode & SCAN_RELEASE, &state->ks_state,
				  &state->ks_accents);
	if (action == NOKEY) {
		goto next_code;
	} else {
		return action;
	}
	/* NOTREACHED */
}
Exemplo n.º 2
0
/* read char from the keyboard */
static u_int
pckbd_read_char(keyboard_t *kbd, int wait)
{
	pckbd_state_t *state;
	u_int action;
	int scancode;
	int keycode;

	state = (pckbd_state_t *)kbd->kb_data;
next_code:
	/* do we have a composed char to return? */
	if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
		action = state->ks_composed_char;
		state->ks_composed_char = 0;
		if (action > UCHAR_MAX)
			return ERRKEY;
		return action;
	}

	/* see if there is something in the keyboard port */
	if (wait) {
		do {
			scancode = read_kbd_data(state->kbdc);
		} while (scancode == -1);
	} else {
		scancode = read_kbd_data_no_wait(state->kbdc);
		if (scancode == -1)
			return NOKEY;
	}
	++kbd->kb_count;

#if 0
	printf("pckbd_read_char(): scancode:0x%x\n", scancode);
#endif

	/* return the byte as is for the K_RAW mode */
	if (state->ks_mode == K_RAW)
		return scancode;

	/* translate the scan code into a keycode */
	keycode = scancode & 0x7F;
	switch(scancode) {
	case 0xF3:	/* GRPH (compose key) released */
		if (state->ks_flags & COMPOSE) {
			state->ks_flags &= ~COMPOSE;
			if (state->ks_composed_char > UCHAR_MAX)
				state->ks_composed_char = 0;
		}
		break;
	case 0x73:	/* GRPH (compose key) pressed */
		if (!(state->ks_flags & COMPOSE)) {
			state->ks_flags |= COMPOSE;
			state->ks_composed_char = 0;
		}
		break;
	}

	/* return the key code in the K_CODE mode */
	if (state->ks_mode == K_CODE)
		return (keycode | (scancode & 0x80));

	/* compose a character code */
	if (state->ks_flags & COMPOSE) {
		switch (scancode) {
		/* key pressed, process it */
		case 0x42: case 0x43: case 0x44:	/* keypad 7,8,9 */
			state->ks_composed_char *= 10;
			state->ks_composed_char += scancode - 0x3B;
			if (state->ks_composed_char > UCHAR_MAX)
				return ERRKEY;
			goto next_code;
		case 0x46: case 0x47: case 0x48:	/* keypad 4,5,6 */
			state->ks_composed_char *= 10;
			state->ks_composed_char += scancode - 0x42;
			if (state->ks_composed_char > UCHAR_MAX)
				return ERRKEY;
			goto next_code;
		case 0x4A: case 0x4B: case 0x4C:	/* keypad 1,2,3 */
			state->ks_composed_char *= 10;
			state->ks_composed_char += scancode - 0x49;
			if (state->ks_composed_char > UCHAR_MAX)
				return ERRKEY;
			goto next_code;
		case 0x4E:				/* keypad 0 */
			state->ks_composed_char *= 10;
			if (state->ks_composed_char > UCHAR_MAX)
				return ERRKEY;
			goto next_code;

		/* key released, no interest here */
		case 0xC2: case 0xC3: case 0xC4:	/* keypad 7,8,9 */
		case 0xC6: case 0xC7: case 0xC8:	/* keypad 4,5,6 */
		case 0xCA: case 0xCB: case 0xCC:	/* keypad 1,2,3 */
		case 0xCE:				/* keypad 0 */
			goto next_code;

		case 0x73:				/* GRPH key */
			break;

		default:
			if (state->ks_composed_char > 0) {
				state->ks_flags &= ~COMPOSE;
				state->ks_composed_char = 0;
				return ERRKEY;
			}
			break;
		}
	}

	/* keycode to key action */
	action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
				  &state->ks_state, &state->ks_accents);
	if (action == NOKEY)
		goto next_code;
	else
		return action;
}
Exemplo n.º 3
0
static u_int
sunkbd_read_char(keyboard_t *kbd, int wait)
{
	struct sunkbd_softc *sc;
	int action;
	int key;

	sc = (struct sunkbd_softc *)kbd;
	if (sc->sc_repeating) {
		sc->sc_repeating = 0;
		callout_reset(&sc->sc_repeat_callout, hz / 10,
		    sunkbd_repeat, sc);
		key = sc->sc_repeat_key;
		if (sc->sc_mode == K_RAW)
			return (key);
		else
			return genkbd_keyaction(kbd, key & 0x7f, key & 0x80,
			    &sc->sc_state, &sc->sc_accents);
	}

	for (;;) {
		/* XXX compose */

		if (sc->sc_uart != NULL && !uart_rx_empty(sc->sc_uart)) {
			key = uart_rx_get(sc->sc_uart);
		} else if (sc->sc_polling != 0 && sc->sc_sysdev != NULL) {
			if (wait)
				key = uart_getc(sc->sc_sysdev);
			else if ((key = uart_poll(sc->sc_sysdev)) == -1)
				return (NOKEY);
		} else {
			return (NOKEY);
		}

		switch (key) {
		case SKBD_RSP_IDLE:
			break;
		default:
			++kbd->kb_count;

			if ((key & 0x80) == 0) {
				callout_reset(&sc->sc_repeat_callout, hz / 2,
				    sunkbd_repeat, sc);
				sc->sc_repeat_key = key;
			} else {
				if (sc->sc_repeat_key == (key & 0x7f)) {
					callout_stop(&sc->sc_repeat_callout);
					sc->sc_repeat_key = -1;
				}
			}

			if (sc->sc_mode == K_RAW)
				return (key);

			action = genkbd_keyaction(kbd, key & 0x7f, key & 0x80,
			    &sc->sc_state, &sc->sc_accents);
			if (action != NOKEY)
				return (action);
			break;
		}
	}
	return (0);
}
Exemplo n.º 4
0
static u_int
sunkbd_read_char(keyboard_t *kbd, int wait)
{
	struct sunkbd_softc *sc;
	int key, release, repeated, suncode;

	sc = (struct sunkbd_softc *)kbd;

#if defined(SUNKBD_EMULATE_ATKBD)
	if (sc->sc_mode == K_RAW && sc->sc_buffered_char[0]) {
		key = sc->sc_buffered_char[0];
		if (key & SCAN_PREFIX) {
			sc->sc_buffered_char[0] = key & ~SCAN_PREFIX;
			return ((key & SCAN_PREFIX_E0) ? 0xe0 : 0xe1);
		} else {
			sc->sc_buffered_char[0] = sc->sc_buffered_char[1];
			sc->sc_buffered_char[1] = 0;
			return (key);
		}
	}
#endif

	repeated = 0;
	if (sc->sc_repeating) {
		repeated = 1;
		sc->sc_repeating = 0;
		callout_reset(&sc->sc_repeat_callout, hz / 10,
		    sunkbd_repeat, sc);
		suncode = sc->sc_repeat_key;
		goto process_code;
	}

	for (;;) {
 next_code:
		if (!(sc->sc_flags & KPCOMPOSE) && (sc->sc_composed_char > 0)) {
			key = sc->sc_composed_char;
			sc->sc_composed_char = 0;
			if (key > UCHAR_MAX)
				return (ERRKEY);
			return (key);
		}

		if (sc->sc_uart != NULL && !uart_rx_empty(sc->sc_uart)) {
			suncode = uart_rx_get(sc->sc_uart);
		} else if (sc->sc_polling != 0 && sc->sc_sysdev != NULL) {
			if (wait)
				suncode = uart_getc(sc->sc_sysdev);
			else if ((suncode = uart_poll(sc->sc_sysdev)) == -1)
				return (NOKEY);
		} else {
			return (NOKEY);
		}

		switch (suncode) {
		case SKBD_RSP_IDLE:
			break;
		default:
 process_code:
			++kbd->kb_count;
			key = SKBD_KEY_CHAR(suncode);
			release = suncode & SKBD_KEY_RELEASE;
			if (!repeated) {
				if (release == 0) {
					callout_reset(&sc->sc_repeat_callout,
					    hz / 2, sunkbd_repeat, sc);
					sc->sc_repeat_key = suncode;
				} else if (sc->sc_repeat_key == key) {
					callout_stop(&sc->sc_repeat_callout);
					sc->sc_repeat_key = -1;
				}
			}

#if defined(SUNKBD_EMULATE_ATKBD)
			key = sunkbd_trtab[key];
			if (key == NOTR)
				return (NOKEY);

			if (!repeated) {
				switch (key) {
				case 0x1d:	/* ctrl */
					if (release != 0)
						sc->sc_flags &= ~CTLS;
					else
						sc->sc_flags |= CTLS;
					break;
				case 0x2a:	/* left shift */
				case 0x36:	/* right shift */
					if (release != 0)
						sc->sc_flags &= ~SHIFTS;
					else
						sc->sc_flags |= SHIFTS;
					break;
				case 0x38:	/* alt */
				case 0x5d:	/* altgr */
					if (release != 0)
						sc->sc_flags &= ~ALTS;
					else
						sc->sc_flags |= ALTS;
					break;
				}
			}
			if (sc->sc_mode == K_RAW) {
				key = keycode2scancode(key, sc->sc_flags,
				    release);
				if (key & SCAN_PREFIX) {
					if (key & SCAN_PREFIX_CTL) {
						sc->sc_buffered_char[0] =
						    0x1d | (key & SCAN_RELEASE);
						sc->sc_buffered_char[1] =
						    key & ~SCAN_PREFIX;
					} else if (key & SCAN_PREFIX_SHIFT) {
						sc->sc_buffered_char[0] =
						    0x2a | (key & SCAN_RELEASE);
						sc->sc_buffered_char[1] =
						    key & ~SCAN_PREFIX_SHIFT;
					} else {
						sc->sc_buffered_char[0] =
						    key & ~SCAN_PREFIX;
						sc->sc_buffered_char[1] = 0;
					}
					return ((key & SCAN_PREFIX_E0) ?
					    0xe0 : 0xe1);
				}
				return (key);
			}
			switch (key) {
			case 0x5c:	/* print screen */
				if (sc->sc_flags & ALTS)
					key = 0x54;	/* sysrq */
				break;
			case 0x68:	/* pause/break */
				if (sc->sc_flags & CTLS)
					key = 0x6c;	/* break */
				break;
			}

			if (sc->sc_mode == K_CODE)
				return (key | release);
#else
			if (sc->sc_mode == K_RAW || sc->sc_mode == K_CODE)
				return (suncode);
#endif

#if defined(SUNKBD_EMULATE_ATKBD)
			if (key == 0x38) {	/* left alt (KP compose key) */
#else
			if (key == 0x13) {	/* left alt (KP compose key) */
#endif
				if (release != 0) {
					if (sc->sc_flags & KPCOMPOSE) {
						sc->sc_flags &= ~KPCOMPOSE;
						if (sc->sc_composed_char >
						    UCHAR_MAX)
							sc->sc_composed_char =
							    0;
					}
				} else {
					if (!(sc->sc_flags & KPCOMPOSE)) {
						sc->sc_flags |= KPCOMPOSE;
						sc->sc_composed_char = 0;
					}
				}
			}
			if (sc->sc_flags & KPCOMPOSE) {
				switch (suncode) {
				case 0x44:			/* KP 7 */
				case 0x45:			/* KP 8 */
				case 0x46:			/* KP 9 */
					sc->sc_composed_char *= 10;
					sc->sc_composed_char += suncode - 0x3d;
					if (sc->sc_composed_char > UCHAR_MAX)
						return (ERRKEY);
					goto next_code;
				case 0x5b:			/* KP 4 */
				case 0x5c:			/* KP 5 */
				case 0x5d:			/* KP 6 */
					sc->sc_composed_char *= 10;
					sc->sc_composed_char += suncode - 0x58;
					if (sc->sc_composed_char > UCHAR_MAX)
						return (ERRKEY);
					goto next_code;
				case 0x70:			/* KP 1 */
				case 0x71:			/* KP 2 */
				case 0x72:			/* KP 3 */
					sc->sc_composed_char *= 10;
					sc->sc_composed_char += suncode - 0x6f;
					if (sc->sc_composed_char > UCHAR_MAX)
						return (ERRKEY);
					goto next_code;
				case 0x5e:			/* KP 0 */
					sc->sc_composed_char *= 10;
					if (sc->sc_composed_char > UCHAR_MAX)
						return (ERRKEY);
					goto next_code;

				case 0x44 | SKBD_KEY_RELEASE:	/* KP 7 */
				case 0x45 | SKBD_KEY_RELEASE:	/* KP 8 */
				case 0x46 | SKBD_KEY_RELEASE:	/* KP 9 */
				case 0x5b | SKBD_KEY_RELEASE:	/* KP 4 */
				case 0x5c | SKBD_KEY_RELEASE:	/* KP 5 */
				case 0x5d | SKBD_KEY_RELEASE:	/* KP 6 */
				case 0x70 | SKBD_KEY_RELEASE:	/* KP 1 */
				case 0x71 | SKBD_KEY_RELEASE:	/* KP 2 */
				case 0x72 | SKBD_KEY_RELEASE:	/* KP 3 */
				case 0x5e | SKBD_KEY_RELEASE:	/* KP 0 */
					goto next_code;
				default:
					if (sc->sc_composed_char > 0) {
						sc->sc_flags &= ~KPCOMPOSE;
						sc->sc_composed_char = 0;
						return (ERRKEY);
					}
				}
			}

			key = genkbd_keyaction(kbd, key, release,
			    &sc->sc_state, &sc->sc_accents);
			if (key != NOKEY || repeated)
				return (key);
		}
	}
	return (0);
}

static int
sunkbd_check_char(keyboard_t *kbd)
{
	struct sunkbd_softc *sc;

	if (!KBD_IS_ACTIVE(kbd))
		return (FALSE);

	sc = (struct sunkbd_softc *)kbd;
	if (!(sc->sc_flags & KPCOMPOSE) && (sc->sc_composed_char > 0))
		return (TRUE);

	return (sunkbd_check(kbd));
}

static int
sunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data)
{
	struct sunkbd_softc *sc;
	int c, error;
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
	int ival;
#endif

	sc = (struct sunkbd_softc *)kbd;
	error = 0;
	switch (cmd) {
	case KDGKBMODE:
		*(int *)data = sc->sc_mode;
		break;
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
	case _IO('K', 7):
		ival = IOCPARM_IVAL(data);
		data = (caddr_t)&ival;
		/* FALLTHROUGH */
#endif
	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) {
				sunkbd_clear_state(kbd);
				sc->sc_mode = *(int *)data;
			}
			break;
		default:
			error = EINVAL;
			break;
		}
		break;
	case KDGETLED:
		*(int *)data = KBD_LED_VAL(kbd);
		break;
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
	case _IO('K', 66):
		ival = IOCPARM_IVAL(data);
		data = (caddr_t)&ival;
		/* FALLTHROUGH */
#endif
	case KDSETLED:
		if (*(int *)data & ~LOCK_MASK) {
			error = EINVAL;
			break;
		}
		if (sc->sc_sysdev == NULL)
			break;
		c = 0;
		if (*(int *)data & CLKED)
			c |= SKBD_LED_CAPSLOCK;
		if (*(int *)data & NLKED)
			c |= SKBD_LED_NUMLOCK;
		if (*(int *)data & SLKED)
			c |= SKBD_LED_SCROLLLOCK;
		uart_lock(sc->sc_sysdev->hwmtx);
		sc->sc_sysdev->ops->putc(&sc->sc_sysdev->bas, SKBD_CMD_SETLED);
		sc->sc_sysdev->ops->putc(&sc->sc_sysdev->bas, c);
		uart_unlock(sc->sc_sysdev->hwmtx);
		KBD_LED_VAL(kbd) = *(int *)data;
		break;
	case KDGKBSTATE:
		*(int *)data = sc->sc_state & LOCK_MASK;
		break;
#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5)
	case _IO('K', 20):
		ival = IOCPARM_IVAL(data);
		data = (caddr_t)&ival;
		/* FALLTHROUGH */
#endif
	case KDSKBSTATE:
		if (*(int *)data & ~LOCK_MASK) {
			error = EINVAL;
			break;
		}
		sc->sc_state &= ~LOCK_MASK;
		sc->sc_state |= *(int *)data;
		/* set LEDs and quit */
		return (sunkbd_ioctl(kbd, KDSETLED, data));
	case KDSETREPEAT:
	case KDSETRAD:
		break;
	case PIO_KEYMAP:
	case OPIO_KEYMAP:
	case PIO_KEYMAPENT:
	case PIO_DEADKEYMAP:
	default:
		return (genkbd_commonioctl(kbd, cmd, data));
	}
	return (error);
}

static int
sunkbd_lock(keyboard_t *kbd, int lock)
{

	TODO;
	return (0);
}
Exemplo n.º 5
0
/* read char from the keyboard */
static u_int
atkbd_read_char(keyboard_t *kbd, int wait)
{
    atkbd_state_t *state;
    u_int action;
    int scancode;
    int keycode;

    state = (atkbd_state_t *)kbd->kb_data;
next_code:
    /* do we have a composed char to return? */
    if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
        action = state->ks_composed_char;
        state->ks_composed_char = 0;
        if (action > UCHAR_MAX)
            return ERRKEY;
        return action;
    }

    /* see if there is something in the keyboard port */
    if (wait) {
        do {
            scancode = read_kbd_data(state->kbdc);
        } while (scancode == -1);
    } else {
        scancode = read_kbd_data_no_wait(state->kbdc);
        if (scancode == -1)
            return NOKEY;
    }
    ++kbd->kb_count;

#if KBDIO_DEBUG >= 10
    printf("atkbd_read_char(): scancode:0x%x\n", scancode);
#endif

    /* return the byte as is for the K_RAW mode */
    if (state->ks_mode == K_RAW)
        return scancode;

    /* translate the scan code into a keycode */
    keycode = scancode & 0x7F;
    switch (state->ks_prefix) {
    case 0x00:	/* normal scancode */
        switch(scancode) {
        case 0xB8:	/* left alt (compose key) released */
            if (state->ks_flags & COMPOSE) {
                state->ks_flags &= ~COMPOSE;
                if (state->ks_composed_char > UCHAR_MAX)
                    state->ks_composed_char = 0;
            }
            break;
        case 0x38:	/* left alt (compose key) pressed */
            if (!(state->ks_flags & COMPOSE)) {
                state->ks_flags |= COMPOSE;
                state->ks_composed_char = 0;
            }
            break;
        case 0xE0:
        case 0xE1:
            state->ks_prefix = scancode;
            goto next_code;
        }
        break;
    case 0xE0:      /* 0xE0 prefix */
        state->ks_prefix = 0;
        switch (keycode) {
        case 0x1C:	/* right enter key */
            keycode = 0x59;
            break;
        case 0x1D:	/* right ctrl key */
            keycode = 0x5A;
            break;
        case 0x35:	/* keypad divide key */
            keycode = 0x5B;
            break;
        case 0x37:	/* print scrn key */
            keycode = 0x5C;
            break;
        case 0x38:	/* right alt key (alt gr) */
            keycode = 0x5D;
            break;
        case 0x46:	/* ctrl-pause/break on AT 101 (see below) */
            keycode = 0x68;
            break;
        case 0x47:	/* grey home key */
            keycode = 0x5E;
            break;
        case 0x48:	/* grey up arrow key */
            keycode = 0x5F;
            break;
        case 0x49:	/* grey page up key */
            keycode = 0x60;
            break;
        case 0x4B:	/* grey left arrow key */
            keycode = 0x61;
            break;
        case 0x4D:	/* grey right arrow key */
            keycode = 0x62;
            break;
        case 0x4F:	/* grey end key */
            keycode = 0x63;
            break;
        case 0x50:	/* grey down arrow key */
            keycode = 0x64;
            break;
        case 0x51:	/* grey page down key */
            keycode = 0x65;
            break;
        case 0x52:	/* grey insert key */
            keycode = 0x66;
            break;
        case 0x53:	/* grey delete key */
            keycode = 0x67;
            break;
        /* the following 3 are only used on the MS "Natural" keyboard */
        case 0x5b:	/* left Window key */
            keycode = 0x69;
            break;
        case 0x5c:	/* right Window key */
            keycode = 0x6a;
            break;
        case 0x5d:	/* menu key */
            keycode = 0x6b;
            break;
        case 0x5e:	/* power key */
            keycode = 0x6d;
            break;
        case 0x5f:	/* sleep key */
            keycode = 0x6e;
            break;
        case 0x63:	/* wake key */
            keycode = 0x6f;
            break;
        default:	/* ignore everything else */
            goto next_code;
        }
        break;
    case 0xE1:	/* 0xE1 prefix */
        /*
         * The pause/break key on the 101 keyboard produces:
         * E1-1D-45 E1-9D-C5
         * Ctrl-pause/break produces:
         * E0-46 E0-C6 (See above.)
         */
        state->ks_prefix = 0;
        if (keycode == 0x1D)
            state->ks_prefix = 0x1D;
        goto next_code;
    /* NOT REACHED */
    case 0x1D:	/* pause / break */
        state->ks_prefix = 0;
        if (keycode != 0x45)
            goto next_code;
        keycode = 0x68;
        break;
    }

    if (kbd->kb_type == KB_84) {
        switch (keycode) {
        case 0x37:	/* *(numpad)/print screen */
            if (state->ks_flags & SHIFTS)
                keycode = 0x5c;	/* print screen */
            break;
        case 0x45:	/* num lock/pause */
            if (state->ks_flags & CTLS)
                keycode = 0x68;	/* pause */
            break;
        case 0x46:	/* scroll lock/break */
            if (state->ks_flags & CTLS)
                keycode = 0x6c;	/* break */
            break;
        }
    } else if (kbd->kb_type == KB_101) {
        switch (keycode) {
        case 0x5c:	/* print screen */
            if (state->ks_flags & ALTS)
                keycode = 0x54;	/* sysrq */
            break;
        case 0x68:	/* pause/break */
            if (state->ks_flags & CTLS)
                keycode = 0x6c;	/* break */
            break;
        }
    }

    /* return the key code in the K_CODE mode */
    if (state->ks_mode == K_CODE)
        return (keycode | (scancode & 0x80));

    /* compose a character code */
    if (state->ks_flags & COMPOSE) {
        switch (keycode | (scancode & 0x80)) {
        /* key pressed, process it */
        case 0x47:
        case 0x48:
        case 0x49:	/* keypad 7,8,9 */
            state->ks_composed_char *= 10;
            state->ks_composed_char += keycode - 0x40;
            if (state->ks_composed_char > UCHAR_MAX)
                return ERRKEY;
            goto next_code;
        case 0x4B:
        case 0x4C:
        case 0x4D:	/* keypad 4,5,6 */
            state->ks_composed_char *= 10;
            state->ks_composed_char += keycode - 0x47;
            if (state->ks_composed_char > UCHAR_MAX)
                return ERRKEY;
            goto next_code;
        case 0x4F:
        case 0x50:
        case 0x51:	/* keypad 1,2,3 */
            state->ks_composed_char *= 10;
            state->ks_composed_char += keycode - 0x4E;
            if (state->ks_composed_char > UCHAR_MAX)
                return ERRKEY;
            goto next_code;
        case 0x52:				/* keypad 0 */
            state->ks_composed_char *= 10;
            if (state->ks_composed_char > UCHAR_MAX)
                return ERRKEY;
            goto next_code;

        /* key released, no interest here */
        case 0xC7:
        case 0xC8:
        case 0xC9:	/* keypad 7,8,9 */
        case 0xCB:
        case 0xCC:
        case 0xCD:	/* keypad 4,5,6 */
        case 0xCF:
        case 0xD0:
        case 0xD1:	/* keypad 1,2,3 */
        case 0xD2:				/* keypad 0 */
            goto next_code;

        case 0x38:				/* left alt key */
            break;

        default:
            if (state->ks_composed_char > 0) {
                state->ks_flags &= ~COMPOSE;
                state->ks_composed_char = 0;
                return ERRKEY;
            }
            break;
        }
    }

    /* keycode to key action */
    action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
                              &state->ks_state, &state->ks_accents);
    if (action == NOKEY)
        goto next_code;
    else
        return action;
}