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