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