g42xxeb_kmkbd.c revision 1.18 1 1.18 andvar /* $NetBSD: g42xxeb_kmkbd.c,v 1.18 2024/02/09 22:08:32 andvar Exp $ */
2 1.1 bsh
3 1.1 bsh /*-
4 1.1 bsh * Copyright (c) 2002, 2003, 2005 Genetec corp.
5 1.1 bsh * All rights reserved.
6 1.1 bsh *
7 1.1 bsh * 4x5 matrix key switch driver for TWINTAIL.
8 1.1 bsh * Written by Hiroyuki Bessho for Genetec corp.
9 1.1 bsh *
10 1.1 bsh * Redistribution and use in source and binary forms, with or without
11 1.1 bsh * modification, are permitted provided that the following conditions
12 1.1 bsh * are met:
13 1.1 bsh * 1. Redistributions of source code must retain the above copyright
14 1.1 bsh * notice, this list of conditions and the following disclaimer.
15 1.1 bsh * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 bsh * notice, this list of conditions and the following disclaimer in the
17 1.1 bsh * documentation and/or other materials provided with the distribution.
18 1.9 martin * 3. Neither the name of The NetBSD Foundation nor the names of its
19 1.9 martin * contributors may be used to endorse or promote products derived
20 1.9 martin * from this software without specific prior written permission.
21 1.1 bsh *
22 1.1 bsh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 1.1 bsh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 1.1 bsh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 1.1 bsh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 1.1 bsh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 1.1 bsh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 1.1 bsh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 1.1 bsh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 1.1 bsh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 1.1 bsh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 1.1 bsh * POSSIBILITY OF SUCH DAMAGE.
33 1.1 bsh */
34 1.1 bsh
35 1.1 bsh /*
36 1.1 bsh * Use on-board matrix switches as wskbd.
37 1.1 bsh */
38 1.1 bsh
39 1.1 bsh #include <sys/cdefs.h>
40 1.18 andvar __KERNEL_RCSID(0, "$NetBSD: g42xxeb_kmkbd.c,v 1.18 2024/02/09 22:08:32 andvar Exp $" );
41 1.1 bsh
42 1.1 bsh #include <sys/param.h>
43 1.1 bsh #include <sys/systm.h>
44 1.1 bsh #include <sys/device.h>
45 1.1 bsh #include <sys/ioctl.h>
46 1.1 bsh #include <sys/callout.h>
47 1.1 bsh #include <sys/kernel.h> /* for hz */
48 1.1 bsh
49 1.12 dyoung #include <sys/bus.h>
50 1.1 bsh
51 1.1 bsh #include <dev/wscons/wsconsio.h>
52 1.1 bsh #include <dev/wscons/wskbdvar.h>
53 1.1 bsh #include <dev/wscons/wsksymdef.h>
54 1.1 bsh #include <dev/wscons/wsksymvar.h>
55 1.1 bsh
56 1.1 bsh #include <arch/evbarm/g42xxeb/g42xxeb_var.h>
57 1.1 bsh
58 1.1 bsh #include "locators.h"
59 1.13 bsh #include "opt_wsdisplay_compat.h"
60 1.1 bsh
61 1.1 bsh #define DEBOUNCE_TICKS ((hz<=50)?1:hz/50) /* 20ms */
62 1.1 bsh #define RELEASE_WATCH_TICKS (hz/10) /* 100ms */
63 1.1 bsh
64 1.13 bsh #define NUMKEYS (4*5) /* the number of keys */
65 1.13 bsh
66 1.1 bsh struct kmkbd_softc {
67 1.11 bsh device_t dev;
68 1.1 bsh
69 1.14 chs device_t wskbddev;
70 1.1 bsh void *ih; /* interrupt handler */
71 1.1 bsh struct callout callout;
72 1.1 bsh
73 1.1 bsh uint32_t notified_bits; /* reported state of keys */
74 1.1 bsh uint32_t last_bits; /* used for debounce */
75 1.1 bsh u_char debounce_counter;
76 1.1 bsh #define DEBOUNCE_COUNT 3
77 1.1 bsh u_char polling;
78 1.13 bsh u_char rawkbd;
79 1.1 bsh enum kmkbd_state {
80 1.1 bsh ST_INIT,
81 1.1 bsh ST_DISABLED,
82 1.1 bsh ST_ALL_UP, /* waiting for interrupt */
83 1.1 bsh ST_DEBOUNCE, /* doing debounce */
84 1.1 bsh ST_KEY_PRESSED /* some keys are pressed */
85 1.1 bsh } state;
86 1.1 bsh };
87 1.1 bsh
88 1.1 bsh
89 1.11 bsh int kmkbd_match(device_t, cfdata_t, void *);
90 1.11 bsh void kmkbd_attach(device_t, device_t, void *);
91 1.1 bsh
92 1.11 bsh CFATTACH_DECL_NEW(kmkbd, sizeof(struct kmkbd_softc),
93 1.1 bsh kmkbd_match, kmkbd_attach, NULL, NULL);
94 1.1 bsh
95 1.1 bsh static int kmkbd_enable(void *, int);
96 1.1 bsh static void kmkbd_set_leds(void *, int);
97 1.5 christos static int kmkbd_ioctl(void *, u_long, void *, int, struct lwp *);
98 1.1 bsh
99 1.1 bsh const struct wskbd_accessops kmkbd_accessops = {
100 1.1 bsh kmkbd_enable,
101 1.1 bsh kmkbd_set_leds,
102 1.1 bsh kmkbd_ioctl,
103 1.1 bsh };
104 1.1 bsh
105 1.1 bsh #if 0
106 1.1 bsh void kmkbd_cngetc(void *, u_int *, int *);
107 1.1 bsh void kmkbd_cnpollc(void *, int);
108 1.1 bsh void kmkbd_cnbell(void *, u_int, u_int, u_int);
109 1.1 bsh
110 1.1 bsh const struct wskbd_consops kmkbd_consops = {
111 1.1 bsh kmkbd_cngetc,
112 1.1 bsh kmkbd_cnpollc,
113 1.1 bsh kmkbd_cnbell,
114 1.1 bsh };
115 1.1 bsh #endif
116 1.1 bsh
117 1.1 bsh static const keysym_t kmkbd_keydesc_0[] = {
118 1.1 bsh /* pos normal shifted */
119 1.1 bsh KS_KEYCODE(0), KS_a, KS_A,
120 1.1 bsh KS_KEYCODE(1), KS_b, KS_B,
121 1.1 bsh KS_KEYCODE(2), KS_c, KS_C,
122 1.1 bsh KS_KEYCODE(3), KS_d, KS_D,
123 1.1 bsh KS_KEYCODE(4), KS_e, KS_E,
124 1.1 bsh KS_KEYCODE(5), KS_f, KS_F,
125 1.1 bsh KS_KEYCODE(6), KS_g, KS_G,
126 1.1 bsh KS_KEYCODE(7), KS_h, KS_H,
127 1.1 bsh KS_KEYCODE(8), KS_i, KS_I,
128 1.1 bsh KS_KEYCODE(9), KS_j, KS_J,
129 1.1 bsh KS_KEYCODE(10), KS_k, KS_K,
130 1.1 bsh KS_KEYCODE(11), KS_l, KS_L,
131 1.1 bsh KS_KEYCODE(12), KS_m, KS_M,
132 1.1 bsh KS_KEYCODE(13), KS_n, KS_N,
133 1.1 bsh KS_KEYCODE(14), KS_o, KS_O,
134 1.1 bsh KS_KEYCODE(15), KS_p, KS_P,
135 1.1 bsh KS_KEYCODE(16), KS_q, KS_Q,
136 1.1 bsh KS_KEYCODE(17), KS_r, KS_R,
137 1.1 bsh KS_KEYCODE(18), '\003', '\003',
138 1.1 bsh KS_KEYCODE(19), KS_Return, KS_Linefeed,
139 1.1 bsh };
140 1.1 bsh
141 1.1 bsh #define KBD_MAP(name, base, map) \
142 1.1 bsh { name, base, sizeof(map)/sizeof(keysym_t), map }
143 1.1 bsh
144 1.1 bsh static const struct wscons_keydesc kmkbd_keydesctab[] = {
145 1.1 bsh KBD_MAP(KB_MACHDEP, 0, kmkbd_keydesc_0),
146 1.1 bsh {0, 0, 0, 0}
147 1.1 bsh };
148 1.1 bsh
149 1.1 bsh const struct wskbd_mapdata kmkbd_keymapdata = {
150 1.1 bsh kmkbd_keydesctab,
151 1.1 bsh #ifdef KMKBD_LAYOUT
152 1.1 bsh KMKBD_LAYOUT,
153 1.1 bsh #else
154 1.1 bsh KB_MACHDEP,
155 1.1 bsh #endif
156 1.1 bsh };
157 1.1 bsh
158 1.1 bsh /*
159 1.18 andvar * Hackish support for a bell on the PC Keyboard; when a suitable beeper
160 1.1 bsh * is found, it attaches itself into the pckbd driver here.
161 1.1 bsh */
162 1.1 bsh void (*kmkbd_bell_fn)(void *, u_int, u_int, u_int, int);
163 1.1 bsh void *kmkbd_bell_fn_arg;
164 1.1 bsh
165 1.1 bsh void kmkbd_bell(u_int, u_int, u_int, int);
166 1.1 bsh void kmkbd_hookup_bell(void (* fn)(void *, u_int, u_int, u_int, int), void *arg);
167 1.1 bsh
168 1.1 bsh static int kmkbd_intr(void *);
169 1.1 bsh static void kmkbd_new_state(struct kmkbd_softc *, enum kmkbd_state);
170 1.1 bsh
171 1.1 bsh /*struct kmkbd_internal kmkbd_consdata;*/
172 1.1 bsh
173 1.1 bsh static int
174 1.1 bsh kmkbd_is_console(void)
175 1.1 bsh {
176 1.1 bsh #if 0
177 1.1 bsh return (kmkbd_consdata.t_isconsole &&
178 1.1 bsh (tag == kmkbd_consdata.t_kbctag) &&
179 1.1 bsh (slot == kmkbd_consdata.t_kbcslot));
180 1.1 bsh #else
181 1.1 bsh return 0;
182 1.1 bsh #endif
183 1.1 bsh }
184 1.1 bsh
185 1.1 bsh int
186 1.14 chs kmkbd_match(device_t parent, cfdata_t cf, void *aux)
187 1.1 bsh {
188 1.1 bsh return 1;
189 1.1 bsh }
190 1.1 bsh
191 1.1 bsh void
192 1.11 bsh kmkbd_attach(device_t parent, device_t self, void *aux)
193 1.1 bsh {
194 1.11 bsh struct kmkbd_softc *sc = device_private(self);
195 1.1 bsh /*struct obio_attach_args *oa = aux;*/
196 1.1 bsh int state0;
197 1.1 bsh struct wskbddev_attach_args a;
198 1.11 bsh struct obio_softc *osc = device_private(parent);
199 1.1 bsh int s;
200 1.1 bsh
201 1.1 bsh printf("\n");
202 1.1 bsh
203 1.11 bsh sc->dev = self;
204 1.1 bsh sc->state = ST_INIT;
205 1.1 bsh
206 1.1 bsh if (kmkbd_is_console()){
207 1.1 bsh a.console = 1;
208 1.1 bsh state0 = ST_ALL_UP;
209 1.1 bsh } else {
210 1.1 bsh a.console = 0;
211 1.1 bsh state0 = ST_DISABLED;
212 1.1 bsh }
213 1.1 bsh
214 1.13 bsh #ifdef WSDISPLAY_COMPAT_RAWKBD
215 1.13 bsh sc->rawkbd = 0;
216 1.13 bsh #endif
217 1.6 ad callout_init(&sc->callout, 0);
218 1.1 bsh
219 1.1 bsh s = spltty();
220 1.1 bsh sc->ih = obio_intr_establish(osc, G42XXEB_INT_KEY, IPL_TTY,
221 1.1 bsh IST_EDGE_FALLING, kmkbd_intr, (void *)sc);
222 1.1 bsh kmkbd_new_state(sc, state0);
223 1.1 bsh splx(s);
224 1.1 bsh
225 1.1 bsh a.keymap = &kmkbd_keymapdata;
226 1.1 bsh
227 1.1 bsh a.accessops = &kmkbd_accessops;
228 1.1 bsh a.accesscookie = sc;
229 1.1 bsh
230 1.1 bsh
231 1.1 bsh /* Attach the wskbd. */
232 1.16 thorpej sc->wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE);
233 1.1 bsh
234 1.1 bsh }
235 1.1 bsh
236 1.1 bsh static int
237 1.1 bsh kmkbd_enable(void *v, int on)
238 1.1 bsh {
239 1.1 bsh struct kmkbd_softc *sc = v;
240 1.1 bsh
241 1.1 bsh if (on) {
242 1.1 bsh if (sc->state != ST_DISABLED) {
243 1.1 bsh #ifdef DIAGNOSTIC
244 1.1 bsh printf("kmkbd_enable: bad enable (state=%d)\n", sc->state);
245 1.1 bsh #endif
246 1.1 bsh return (EBUSY);
247 1.1 bsh }
248 1.1 bsh
249 1.1 bsh kmkbd_new_state(sc, ST_ALL_UP);
250 1.1 bsh } else {
251 1.1 bsh #if 0
252 1.1 bsh if (sc->id->t_isconsole)
253 1.1 bsh return (EBUSY);
254 1.1 bsh #endif
255 1.1 bsh
256 1.1 bsh kmkbd_new_state(sc, ST_DISABLED);
257 1.1 bsh }
258 1.1 bsh
259 1.1 bsh return (0);
260 1.1 bsh }
261 1.1 bsh
262 1.1 bsh
263 1.1 bsh
264 1.1 bsh static void
265 1.1 bsh kmkbd_set_leds(void *v, int leds)
266 1.1 bsh {
267 1.1 bsh }
268 1.1 bsh
269 1.1 bsh static int
270 1.5 christos kmkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
271 1.1 bsh {
272 1.13 bsh #ifdef WSDISPLAY_COMPAT_RAWKBD
273 1.13 bsh struct kmkbd_softc *sc = v;
274 1.13 bsh #endif
275 1.1 bsh
276 1.1 bsh switch (cmd) {
277 1.1 bsh case WSKBDIO_GTYPE:
278 1.1 bsh *(int *)data = WSKBD_TYPE_PC_XT; /* XXX */
279 1.1 bsh return 0;
280 1.1 bsh case WSKBDIO_COMPLEXBELL:
281 1.1 bsh #define d ((struct wskbd_bell_data *)data)
282 1.1 bsh /*
283 1.1 bsh * Keyboard can't beep directly; we have an
284 1.1 bsh * externally-provided global hook to do this.
285 1.1 bsh */
286 1.1 bsh kmkbd_bell(d->pitch, d->period, d->volume, 0);
287 1.1 bsh #undef d
288 1.1 bsh return (0);
289 1.1 bsh #ifdef WSDISPLAY_COMPAT_RAWKBD
290 1.1 bsh case WSKBDIO_SETMODE:
291 1.1 bsh sc->rawkbd = (*(int *)data == WSKBD_RAW);
292 1.1 bsh return (0);
293 1.1 bsh #endif
294 1.1 bsh
295 1.1 bsh #if 0
296 1.1 bsh case WSKBDIO_SETLEDS:
297 1.1 bsh case WSKBDIO_GETLEDS:
298 1.1 bsh /* no LED support */
299 1.1 bsh #endif
300 1.1 bsh }
301 1.1 bsh return EPASSTHROUGH;
302 1.1 bsh }
303 1.1 bsh
304 1.1 bsh void
305 1.1 bsh kmkbd_bell(u_int pitch, u_int period, u_int volume, int poll)
306 1.1 bsh {
307 1.1 bsh
308 1.1 bsh if (kmkbd_bell_fn != NULL)
309 1.1 bsh (*kmkbd_bell_fn)(kmkbd_bell_fn_arg, pitch, period,
310 1.1 bsh volume, poll);
311 1.1 bsh }
312 1.1 bsh
313 1.1 bsh void
314 1.1 bsh kmkbd_hookup_bell(void (* fn)(void *, u_int, u_int, u_int, int), void *arg)
315 1.1 bsh {
316 1.1 bsh
317 1.1 bsh if (kmkbd_bell_fn == NULL) {
318 1.1 bsh kmkbd_bell_fn = fn;
319 1.1 bsh kmkbd_bell_fn_arg = arg;
320 1.1 bsh }
321 1.1 bsh }
322 1.1 bsh
323 1.1 bsh #if 0
324 1.1 bsh int
325 1.10 dsl kmkbd_cnattach(pckbc_tag_t kbctag, int kbcslot)
326 1.1 bsh {
327 1.1 bsh int res;
328 1.1 bsh
329 1.1 bsh res = kmkbd_init(&kmkbd_consdata, kbctag, kbcslot, 1);
330 1.1 bsh
331 1.1 bsh wskbd_cnattach(&kmkbd_consops, &kmkbd_consdata, &kmkbd_keymapdata);
332 1.1 bsh
333 1.1 bsh return (0);
334 1.1 bsh }
335 1.1 bsh
336 1.1 bsh void
337 1.1 bsh kmkbd_cngetc(void *v, u_int type, int *data)
338 1.1 bsh {
339 1.1 bsh struct kmkbd_internal *t = v;
340 1.1 bsh int val;
341 1.1 bsh
342 1.1 bsh for (;;) {
343 1.1 bsh val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
344 1.1 bsh if ((val != -1) && kmkbd_decode(t, val, type, data))
345 1.1 bsh return;
346 1.1 bsh }
347 1.1 bsh }
348 1.1 bsh
349 1.1 bsh void
350 1.1 bsh kmkbd_cnpollc(void *v, int on)
351 1.1 bsh {
352 1.1 bsh struct kmkbd_internal *t = v;
353 1.1 bsh
354 1.1 bsh pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
355 1.1 bsh }
356 1.1 bsh
357 1.1 bsh void
358 1.1 bsh kmkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
359 1.1 bsh {
360 1.1 bsh
361 1.1 bsh kmkbd_bell(pitch, period, volume, 1);
362 1.1 bsh }
363 1.1 bsh #endif
364 1.1 bsh
365 1.1 bsh
366 1.1 bsh /*
367 1.1 bsh * low level access to key matrix
368 1.1 bsh *
369 1.1 bsh * returns bitset of keys being pressed.
370 1.1 bsh */
371 1.1 bsh static u_int
372 1.1 bsh kmkbd_read_matrix(struct kmkbd_softc *sc)
373 1.1 bsh {
374 1.1 bsh int i;
375 1.1 bsh u_int ret, data;
376 1.11 bsh struct obio_softc *osc = device_private(device_parent(sc->dev));
377 1.1 bsh bus_space_tag_t iot = osc->sc_iot;
378 1.1 bsh bus_space_handle_t ioh = osc->sc_obioreg_ioh;
379 1.1 bsh
380 1.1 bsh #define KMDELAY() delay(3)
381 1.1 bsh
382 1.1 bsh bus_space_write_2( iot, ioh, G42XXEB_KEYSCAN, 0 );
383 1.1 bsh KMDELAY();
384 1.1 bsh
385 1.1 bsh data = KEYSCAN_SENSE_IN &
386 1.1 bsh bus_space_read_2(iot, ioh, G42XXEB_KEYSCAN);
387 1.1 bsh
388 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, KEYSCAN_SCAN_OUT);
389 1.1 bsh
390 1.1 bsh if (data == KEYSCAN_SENSE_IN)
391 1.1 bsh return 0;
392 1.1 bsh
393 1.1 bsh ret = 0;
394 1.1 bsh for( i=0; i<5; ++i ){
395 1.1 bsh /* scan one line */
396 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, ~(0x0100<<i));
397 1.1 bsh KMDELAY();
398 1.1 bsh data = bus_space_read_2(iot, ioh, G42XXEB_KEYSCAN );
399 1.1 bsh
400 1.1 bsh data = ~data & KEYSCAN_SENSE_IN;
401 1.1 bsh ret |= data << (i*4);
402 1.1 bsh }
403 1.1 bsh
404 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, KEYSCAN_SCAN_OUT);
405 1.1 bsh return ret;
406 1.1 bsh
407 1.1 bsh #undef KMDELAY
408 1.1 bsh
409 1.1 bsh }
410 1.1 bsh
411 1.1 bsh /*
412 1.1 bsh * report key status change to wskbd subsystem.
413 1.1 bsh */
414 1.1 bsh static void
415 1.1 bsh kmkbd_report(struct kmkbd_softc *sc, u_int bitset)
416 1.1 bsh {
417 1.1 bsh u_int changed;
418 1.1 bsh int i;
419 1.1 bsh
420 1.1 bsh if (bitset == sc->notified_bits)
421 1.1 bsh return;
422 1.1 bsh
423 1.1 bsh if (sc->notified_bits && bitset == 0){
424 1.1 bsh wskbd_input(sc->wskbddev, WSCONS_EVENT_ALL_KEYS_UP, 0);
425 1.1 bsh sc->notified_bits = 0;
426 1.1 bsh return;
427 1.1 bsh }
428 1.1 bsh
429 1.1 bsh changed = bitset ^ sc->notified_bits;
430 1.1 bsh for( i=0; changed; ++i){
431 1.1 bsh if ((changed & (1<<i)) == 0)
432 1.1 bsh continue;
433 1.1 bsh changed &= ~(1<<i);
434 1.1 bsh
435 1.1 bsh wskbd_input(sc->wskbddev,
436 1.1 bsh (bitset & (1<<i)) ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP,
437 1.1 bsh i);
438 1.1 bsh }
439 1.1 bsh
440 1.1 bsh sc->notified_bits = bitset;
441 1.1 bsh }
442 1.1 bsh
443 1.13 bsh #ifdef WSDISPLAY_COMPAT_RAWKBD
444 1.13 bsh static void
445 1.13 bsh kmkbd_report_raw(struct kmkbd_softc *sc, u_int bitset)
446 1.13 bsh {
447 1.13 bsh int i, nc;
448 1.13 bsh char cbuf[NUMKEYS];
449 1.13 bsh u_int changed;
450 1.13 bsh
451 1.13 bsh if (bitset == sc->notified_bits)
452 1.13 bsh return;
453 1.13 bsh
454 1.13 bsh nc = 0;
455 1.13 bsh changed = bitset ^ sc->notified_bits;
456 1.13 bsh
457 1.13 bsh while (changed) {
458 1.13 bsh i = ffs(changed) - 1;
459 1.13 bsh if (nc < NUMKEYS) {
460 1.13 bsh cbuf[nc] = i + 1;
461 1.13 bsh if (0 == (bitset & (1<<i))) {
462 1.13 bsh /* the key is released */
463 1.13 bsh cbuf[nc] |= 0x80;
464 1.13 bsh }
465 1.13 bsh ++nc;
466 1.13 bsh }
467 1.13 bsh
468 1.13 bsh changed &= ~(1<<i);
469 1.13 bsh }
470 1.13 bsh
471 1.13 bsh wskbd_rawinput(sc->wskbddev, cbuf, nc);
472 1.13 bsh sc->notified_bits = bitset;
473 1.13 bsh }
474 1.13 bsh #endif
475 1.13 bsh
476 1.1 bsh static int
477 1.1 bsh kmkbd_intr(void *arg)
478 1.1 bsh {
479 1.1 bsh struct kmkbd_softc *sc = arg;
480 1.11 bsh struct obio_softc *osc = device_private(device_parent(sc->dev));
481 1.1 bsh
482 1.1 bsh if ( sc->state != ST_ALL_UP ){
483 1.1 bsh printf("Spurious interrupt from key matrix\n");
484 1.1 bsh obio_intr_mask(osc, sc->ih);
485 1.1 bsh return 1;
486 1.1 bsh }
487 1.1 bsh
488 1.1 bsh kmkbd_new_state(sc, ST_DEBOUNCE);
489 1.1 bsh
490 1.1 bsh return 1;
491 1.1 bsh }
492 1.1 bsh
493 1.1 bsh static void
494 1.1 bsh kmkbd_debounce(void *arg)
495 1.1 bsh {
496 1.1 bsh struct kmkbd_softc *sc = arg;
497 1.1 bsh u_int newbits;
498 1.1 bsh enum kmkbd_state new_state = ST_DEBOUNCE;
499 1.1 bsh int s = spltty();
500 1.1 bsh
501 1.1 bsh newbits = kmkbd_read_matrix(sc);
502 1.1 bsh
503 1.1 bsh if (newbits != sc->last_bits){
504 1.1 bsh sc->last_bits = newbits;
505 1.1 bsh sc->debounce_counter = 0;
506 1.1 bsh }
507 1.1 bsh else if( ++(sc->debounce_counter) >= DEBOUNCE_COUNT ){
508 1.1 bsh new_state = newbits == 0 ? ST_ALL_UP : ST_KEY_PRESSED;
509 1.13 bsh #ifdef WSDISPLAY_COMPAT_RAWKBD
510 1.13 bsh if (sc->rawkbd)
511 1.13 bsh kmkbd_report_raw(sc, newbits);
512 1.13 bsh else
513 1.13 bsh #endif
514 1.13 bsh kmkbd_report(sc, newbits);
515 1.1 bsh }
516 1.1 bsh
517 1.1 bsh kmkbd_new_state(sc, new_state);
518 1.1 bsh splx(s);
519 1.1 bsh }
520 1.1 bsh
521 1.1 bsh /* callout routine to watch key release */
522 1.1 bsh static void
523 1.1 bsh kmkbd_watch(void *arg)
524 1.1 bsh {
525 1.1 bsh int s = spltty();
526 1.1 bsh struct kmkbd_softc *sc = arg;
527 1.1 bsh u_int newbits;
528 1.1 bsh int new_state = ST_KEY_PRESSED;
529 1.1 bsh
530 1.1 bsh newbits = kmkbd_read_matrix(sc);
531 1.1 bsh
532 1.1 bsh if (newbits != sc->last_bits){
533 1.1 bsh /* some keys are released or new keys are pressed.
534 1.1 bsh start debounce */
535 1.1 bsh new_state = ST_DEBOUNCE;
536 1.1 bsh sc->last_bits = newbits;
537 1.1 bsh }
538 1.1 bsh
539 1.1 bsh kmkbd_new_state(sc, new_state);
540 1.1 bsh splx(s);
541 1.1 bsh }
542 1.1 bsh
543 1.1 bsh static void
544 1.1 bsh kmkbd_new_state(struct kmkbd_softc *sc, enum kmkbd_state new_state)
545 1.1 bsh {
546 1.11 bsh struct obio_softc *osc = device_private(device_parent(sc->dev));
547 1.1 bsh
548 1.1 bsh switch(new_state){
549 1.1 bsh case ST_DISABLED:
550 1.1 bsh if (sc->state != ST_DISABLED){
551 1.1 bsh callout_stop(&sc->callout);
552 1.1 bsh obio_intr_mask(osc,sc->ih);
553 1.1 bsh }
554 1.1 bsh break;
555 1.1 bsh case ST_DEBOUNCE:
556 1.1 bsh if (sc->state == ST_ALL_UP){
557 1.1 bsh obio_intr_mask(osc, sc->ih);
558 1.1 bsh sc->last_bits = kmkbd_read_matrix(sc);
559 1.1 bsh }
560 1.1 bsh if (sc->state != ST_DEBOUNCE)
561 1.1 bsh sc->debounce_counter = 0;
562 1.1 bsh
563 1.1 bsh /* start debounce timer */
564 1.1 bsh callout_reset(&sc->callout, DEBOUNCE_TICKS, kmkbd_debounce, sc);
565 1.1 bsh break;
566 1.1 bsh case ST_KEY_PRESSED:
567 1.1 bsh /* start timer to check key release */
568 1.1 bsh callout_reset(&sc->callout, RELEASE_WATCH_TICKS, kmkbd_watch, sc);
569 1.1 bsh break;
570 1.1 bsh case ST_ALL_UP:
571 1.1 bsh if (sc->state != ST_ALL_UP){
572 1.1 bsh bus_space_tag_t iot = osc->sc_iot;
573 1.1 bsh bus_space_handle_t ioh = osc->sc_obioreg_ioh;
574 1.1 bsh
575 1.1 bsh obio_intr_unmask(osc, sc->ih);
576 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, 0);
577 1.1 bsh }
578 1.1 bsh break;
579 1.1 bsh case ST_INIT:
580 1.1 bsh ; /* Nothing to do */
581 1.1 bsh }
582 1.1 bsh
583 1.1 bsh sc->state = new_state;
584 1.1 bsh }
585