1 /* $OpenBSD: crosec_kbd.c,v 1.3 2015/07/19 01:13:27 bmercer Exp $ */ 2 /* 3 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/sensors.h> 22 #include <sys/malloc.h> 23 24 #include <armv7/exynos/crosecvar.h> 25 26 #include <dev/wscons/wsconsio.h> 27 #include <dev/wscons/wskbdvar.h> 28 #include <dev/wscons/wsksymdef.h> 29 #include <dev/wscons/wsksymvar.h> 30 31 void cros_ec_add_task(void *); 32 void cros_ec_poll_keystate(void *); 33 int cros_ec_get_keystate(struct cros_ec_softc *); 34 35 int cros_ec_keyboard_enable(void *, int); 36 void cros_ec_keyboard_set_leds(void *, int); 37 int cros_ec_keyboard_ioctl(void *, u_long, caddr_t, int, struct proc *); 38 39 struct wskbd_accessops cros_ec_keyboard_accessops = { 40 cros_ec_keyboard_enable, 41 cros_ec_keyboard_set_leds, 42 cros_ec_keyboard_ioctl, 43 }; 44 45 void cros_ec_keyboard_cngetc(void *, u_int *, int *); 46 void cros_ec_keyboard_cnpollc(void *, int); 47 48 struct wskbd_consops cros_ec_keyboard_consops = { 49 cros_ec_keyboard_cngetc, 50 cros_ec_keyboard_cnpollc, 51 }; 52 53 54 /* XXX: assumes 8 rows, 13 cols, FDT */ 55 #define KC(n) KS_KEYCODE(n) 56 static const keysym_t cros_ec_keyboard_keydesc_us[] = { 57 KC(1), KS_Caps_Lock, 58 KC(3), KS_b, 59 KC(6), KS_n, 60 KC(10), KS_Alt_R, 61 KC(14), KS_Escape, 62 KC(16), KS_g, 63 KC(19), KS_h, 64 KC(24), KS_BackSpace, 65 KC(26), KS_Control_L, 66 KC(27), KS_Tab, 67 KC(29), KS_t, 68 KC(32), KS_y, 69 KC(42), KS_5, 70 KC(45), KS_6, 71 KC(52), KS_Control_R, 72 KC(53), KS_a, 73 KC(54), KS_d, 74 KC(55), KS_f, 75 KC(56), KS_s, 76 KC(57), KS_k, 77 KC(58), KS_j, 78 KC(61), KS_l, 79 KC(63), KS_Return, 80 KC(66), KS_z, 81 KC(67), KS_c, 82 KC(68), KS_v, 83 KC(69), KS_x, 84 KC(70), KS_comma, 85 KC(71), KS_m, 86 KC(72), KS_Shift_L, 87 KC(74), KS_period, 88 KC(76), KS_space, 89 KC(79), KS_1, 90 KC(80), KS_3, 91 KC(81), KS_4, 92 KC(82), KS_2, 93 KC(83), KS_8, 94 KC(84), KS_7, 95 KC(86), KS_0, 96 KC(87), KS_9, 97 KC(88), KS_Alt_L, 98 KC(92), KS_q, 99 KC(93), KS_e, 100 KC(94), KS_r, 101 KC(95), KS_w, 102 KC(96), KS_i, 103 KC(97), KS_u, 104 KC(98), KS_Shift_R, 105 KC(99), KS_p, 106 KC(100), KS_o, 107 }; 108 109 #define KBD_MAP(name, base, map) \ 110 { name, base, sizeof(map)/sizeof(keysym_t), map } 111 static const struct wscons_keydesc cros_ec_keyboard_keydesctab[] = { 112 KBD_MAP(KB_US, 0, cros_ec_keyboard_keydesc_us), 113 {0, 0, 0, 0} 114 }; 115 struct wskbd_mapdata cros_ec_keyboard_keymapdata = { 116 cros_ec_keyboard_keydesctab, 117 KB_US, 118 }; 119 120 int 121 cros_ec_init_keyboard(struct cros_ec_softc *sc) 122 { 123 struct ec_response_cros_ec_info info; 124 struct wskbddev_attach_args a; 125 126 if (cros_ec_info(sc, &info)) { 127 printf("%s: could not read KBC info\n", __func__); 128 return (-1); 129 } 130 131 sc->keyboard.rows = info.rows; 132 sc->keyboard.cols = info.cols; 133 sc->keyboard.switches = info.switches; 134 sc->keyboard.state = (uint8_t *)malloc(info.rows*info.cols, 135 M_DEVBUF, M_WAITOK|M_ZERO); 136 if (sc->keyboard.state == NULL) 137 panic("%s: no memory available for keyboard states", __func__); 138 139 /* FIXME: interrupt driven, please. */ 140 sc->keyboard.taskq = taskq_create("crosec-keyb", 1, IPL_TTY, 0); 141 task_set(&sc->keyboard.task, cros_ec_poll_keystate, sc); 142 timeout_set(&sc->keyboard.timeout, cros_ec_add_task, sc); 143 144 /* XXX: ghosting */ 145 146 wskbd_cnattach(&cros_ec_keyboard_consops, sc, &cros_ec_keyboard_keymapdata); 147 a.console = 1; 148 149 a.keymap = &cros_ec_keyboard_keymapdata; 150 a.accessops = &cros_ec_keyboard_accessops; 151 a.accesscookie = sc; 152 153 sc->keyboard.wskbddev = config_found((void *)sc, &a, wskbddevprint); 154 155 timeout_add_sec(&sc->keyboard.timeout, 10); 156 157 return 0; 158 } 159 160 void 161 cros_ec_add_task(void *arg) 162 { 163 struct cros_ec_softc *sc = (struct cros_ec_softc *)arg; 164 task_add(sc->keyboard.taskq, &sc->keyboard.task); 165 timeout_add_msec(&sc->keyboard.timeout, 100); 166 } 167 168 void 169 cros_ec_poll_keystate(void *arg) 170 { 171 struct cros_ec_softc *sc = (struct cros_ec_softc *)arg; 172 cros_ec_get_keystate(sc); 173 } 174 175 int 176 cros_ec_get_keystate(struct cros_ec_softc *sc) 177 { 178 int col, row, s; 179 uint8_t state[sc->keyboard.cols]; 180 cros_ec_scan_keyboard(sc, state, sc->keyboard.cols); 181 for (col = 0; col < sc->keyboard.cols; col++) { 182 for (row = 0; row < sc->keyboard.rows; row++) { 183 int off = row*sc->keyboard.cols; 184 int pressed = !!(state[col] & (1 << row)); 185 if (pressed && !sc->keyboard.state[off+col]) { 186 //printf("row %d col %d id %d pressed\n", row, col, off+col); 187 sc->keyboard.state[off+col] = 1; 188 if (sc->keyboard.polling) 189 return off+col; 190 s = spltty(); 191 wskbd_input(sc->keyboard.wskbddev, WSCONS_EVENT_KEY_DOWN, off+col); 192 splx(s); 193 } else if (!pressed && sc->keyboard.state[off+col]) { 194 //printf("row %d col %d id %d released\n", row, col, off+col); 195 sc->keyboard.state[off+col] = 0; 196 if (sc->keyboard.polling) 197 return off+col; 198 s = spltty(); 199 wskbd_input(sc->keyboard.wskbddev, WSCONS_EVENT_KEY_UP, off+col); 200 splx(s); 201 } else if (sc->keyboard.state[off+col]) { 202 //printf("row %d col %d id %d repeated\n", row, col, off+col); 203 } 204 } 205 } 206 return (-1); 207 } 208 209 void 210 cros_ec_keyboard_cngetc(void *v, u_int *type, int *data) 211 { 212 struct cros_ec_softc *sc = v; 213 int key; 214 215 sc->keyboard.polling = 1; 216 while ((key = cros_ec_get_keystate(sc)) == -1) { 217 delay(10000); 218 } 219 sc->keyboard.polling = 0; 220 221 *data = key; 222 *type = sc->keyboard.state[key] ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 223 } 224 225 void 226 cros_ec_keyboard_cnpollc(void *v, int on) 227 { 228 } 229 230 int 231 cros_ec_keyboard_enable(void *v, int on) 232 { 233 return 0; 234 } 235 236 void 237 cros_ec_keyboard_set_leds(void *v, int on) 238 { 239 } 240 241 int 242 cros_ec_keyboard_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 243 { 244 #ifdef WSDISPLAY_COMPAT_RAWKBD 245 struct cros_ec_softc *sc = v; 246 #endif 247 248 switch (cmd) { 249 250 case WSKBDIO_GTYPE: 251 *(int *)data = WSKBD_TYPE_ZAURUS; 252 return 0; 253 case WSKBDIO_SETLEDS: 254 return 0; 255 case WSKBDIO_GETLEDS: 256 *(int *)data = 0; 257 return 0; 258 #ifdef WSDISPLAY_COMPAT_RAWKBD 259 case WSKBDIO_SETMODE: 260 sc->keyboard.rawkbd = *(int *)data == WSKBD_RAW; 261 return (0); 262 #endif 263 264 } 265 /* kbdioctl(...); */ 266 267 return -1; 268 } 269