summaryrefslogtreecommitdiff
path: root/sys/arch/armv7/exynos/crosec_kbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/armv7/exynos/crosec_kbd.c')
-rw-r--r--sys/arch/armv7/exynos/crosec_kbd.c249
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;
+}