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