xref: /openbsd/sys/arch/armv7/exynos/crosec_kbd.c (revision 7c772976)
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