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