xref: /netbsd-src/sys/arch/zaurus/dev/zkbd.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: zkbd.c,v 1.7 2007/10/17 19:58:34 garbled Exp $	*/
2 /* $OpenBSD: zaurus_kbd.c,v 1.28 2005/12/21 20:36:03 deraadt Exp $ */
3 
4 /*
5  * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: zkbd.c,v 1.7 2007/10/17 19:58:34 garbled Exp $");
22 
23 #include "opt_wsdisplay_compat.h"
24 #include "lcd.h"
25 #if 0	/* XXX */
26 #include "apm.h"
27 #endif
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/malloc.h>
33 #include <sys/kernel.h>
34 #include <sys/proc.h>
35 #include <sys/signalvar.h>
36 #include <sys/callout.h>
37 
38 #include <arm/xscale/pxa2x0reg.h>
39 #include <arm/xscale/pxa2x0_gpio.h>
40 
41 #include <dev/wscons/wsconsio.h>
42 #include <dev/wscons/wskbdvar.h>
43 #include <dev/wscons/wsksymdef.h>
44 #include <dev/wscons/wsksymvar.h>
45 
46 #include <zaurus/dev/zkbdmap.h>
47 #include <zaurus/zaurus/zaurus_var.h>
48 
49 static const int gpio_sense_pins_c3000[] = {
50 	12,
51 	17,
52 	91,
53 	34,
54 	36,
55 	38,
56 	39,
57 	-1
58 };
59 
60 static const int gpio_strobe_pins_c3000[] = {
61 	88,
62 	23,
63 	24,
64 	25,
65 	26,
66 	27,
67 	52,
68 	103,
69 	107,
70 	-1,
71 	108,
72 	114
73 };
74 
75 static const int stuck_keys[] = {
76 	7,
77 	15,
78 	23,
79 	31
80 };
81 
82 #define REP_DELAY1 400
83 #define REP_DELAYN 100
84 
85 struct zkbd_softc {
86 	struct device sc_dev;
87 
88 	const int *sc_sense_array;
89 	const int *sc_strobe_array;
90 	int sc_nsense;
91 	int sc_nstrobe;
92 
93 	short sc_onkey_pin;
94 	short sc_sync_pin;
95 	short sc_swa_pin;
96 	short sc_swb_pin;
97 	char *sc_okeystate;
98 	char *sc_keystate;
99 	char sc_hinge;		/* 0=open, 1=nonsense, 2=backwards, 3=closed */
100 	char sc_maxkbdcol;
101 
102 	struct callout sc_roll_to;
103 
104 	/* console stuff */
105 	int sc_polling;
106 	int sc_pollUD;
107 	int sc_pollkey;
108 
109 	/* wskbd bits */
110 	struct device *sc_wskbddev;
111 	int sc_rawkbd;
112 #ifdef WSDISPLAY_COMPAT_RAWKBD
113 	const char *sc_xt_keymap;
114 	struct callout sc_rawrepeat_ch;
115 #define MAXKEYS 20
116 	char sc_rep[MAXKEYS];
117 	int sc_nrep;
118 #endif
119 	void *sc_powerhook;
120 };
121 
122 static struct zkbd_softc *zkbd_sc;
123 
124 static int	zkbd_match(struct device *, struct cfdata *, void *);
125 static void	zkbd_attach(struct device *, struct device *, void *);
126 
127 CFATTACH_DECL(zkbd, sizeof(struct zkbd_softc),
128 	zkbd_match, zkbd_attach, NULL, NULL);
129 
130 static int	zkbd_irq(void *v);
131 static void	zkbd_poll(void *v);
132 static int	zkbd_on(void *v);
133 static int	zkbd_sync(void *v);
134 static int	zkbd_hinge(void *v);
135 static void	zkbd_power(int why, void *arg);
136 
137 int zkbd_modstate;
138 
139 static int	zkbd_enable(void *, int);
140 static void	zkbd_set_leds(void *, int);
141 static int	zkbd_ioctl(void *, u_long, void *, int, struct lwp *);
142 #ifdef WSDISPLAY_COMPAT_RAWKBD
143 static void	zkbd_rawrepeat(void *v);
144 #endif
145 
146 static struct wskbd_accessops zkbd_accessops = {
147 	zkbd_enable,
148 	zkbd_set_leds,
149 	zkbd_ioctl,
150 };
151 
152 static void	zkbd_cngetc(void *, u_int *, int *);
153 static void	zkbd_cnpollc(void *, int);
154 
155 static struct wskbd_consops zkbd_consops = {
156 	zkbd_cngetc,
157 	zkbd_cnpollc,
158 };
159 
160 static struct wskbd_mapdata zkbd_keymapdata = {
161 	zkbd_keydesctab,
162 	KB_US,
163 };
164 
165 static int
166 zkbd_match(struct device *parent, struct cfdata *cf, void *aux)
167 {
168 
169 	if (zkbd_sc)
170 		return 0;
171 
172 	return 1;
173 }
174 
175 static void
176 zkbd_attach(struct device *parent, struct device *self, void *aux)
177 {
178 	struct zkbd_softc *sc = (struct zkbd_softc *)self;
179 	struct wskbddev_attach_args a;
180 	int pin, i;
181 
182 	zkbd_sc = sc;
183 
184 	printf("\n");
185 
186 	sc->sc_polling = 0;
187 #ifdef WSDISPLAY_COMPAT_RAWKBD
188 	sc->sc_rawkbd = 0;
189 #endif
190 
191 	callout_init(&sc->sc_roll_to, 0);
192 	callout_setfunc(&sc->sc_roll_to, zkbd_poll, sc);
193 #ifdef WSDISPLAY_COMPAT_RAWKBD
194 	callout_init(&sc->sc_rawrepeat_ch, 0);
195 	callout_setfunc(&sc->sc_rawrepeat_ch, zkbd_rawrepeat, sc);
196 #endif
197 
198 	if (ZAURUS_ISC3000) {
199 		sc->sc_sense_array = gpio_sense_pins_c3000;
200 		sc->sc_strobe_array = gpio_strobe_pins_c3000;
201 		sc->sc_nsense = __arraycount(gpio_sense_pins_c3000);
202 		sc->sc_nstrobe = __arraycount(gpio_strobe_pins_c3000);
203 		sc->sc_maxkbdcol = 10;
204 		sc->sc_onkey_pin = 95;
205 		sc->sc_sync_pin = 16;
206 		sc->sc_swa_pin = 97;
207 		sc->sc_swb_pin = 96;
208 #ifdef WSDISPLAY_COMPAT_RAWKBD
209 		sc->sc_xt_keymap = xt_keymap;
210 #endif
211 	} else {
212 		/* XXX */
213 		return;
214 	}
215 
216 	sc->sc_powerhook = powerhook_establish(sc->sc_dev.dv_xname,
217 	    zkbd_power, sc);
218 	if (sc->sc_powerhook == NULL) {
219 		printf("%s: unable to establish powerhook\n",
220 		    sc->sc_dev.dv_xname);
221 		return;
222 	}
223 
224 	sc->sc_okeystate = malloc(sc->sc_nsense * sc->sc_nstrobe,
225 	    M_DEVBUF, M_NOWAIT);
226 	memset(sc->sc_okeystate, 0, sc->sc_nsense * sc->sc_nstrobe);
227 
228 	sc->sc_keystate = malloc(sc->sc_nsense * sc->sc_nstrobe,
229 	    M_DEVBUF, M_NOWAIT);
230 	memset(sc->sc_keystate, 0, sc->sc_nsense * sc->sc_nstrobe);
231 
232 	/* set all the strobe bits */
233 	for (i = 0; i < sc->sc_nstrobe; i++) {
234 		pin = sc->sc_strobe_array[i];
235 		if (pin == -1)
236 			continue;
237 		pxa2x0_gpio_set_function(pin, GPIO_SET|GPIO_OUT);
238 	}
239 
240 	/* set all the sense bits */
241 	for (i = 0; i < sc->sc_nsense; i++) {
242 		pin = sc->sc_sense_array[i];
243 		if (pin == -1)
244 			continue;
245 		pxa2x0_gpio_set_function(pin, GPIO_IN);
246 		pxa2x0_gpio_intr_establish(pin, IST_EDGE_BOTH, IPL_TTY,
247 		    zkbd_irq, sc);
248 	}
249 
250 	pxa2x0_gpio_intr_establish(sc->sc_onkey_pin, IST_EDGE_BOTH, IPL_TTY,
251 	    zkbd_on, sc);
252 	pxa2x0_gpio_intr_establish(sc->sc_sync_pin, IST_EDGE_RISING, IPL_TTY,
253 	    zkbd_sync, sc);
254 	pxa2x0_gpio_intr_establish(sc->sc_swa_pin, IST_EDGE_BOTH, IPL_TTY,
255 	    zkbd_hinge, sc);
256 	pxa2x0_gpio_intr_establish(sc->sc_swb_pin, IST_EDGE_BOTH, IPL_TTY,
257 	    zkbd_hinge, sc);
258 
259 	if (glass_console) {
260 		wskbd_cnattach(&zkbd_consops, sc, &zkbd_keymapdata);
261 		a.console = 1;
262 	} else {
263 		a.console = 0;
264 	}
265 	a.keymap = &zkbd_keymapdata;
266 	a.accessops = &zkbd_accessops;
267 	a.accesscookie = sc;
268 
269 	zkbd_hinge(sc);		/* to initialize sc_hinge */
270 
271 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
272 }
273 
274 #ifdef WSDISPLAY_COMPAT_RAWKBD
275 static void
276 zkbd_rawrepeat(void *v)
277 {
278 	struct zkbd_softc *sc = (struct zkbd_softc *)v;
279 	int s;
280 
281 	s = spltty();
282 	wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
283 	splx(s);
284 	callout_schedule(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000);
285 }
286 #endif
287 
288 /* XXX only deal with keys that can be pressed when display is open? */
289 /* XXX are some not in the array? */
290 /* handle keypress interrupt */
291 static int
292 zkbd_irq(void *v)
293 {
294 
295 	zkbd_poll(v);
296 
297 	return 1;
298 }
299 
300 static void
301 zkbd_poll(void *v)
302 {
303 	struct zkbd_softc *sc = (struct zkbd_softc *)v;
304 	int i, j, col, pin, type, keysdown = 0;
305 	int stuck;
306 	int keystate;
307 	int s;
308 #ifdef WSDISPLAY_COMPAT_RAWKBD
309 	int npress = 0, ncbuf = 0, c;
310 	char cbuf[MAXKEYS * 2];
311 #endif
312 
313 	s = spltty();
314 
315 	/* discharge all */
316 	for (i = 0; i < sc->sc_nstrobe; i++) {
317 		pin = sc->sc_strobe_array[i];
318 		if (pin == -1)
319 			continue;
320 		pxa2x0_gpio_clear_bit(pin);
321 		pxa2x0_gpio_set_dir(pin, GPIO_IN);
322 	}
323 
324 	delay(10);
325 	for (col = 0; col < sc->sc_nstrobe; col++) {
326 		pin = sc->sc_strobe_array[col];
327 		if (pin == -1)
328 			continue;
329 
330 		/* activate_col */
331 		pxa2x0_gpio_set_bit(pin);
332 		pxa2x0_gpio_set_dir(pin, GPIO_OUT);
333 
334 		/* wait activate delay */
335 		delay(10);
336 
337 		/* read row */
338 		for (i = 0; i < sc->sc_nsense; i++) {
339 			int bit;
340 
341 			if (sc->sc_sense_array[i] == -1)
342 				continue;
343 			bit = pxa2x0_gpio_get_bit(sc->sc_sense_array[i]);
344 			if (bit && sc->sc_hinge && col < sc->sc_maxkbdcol)
345 				continue;
346 			sc->sc_keystate[i + (col * sc->sc_nsense)] = bit;
347 		}
348 
349 		/* reset_col */
350 		pxa2x0_gpio_set_dir(pin, GPIO_IN);
351 
352 		/* wait discharge delay */
353 		delay(10);
354 	}
355 
356 	/* charge all */
357 	for (i = 0; i < sc->sc_nstrobe; i++) {
358 		pin = sc->sc_strobe_array[i];
359 		if (pin == -1)
360 			continue;
361 		pxa2x0_gpio_set_bit(pin);
362 		pxa2x0_gpio_set_dir(pin, GPIO_OUT);
363 	}
364 
365 	/* force the irqs to clear as we have just played with them. */
366 	for (i = 0; i < sc->sc_nsense; i++) {
367 		pin = sc->sc_sense_array[i];
368 		if (pin == -1)
369 			continue;
370 		pxa2x0_gpio_clear_intr(pin);
371 	}
372 
373 	/* process after resetting interrupt */
374 	zkbd_modstate = (
375 		(sc->sc_keystate[84] ? (1 << 0) : 0) | /* shift */
376 		(sc->sc_keystate[93] ? (1 << 1) : 0) | /* Fn */
377 		(sc->sc_keystate[14] ? (1 << 2) : 0)); /* 'alt' */
378 
379 	for (i = 0; i < sc->sc_nsense * sc->sc_nstrobe; i++) {
380 		stuck = 0;
381 		/* extend  xt_keymap to do this faster. */
382 		/* ignore 'stuck' keys' */
383 		for (j = 0; j < __arraycount(stuck_keys); j++) {
384 			if (stuck_keys[j] == i) {
385 				stuck = 1;
386 				break;
387 			}
388 		}
389 		if (stuck)
390 			continue;
391 
392 		keystate = sc->sc_keystate[i];
393 		keysdown |= keystate; /* if any keys held */
394 
395 #ifdef WSDISPLAY_COMPAT_RAWKBD
396 		if (sc->sc_polling == 0 && sc->sc_rawkbd) {
397 			if ((keystate) || (sc->sc_okeystate[i] != keystate)) {
398 				c = sc->sc_xt_keymap[i];
399 				if (c & 0x80) {
400 					cbuf[ncbuf++] = 0xe0;
401 				}
402 				cbuf[ncbuf] = c & 0x7f;
403 
404 				if (keystate) {
405 					if (c & 0x80) {
406 						sc->sc_rep[npress++] = 0xe0;
407 					}
408 					sc->sc_rep[npress++] = c & 0x7f;
409 				} else {
410 					cbuf[ncbuf] |= 0x80;
411 				}
412 				ncbuf++;
413 				sc->sc_okeystate[i] = keystate;
414 			}
415 		}
416 #endif
417 
418 		if ((!sc->sc_rawkbd) && (sc->sc_okeystate[i] != keystate)) {
419 			type = keystate ? WSCONS_EVENT_KEY_DOWN :
420 			    WSCONS_EVENT_KEY_UP;
421 
422 			if (sc->sc_polling) {
423 				sc->sc_pollkey = i;
424 				sc->sc_pollUD = type;
425 			} else {
426 				wskbd_input(sc->sc_wskbddev, type, i);
427 			}
428 
429 			sc->sc_okeystate[i] = keystate;
430 		}
431 	}
432 
433 #ifdef WSDISPLAY_COMPAT_RAWKBD
434 	if (sc->sc_polling == 0 && sc->sc_rawkbd) {
435 		wskbd_rawinput(sc->sc_wskbddev, cbuf, ncbuf);
436 		sc->sc_nrep = npress;
437 		if (npress != 0)
438 			callout_schedule(&sc->sc_rawrepeat_ch,
439 			    hz * REP_DELAY1 / 1000);
440 		else
441 			callout_stop(&sc->sc_rawrepeat_ch);
442 	}
443 #endif
444 	if (keysdown)
445 		callout_schedule(&sc->sc_roll_to, hz * REP_DELAYN / 1000 / 2);
446 	else
447 		callout_stop(&sc->sc_roll_to);	/* always cancel? */
448 
449 	splx(s);
450 }
451 
452 #if NAPM > 0
453 extern	int kbd_reset;
454 extern	int apm_suspends;
455 static	int zkbdondown;				/* on key is pressed */
456 static	struct timeval zkbdontv = { 0, 0 };	/* last on key event */
457 const	struct timeval zkbdhalttv = { 3, 0 };	/*  3s for safe shutdown */
458 const	struct timeval zkbdsleeptv = { 0, 250000 };	/* .25s for suspend */
459 extern	int lid_suspend;
460 #endif
461 
462 static int
463 zkbd_on(void *v)
464 {
465 #if NAPM > 0
466 	struct zkbd_softc *sc = (struct zkbd_softc *)v;
467 	int down = pxa2x0_gpio_get_bit(sc->sc_onkey_pin) ? 1 : 0;
468 
469 	/*
470 	 * Change run mode depending on how long the key is held down.
471 	 * Ignore the key if it gets pressed while the lid is closed.
472 	 *
473 	 * Keys can bounce and we have to work around missed interrupts.
474 	 * Only the second edge is detected upon exit from sleep mode.
475 	 */
476 	if (down) {
477 		if (sc->sc_hinge == 3) {
478 			zkbdondown = 0;
479 		} else {
480 			microuptime(&zkbdontv);
481 			zkbdondown = 1;
482 		}
483 	} else if (zkbdondown) {
484 		if (ratecheck(&zkbdontv, &zkbdhalttv)) {
485 			if (kbd_reset == 1) {
486 				kbd_reset = 0;
487 				psignal(initproc, SIGUSR1);
488 			}
489 		} else if (ratecheck(&zkbdontv, &zkbdsleeptv)) {
490 			apm_suspends++;
491 		}
492 		zkbdondown = 0;
493 	}
494 #endif
495 	return 1;
496 }
497 
498 static int
499 zkbd_sync(void *v)
500 {
501 
502 	return 1;
503 }
504 
505 static int
506 zkbd_hinge(void *v)
507 {
508 	struct zkbd_softc *sc = (struct zkbd_softc *)v;
509 	int a = pxa2x0_gpio_get_bit(sc->sc_swa_pin) ? 1 : 0;
510 	int b = pxa2x0_gpio_get_bit(sc->sc_swb_pin) ? 2 : 0;
511 #if NLCD > 0
512 	extern void lcd_blank(int);
513 #endif
514 
515 	sc->sc_hinge = a | b;
516 
517 	if (sc->sc_hinge == 3) {
518 #if NAPM > 0
519 		if (lid_suspend)
520 			apm_suspends++;
521 #endif
522 #if NLCD > 0
523 		lcd_blank(1);
524 #endif
525 	} else {
526 #if NLCD > 0
527 		lcd_blank(0);
528 #endif
529 	}
530 
531 	return 1;
532 }
533 
534 static int
535 zkbd_enable(void *v, int on)
536 {
537 
538 	return 0;
539 }
540 
541 void
542 zkbd_set_leds(void *v, int on)
543 {
544 }
545 
546 static int
547 zkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
548 {
549 #ifdef WSDISPLAY_COMPAT_RAWKBD
550 	struct zkbd_softc *sc = (struct zkbd_softc *)v;
551 #endif
552 
553 	switch (cmd) {
554 	case WSKBDIO_GTYPE:
555 		*(int *)data = WSKBD_TYPE_ZAURUS;
556 		return 0;
557 
558 	case WSKBDIO_SETLEDS:
559 		return 0;
560 
561 	case WSKBDIO_GETLEDS:
562 		*(int *)data = 0;
563 		return 0;
564 
565 #ifdef WSDISPLAY_COMPAT_RAWKBD
566 	case WSKBDIO_SETMODE:
567 		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
568 		callout_stop(&sc->sc_rawrepeat_ch);
569 		return 0;
570 #endif
571 
572 	}
573 	return EPASSTHROUGH;
574 }
575 
576 /* implement polling for zaurus_kbd */
577 static void
578 zkbd_cngetc(void *v, u_int *type, int *data)
579 {
580 	struct zkbd_softc *sc = (struct zkbd_softc *)zkbd_sc;
581 
582 	sc->sc_pollkey = -1;
583 	sc->sc_pollUD = -1;
584 	sc->sc_polling = 1;
585 	while (sc->sc_pollkey == -1) {
586 		zkbd_poll(sc);
587 		DELAY(10000);	/* XXX */
588 	}
589 	sc->sc_polling = 0;
590 	*data = sc->sc_pollkey;
591 	*type = sc->sc_pollUD;
592 }
593 
594 static void
595 zkbd_cnpollc(void *v, int on)
596 {
597 }
598 
599 static void
600 zkbd_power(int why, void *arg)
601 {
602 
603 	zkbd_hinge(arg);
604 }
605