g42xxeb_kmkbd.c revision 1.1 1 1.1 bsh /* $NetBSD: g42xxeb_kmkbd.c,v 1.1 2005/02/26 10:49:53 bsh 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.1 bsh * 3. Neither the name of The NetBSD Foundation nor the names of its
19 1.1 bsh * contributors may be used to endorse or promote products derived
20 1.1 bsh * 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.1 bsh __KERNEL_RCSID(0, "$NetBSD: g42xxeb_kmkbd.c,v 1.1 2005/02/26 10:49:53 bsh 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/malloc.h>
46 1.1 bsh #include <sys/ioctl.h>
47 1.1 bsh #include <sys/callout.h>
48 1.1 bsh #include <sys/kernel.h> /* for hz */
49 1.1 bsh
50 1.1 bsh #include <machine/bus.h>
51 1.1 bsh
52 1.1 bsh #include <dev/wscons/wsconsio.h>
53 1.1 bsh #include <dev/wscons/wskbdvar.h>
54 1.1 bsh #include <dev/wscons/wsksymdef.h>
55 1.1 bsh #include <dev/wscons/wsksymvar.h>
56 1.1 bsh
57 1.1 bsh #include <arch/evbarm/g42xxeb/g42xxeb_var.h>
58 1.1 bsh
59 1.1 bsh #include "locators.h"
60 1.1 bsh
61 1.1 bsh /*#include "opt_pckbd_layout.h"*/
62 1.1 bsh /*#include "opt_wsdisplay_compat.h"*/
63 1.1 bsh
64 1.1 bsh #define DEBOUNCE_TICKS ((hz<=50)?1:hz/50) /* 20ms */
65 1.1 bsh #define RELEASE_WATCH_TICKS (hz/10) /* 100ms */
66 1.1 bsh
67 1.1 bsh struct kmkbd_softc {
68 1.1 bsh struct device dev;
69 1.1 bsh
70 1.1 bsh struct device *wskbddev;
71 1.1 bsh void *ih; /* interrupt handler */
72 1.1 bsh struct callout callout;
73 1.1 bsh
74 1.1 bsh uint32_t notified_bits; /* reported state of keys */
75 1.1 bsh uint32_t last_bits; /* used for debounce */
76 1.1 bsh u_char debounce_counter;
77 1.1 bsh #define DEBOUNCE_COUNT 3
78 1.1 bsh u_char polling;
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.1 bsh int kmkbd_match(struct device *, struct cfdata *, void *);
90 1.1 bsh void kmkbd_attach(struct device *, struct device *, void *);
91 1.1 bsh
92 1.1 bsh CFATTACH_DECL(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.1 bsh static int kmkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
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.1 bsh * Hackish support for a bell on the PC Keyboard; when a suitable feeper
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.1 bsh kmkbd_match(struct device *parent, struct cfdata *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.1 bsh kmkbd_attach(struct device *parent, struct device *self, void *aux)
193 1.1 bsh {
194 1.1 bsh struct kmkbd_softc *sc = (void *)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.1 bsh struct obio_softc *osc = (struct obio_softc *)parent;
199 1.1 bsh int s;
200 1.1 bsh
201 1.1 bsh printf("\n");
202 1.1 bsh
203 1.1 bsh sc->state = ST_INIT;
204 1.1 bsh
205 1.1 bsh if (kmkbd_is_console()){
206 1.1 bsh a.console = 1;
207 1.1 bsh state0 = ST_ALL_UP;
208 1.1 bsh } else {
209 1.1 bsh a.console = 0;
210 1.1 bsh state0 = ST_DISABLED;
211 1.1 bsh }
212 1.1 bsh
213 1.1 bsh callout_init(&sc->callout);
214 1.1 bsh
215 1.1 bsh s = spltty();
216 1.1 bsh sc->ih = obio_intr_establish(osc, G42XXEB_INT_KEY, IPL_TTY,
217 1.1 bsh IST_EDGE_FALLING, kmkbd_intr, (void *)sc);
218 1.1 bsh kmkbd_new_state(sc, state0);
219 1.1 bsh splx(s);
220 1.1 bsh
221 1.1 bsh a.keymap = &kmkbd_keymapdata;
222 1.1 bsh
223 1.1 bsh a.accessops = &kmkbd_accessops;
224 1.1 bsh a.accesscookie = sc;
225 1.1 bsh
226 1.1 bsh
227 1.1 bsh /* Attach the wskbd. */
228 1.1 bsh sc->wskbddev = config_found(self, &a, wskbddevprint);
229 1.1 bsh
230 1.1 bsh }
231 1.1 bsh
232 1.1 bsh static int
233 1.1 bsh kmkbd_enable(void *v, int on)
234 1.1 bsh {
235 1.1 bsh struct kmkbd_softc *sc = v;
236 1.1 bsh
237 1.1 bsh if (on) {
238 1.1 bsh if (sc->state != ST_DISABLED) {
239 1.1 bsh #ifdef DIAGNOSTIC
240 1.1 bsh printf("kmkbd_enable: bad enable (state=%d)\n", sc->state);
241 1.1 bsh #endif
242 1.1 bsh return (EBUSY);
243 1.1 bsh }
244 1.1 bsh
245 1.1 bsh kmkbd_new_state(sc, ST_ALL_UP);
246 1.1 bsh } else {
247 1.1 bsh #if 0
248 1.1 bsh if (sc->id->t_isconsole)
249 1.1 bsh return (EBUSY);
250 1.1 bsh #endif
251 1.1 bsh
252 1.1 bsh kmkbd_new_state(sc, ST_DISABLED);
253 1.1 bsh }
254 1.1 bsh
255 1.1 bsh return (0);
256 1.1 bsh }
257 1.1 bsh
258 1.1 bsh
259 1.1 bsh
260 1.1 bsh static void
261 1.1 bsh kmkbd_set_leds(void *v, int leds)
262 1.1 bsh {
263 1.1 bsh }
264 1.1 bsh
265 1.1 bsh static int
266 1.1 bsh kmkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
267 1.1 bsh {
268 1.1 bsh /*struct kmkbd_softc *sc = v;*/
269 1.1 bsh
270 1.1 bsh switch (cmd) {
271 1.1 bsh case WSKBDIO_GTYPE:
272 1.1 bsh *(int *)data = WSKBD_TYPE_PC_XT; /* XXX */
273 1.1 bsh return 0;
274 1.1 bsh case WSKBDIO_COMPLEXBELL:
275 1.1 bsh #define d ((struct wskbd_bell_data *)data)
276 1.1 bsh /*
277 1.1 bsh * Keyboard can't beep directly; we have an
278 1.1 bsh * externally-provided global hook to do this.
279 1.1 bsh */
280 1.1 bsh kmkbd_bell(d->pitch, d->period, d->volume, 0);
281 1.1 bsh #undef d
282 1.1 bsh return (0);
283 1.1 bsh #ifdef WSDISPLAY_COMPAT_RAWKBD
284 1.1 bsh case WSKBDIO_SETMODE:
285 1.1 bsh sc->rawkbd = (*(int *)data == WSKBD_RAW);
286 1.1 bsh return (0);
287 1.1 bsh #endif
288 1.1 bsh
289 1.1 bsh #if 0
290 1.1 bsh case WSKBDIO_SETLEDS:
291 1.1 bsh case WSKBDIO_GETLEDS:
292 1.1 bsh /* no LED support */
293 1.1 bsh #endif
294 1.1 bsh }
295 1.1 bsh return EPASSTHROUGH;
296 1.1 bsh }
297 1.1 bsh
298 1.1 bsh void
299 1.1 bsh kmkbd_bell(u_int pitch, u_int period, u_int volume, int poll)
300 1.1 bsh {
301 1.1 bsh
302 1.1 bsh if (kmkbd_bell_fn != NULL)
303 1.1 bsh (*kmkbd_bell_fn)(kmkbd_bell_fn_arg, pitch, period,
304 1.1 bsh volume, poll);
305 1.1 bsh }
306 1.1 bsh
307 1.1 bsh void
308 1.1 bsh kmkbd_hookup_bell(void (* fn)(void *, u_int, u_int, u_int, int), void *arg)
309 1.1 bsh {
310 1.1 bsh
311 1.1 bsh if (kmkbd_bell_fn == NULL) {
312 1.1 bsh kmkbd_bell_fn = fn;
313 1.1 bsh kmkbd_bell_fn_arg = arg;
314 1.1 bsh }
315 1.1 bsh }
316 1.1 bsh
317 1.1 bsh #if 0
318 1.1 bsh int
319 1.1 bsh kmkbd_cnattach(kbctag, kbcslot)
320 1.1 bsh pckbc_tag_t kbctag;
321 1.1 bsh int kbcslot;
322 1.1 bsh {
323 1.1 bsh int res;
324 1.1 bsh
325 1.1 bsh res = kmkbd_init(&kmkbd_consdata, kbctag, kbcslot, 1);
326 1.1 bsh
327 1.1 bsh wskbd_cnattach(&kmkbd_consops, &kmkbd_consdata, &kmkbd_keymapdata);
328 1.1 bsh
329 1.1 bsh return (0);
330 1.1 bsh }
331 1.1 bsh
332 1.1 bsh void
333 1.1 bsh kmkbd_cngetc(void *v, u_int type, int *data)
334 1.1 bsh {
335 1.1 bsh struct kmkbd_internal *t = v;
336 1.1 bsh int val;
337 1.1 bsh
338 1.1 bsh for (;;) {
339 1.1 bsh val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
340 1.1 bsh if ((val != -1) && kmkbd_decode(t, val, type, data))
341 1.1 bsh return;
342 1.1 bsh }
343 1.1 bsh }
344 1.1 bsh
345 1.1 bsh void
346 1.1 bsh kmkbd_cnpollc(void *v, int on)
347 1.1 bsh {
348 1.1 bsh struct kmkbd_internal *t = v;
349 1.1 bsh
350 1.1 bsh pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
351 1.1 bsh }
352 1.1 bsh
353 1.1 bsh void
354 1.1 bsh kmkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
355 1.1 bsh {
356 1.1 bsh
357 1.1 bsh kmkbd_bell(pitch, period, volume, 1);
358 1.1 bsh }
359 1.1 bsh #endif
360 1.1 bsh
361 1.1 bsh
362 1.1 bsh /*
363 1.1 bsh * low level access to key matrix
364 1.1 bsh *
365 1.1 bsh * returns bitset of keys being pressed.
366 1.1 bsh */
367 1.1 bsh static u_int
368 1.1 bsh kmkbd_read_matrix(struct kmkbd_softc *sc)
369 1.1 bsh {
370 1.1 bsh int i;
371 1.1 bsh u_int ret, data;
372 1.1 bsh struct obio_softc *osc = (struct obio_softc *)(sc->dev.dv_parent);
373 1.1 bsh bus_space_tag_t iot = osc->sc_iot;
374 1.1 bsh bus_space_handle_t ioh = osc->sc_obioreg_ioh;
375 1.1 bsh
376 1.1 bsh #define KMDELAY() delay(3)
377 1.1 bsh
378 1.1 bsh bus_space_write_2( iot, ioh, G42XXEB_KEYSCAN, 0 );
379 1.1 bsh KMDELAY();
380 1.1 bsh
381 1.1 bsh data = KEYSCAN_SENSE_IN &
382 1.1 bsh bus_space_read_2(iot, ioh, G42XXEB_KEYSCAN);
383 1.1 bsh
384 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, KEYSCAN_SCAN_OUT);
385 1.1 bsh
386 1.1 bsh if (data == KEYSCAN_SENSE_IN)
387 1.1 bsh return 0;
388 1.1 bsh
389 1.1 bsh ret = 0;
390 1.1 bsh for( i=0; i<5; ++i ){
391 1.1 bsh /* scan one line */
392 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, ~(0x0100<<i));
393 1.1 bsh KMDELAY();
394 1.1 bsh data = bus_space_read_2(iot, ioh, G42XXEB_KEYSCAN );
395 1.1 bsh
396 1.1 bsh data = ~data & KEYSCAN_SENSE_IN;
397 1.1 bsh ret |= data << (i*4);
398 1.1 bsh }
399 1.1 bsh
400 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, KEYSCAN_SCAN_OUT);
401 1.1 bsh return ret;
402 1.1 bsh
403 1.1 bsh #undef KMDELAY
404 1.1 bsh
405 1.1 bsh }
406 1.1 bsh
407 1.1 bsh /*
408 1.1 bsh * report key status change to wskbd subsystem.
409 1.1 bsh */
410 1.1 bsh static void
411 1.1 bsh kmkbd_report(struct kmkbd_softc *sc, u_int bitset)
412 1.1 bsh {
413 1.1 bsh u_int changed;
414 1.1 bsh int i;
415 1.1 bsh
416 1.1 bsh if (bitset == sc->notified_bits)
417 1.1 bsh return;
418 1.1 bsh
419 1.1 bsh if (sc->notified_bits && bitset == 0){
420 1.1 bsh wskbd_input(sc->wskbddev, WSCONS_EVENT_ALL_KEYS_UP, 0);
421 1.1 bsh sc->notified_bits = 0;
422 1.1 bsh return;
423 1.1 bsh }
424 1.1 bsh
425 1.1 bsh changed = bitset ^ sc->notified_bits;
426 1.1 bsh for( i=0; changed; ++i){
427 1.1 bsh if ((changed & (1<<i)) == 0)
428 1.1 bsh continue;
429 1.1 bsh changed &= ~(1<<i);
430 1.1 bsh
431 1.1 bsh wskbd_input(sc->wskbddev,
432 1.1 bsh (bitset & (1<<i)) ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP,
433 1.1 bsh i);
434 1.1 bsh }
435 1.1 bsh
436 1.1 bsh sc->notified_bits = bitset;
437 1.1 bsh }
438 1.1 bsh
439 1.1 bsh static int
440 1.1 bsh kmkbd_intr(void *arg)
441 1.1 bsh {
442 1.1 bsh struct kmkbd_softc *sc = arg;
443 1.1 bsh struct obio_softc *osc = (struct obio_softc *)(sc->dev.dv_parent);
444 1.1 bsh
445 1.1 bsh if ( sc->state != ST_ALL_UP ){
446 1.1 bsh printf("Spurious interrupt from key matrix\n");
447 1.1 bsh obio_intr_mask(osc, sc->ih);
448 1.1 bsh return 1;
449 1.1 bsh }
450 1.1 bsh
451 1.1 bsh kmkbd_new_state(sc, ST_DEBOUNCE);
452 1.1 bsh
453 1.1 bsh return 1;
454 1.1 bsh }
455 1.1 bsh
456 1.1 bsh static void
457 1.1 bsh kmkbd_debounce(void *arg)
458 1.1 bsh {
459 1.1 bsh struct kmkbd_softc *sc = arg;
460 1.1 bsh u_int newbits;
461 1.1 bsh enum kmkbd_state new_state = ST_DEBOUNCE;
462 1.1 bsh int s = spltty();
463 1.1 bsh
464 1.1 bsh newbits = kmkbd_read_matrix(sc);
465 1.1 bsh
466 1.1 bsh if (newbits != sc->last_bits){
467 1.1 bsh sc->last_bits = newbits;
468 1.1 bsh sc->debounce_counter = 0;
469 1.1 bsh }
470 1.1 bsh else if( ++(sc->debounce_counter) >= DEBOUNCE_COUNT ){
471 1.1 bsh new_state = newbits == 0 ? ST_ALL_UP : ST_KEY_PRESSED;
472 1.1 bsh kmkbd_report(sc, newbits);
473 1.1 bsh }
474 1.1 bsh
475 1.1 bsh kmkbd_new_state(sc, new_state);
476 1.1 bsh splx(s);
477 1.1 bsh }
478 1.1 bsh
479 1.1 bsh /* callout routine to watch key release */
480 1.1 bsh static void
481 1.1 bsh kmkbd_watch(void *arg)
482 1.1 bsh {
483 1.1 bsh int s = spltty();
484 1.1 bsh struct kmkbd_softc *sc = arg;
485 1.1 bsh u_int newbits;
486 1.1 bsh int new_state = ST_KEY_PRESSED;
487 1.1 bsh
488 1.1 bsh newbits = kmkbd_read_matrix(sc);
489 1.1 bsh
490 1.1 bsh if (newbits != sc->last_bits){
491 1.1 bsh /* some keys are released or new keys are pressed.
492 1.1 bsh start debounce */
493 1.1 bsh new_state = ST_DEBOUNCE;
494 1.1 bsh sc->last_bits = newbits;
495 1.1 bsh }
496 1.1 bsh
497 1.1 bsh kmkbd_new_state(sc, new_state);
498 1.1 bsh splx(s);
499 1.1 bsh }
500 1.1 bsh
501 1.1 bsh static void
502 1.1 bsh kmkbd_new_state(struct kmkbd_softc *sc, enum kmkbd_state new_state)
503 1.1 bsh {
504 1.1 bsh struct obio_softc *osc = (struct obio_softc *)(sc->dev.dv_parent);
505 1.1 bsh
506 1.1 bsh switch(new_state){
507 1.1 bsh case ST_DISABLED:
508 1.1 bsh if (sc->state != ST_DISABLED){
509 1.1 bsh callout_stop(&sc->callout);
510 1.1 bsh obio_intr_mask(osc,sc->ih);
511 1.1 bsh }
512 1.1 bsh break;
513 1.1 bsh case ST_DEBOUNCE:
514 1.1 bsh if (sc->state == ST_ALL_UP){
515 1.1 bsh obio_intr_mask(osc, sc->ih);
516 1.1 bsh sc->last_bits = kmkbd_read_matrix(sc);
517 1.1 bsh }
518 1.1 bsh if (sc->state != ST_DEBOUNCE)
519 1.1 bsh sc->debounce_counter = 0;
520 1.1 bsh
521 1.1 bsh /* start debounce timer */
522 1.1 bsh callout_reset(&sc->callout, DEBOUNCE_TICKS, kmkbd_debounce, sc);
523 1.1 bsh break;
524 1.1 bsh case ST_KEY_PRESSED:
525 1.1 bsh /* start timer to check key release */
526 1.1 bsh callout_reset(&sc->callout, RELEASE_WATCH_TICKS, kmkbd_watch, sc);
527 1.1 bsh break;
528 1.1 bsh case ST_ALL_UP:
529 1.1 bsh if (sc->state != ST_ALL_UP){
530 1.1 bsh bus_space_tag_t iot = osc->sc_iot;
531 1.1 bsh bus_space_handle_t ioh = osc->sc_obioreg_ioh;
532 1.1 bsh
533 1.1 bsh obio_intr_unmask(osc, sc->ih);
534 1.1 bsh bus_space_write_2(iot, ioh, G42XXEB_KEYSCAN, 0);
535 1.1 bsh }
536 1.1 bsh break;
537 1.1 bsh case ST_INIT:
538 1.1 bsh ; /* Nothing to do */
539 1.1 bsh }
540 1.1 bsh
541 1.1 bsh sc->state = new_state;
542 1.1 bsh }
543