diff options
Diffstat (limited to 'sys/arch/armv7/exynos/crosec_kbd.c')
-rw-r--r-- | sys/arch/armv7/exynos/crosec_kbd.c | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/sys/arch/armv7/exynos/crosec_kbd.c b/sys/arch/armv7/exynos/crosec_kbd.c new file mode 100644 index 00000000000..cc8e0151b15 --- /dev/null +++ b/sys/arch/armv7/exynos/crosec_kbd.c @@ -0,0 +1,249 @@ +/* $OpenBSD: crosec_kbd.c,v 1.1 2015/01/26 02:48:24 bmercer Exp $ */ +/* + * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/sensors.h> +#include <sys/malloc.h> + +#include <armv7/exynos/crosecvar.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wskbdvar.h> +#include <dev/wscons/wsksymdef.h> +#include <dev/wscons/wsksymvar.h> + +int cros_ec_get_keystate(struct cros_ec_softc *); + +int cros_ec_keyboard_enable(void *, int); +void cros_ec_keyboard_set_leds(void *, int); +int cros_ec_keyboard_ioctl(void *, u_long, caddr_t, int, struct proc *); + +struct wskbd_accessops cros_ec_keyboard_accessops = { + cros_ec_keyboard_enable, + cros_ec_keyboard_set_leds, + cros_ec_keyboard_ioctl, +}; + +void cros_ec_keyboard_cngetc(void *, u_int *, int *); +void cros_ec_keyboard_cnpollc(void *, int); + +struct wskbd_consops cros_ec_keyboard_consops = { + cros_ec_keyboard_cngetc, + cros_ec_keyboard_cnpollc, +}; + + +/* XXX: assumes 8 rows, 13 cols, FDT */ +#define KC(n) KS_KEYCODE(n) +static const keysym_t cros_ec_keyboard_keydesc_us[] = { + KC(1), KS_Caps_Lock, + KC(3), KS_b, + KC(6), KS_n, + KC(10), KS_Alt_R, + KC(14), KS_Escape, + KC(16), KS_g, + KC(19), KS_h, + KC(24), KS_BackSpace, + KC(26), KS_Control_L, + KC(27), KS_Tab, + KC(29), KS_t, + KC(32), KS_y, + KC(42), KS_5, + KC(45), KS_6, + KC(52), KS_Control_R, + KC(53), KS_a, + KC(54), KS_d, + KC(55), KS_f, + KC(56), KS_s, + KC(57), KS_k, + KC(58), KS_j, + KC(61), KS_l, + KC(63), KS_Return, + KC(66), KS_z, + KC(67), KS_c, + KC(68), KS_v, + KC(69), KS_x, + KC(70), KS_comma, + KC(71), KS_m, + KC(72), KS_Shift_L, + KC(74), KS_period, + KC(76), KS_space, + KC(79), KS_1, + KC(80), KS_3, + KC(81), KS_4, + KC(82), KS_2, + KC(83), KS_8, + KC(84), KS_7, + KC(86), KS_0, + KC(87), KS_9, + KC(88), KS_Alt_L, + KC(92), KS_q, + KC(93), KS_e, + KC(94), KS_r, + KC(95), KS_w, + KC(96), KS_i, + KC(97), KS_u, + KC(98), KS_Shift_R, + KC(99), KS_p, + KC(100), KS_o, +}; + +#define KBD_MAP(name, base, map) \ + { name, base, sizeof(map)/sizeof(keysym_t), map } +static const struct wscons_keydesc cros_ec_keyboard_keydesctab[] = { + KBD_MAP(KB_US, 0, cros_ec_keyboard_keydesc_us), + {0, 0, 0, 0} +}; +struct wskbd_mapdata cros_ec_keyboard_keymapdata = { + cros_ec_keyboard_keydesctab, + KB_US, +}; + +int +cros_ec_init_keyboard(struct cros_ec_softc *sc) +{ + struct ec_response_cros_ec_info info; + struct wskbddev_attach_args a; + + if (cros_ec_info(sc, &info)) { + printf("%s: could not read KBC info\n", __func__); + return (-1); + } + + sc->keyboard.rows = info.rows; + sc->keyboard.cols = info.cols; + sc->keyboard.switches = info.switches; + sc->keyboard.state = (uint8_t *)malloc(info.rows*info.cols, + M_DEVBUF, M_WAITOK|M_ZERO); + if (sc->keyboard.state == NULL) + panic("%s: no memory available for keyboard states", __func__); + + /* XXX: ghosting */ + +#if 0 + while (sc->keyboard.state != NULL) { + cros_ec_get_keystate(sc); + delay(100000); + } +#endif + + wskbd_cnattach(&cros_ec_keyboard_consops, sc, &cros_ec_keyboard_keymapdata); + a.console = 1; + + a.keymap = &cros_ec_keyboard_keymapdata; + a.accessops = &cros_ec_keyboard_accessops; + a.accesscookie = sc; + + sc->keyboard.wskbddev = config_found((void *)sc, &a, wskbddevprint); + + return 0; +} + +int +cros_ec_get_keystate(struct cros_ec_softc *sc) +{ + int col, row; + uint8_t state[sc->keyboard.cols]; + cros_ec_scan_keyboard(sc, state, sc->keyboard.cols); + for (col = 0; col < sc->keyboard.cols; col++) { + for (row = 0; row < sc->keyboard.rows; row++) { + int off = row*sc->keyboard.cols; + int pressed = !!(state[col] & (1 << row)); + if (pressed && !sc->keyboard.state[off+col]) { + //printf("row %d col %d id %d pressed\n", row, col, off+col); + sc->keyboard.state[off+col] = 1; + if (sc->keyboard.polling) + return off+col; + wskbd_input(sc->keyboard.wskbddev, WSCONS_EVENT_KEY_DOWN, off+col); + } else if (!pressed && sc->keyboard.state[off+col]) { + //printf("row %d col %d id %d released\n", row, col, off+col); + sc->keyboard.state[off+col] = 0; + if (sc->keyboard.polling) + return off+col; + wskbd_input(sc->keyboard.wskbddev, WSCONS_EVENT_KEY_UP, off+col); + } else if (sc->keyboard.state[off+col]) { + //printf("row %d col %d id %d repeated\n", row, col, off+col); + if (sc->keyboard.polling) + return off+col; + } + } + } + return (-1); +} + +void +cros_ec_keyboard_cngetc(void *v, u_int *type, int *data) +{ + struct cros_ec_softc *sc = v; + int key; + + sc->keyboard.polling = 1; + while ((key = cros_ec_get_keystate(sc)) == -1) { + delay(10000); + } + sc->keyboard.polling = 0; + + *data = key; + *type = sc->keyboard.state[key] ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; +} + +void +cros_ec_keyboard_cnpollc(void *v, int on) +{ +} + +int +cros_ec_keyboard_enable(void *v, int on) +{ + return 0; +} + +void +cros_ec_keyboard_set_leds(void *v, int on) +{ +} + +int +cros_ec_keyboard_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ +#ifdef WSDISPLAY_COMPAT_RAWKBD + struct cros_ec_softc *sc = v; +#endif + + switch (cmd) { + + case WSKBDIO_GTYPE: + *(int *)data = WSKBD_TYPE_ZAURUS; + return 0; + case WSKBDIO_SETLEDS: + return 0; + case WSKBDIO_GETLEDS: + *(int *)data = 0; + return 0; +#ifdef WSDISPLAY_COMPAT_RAWKBD + case WSKBDIO_SETMODE: + sc->rawkbd = *(int *)data == WSKBD_RAW; + return (0); +#endif + + } + /* kbdioctl(...); */ + + return -1; +} |