1*c7fb772bSthorpej /* $NetBSD: zkbd.c,v 1.22 2021/08/07 16:19:08 thorpej Exp $ */
2953d3b5bSober /* $OpenBSD: zaurus_kbd.c,v 1.28 2005/12/21 20:36:03 deraadt Exp $ */
3953d3b5bSober
4953d3b5bSober /*
5953d3b5bSober * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
6953d3b5bSober *
7953d3b5bSober * Permission to use, copy, modify, and distribute this software for any
8953d3b5bSober * purpose with or without fee is hereby granted, provided that the above
9953d3b5bSober * copyright notice and this permission notice appear in all copies.
10953d3b5bSober *
11953d3b5bSober * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12953d3b5bSober * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13953d3b5bSober * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14953d3b5bSober * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15953d3b5bSober * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16953d3b5bSober * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17953d3b5bSober * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18953d3b5bSober */
19953d3b5bSober
20953d3b5bSober #include <sys/cdefs.h>
21*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: zkbd.c,v 1.22 2021/08/07 16:19:08 thorpej Exp $");
22953d3b5bSober
23953d3b5bSober #include "opt_wsdisplay_compat.h"
24953d3b5bSober #if 0 /* XXX */
25953d3b5bSober #include "apm.h"
26953d3b5bSober #endif
276145ba81Stsutsui #include "lcdctl.h"
28953d3b5bSober
29953d3b5bSober #include <sys/param.h>
30953d3b5bSober #include <sys/systm.h>
31953d3b5bSober #include <sys/device.h>
32b8a5a356Sthorpej #include <sys/kmem.h>
33953d3b5bSober #include <sys/kernel.h>
34953d3b5bSober #include <sys/proc.h>
35953d3b5bSober #include <sys/signalvar.h>
36953d3b5bSober #include <sys/callout.h>
37953d3b5bSober
38953d3b5bSober #include <arm/xscale/pxa2x0reg.h>
39953d3b5bSober #include <arm/xscale/pxa2x0_gpio.h>
40953d3b5bSober
41953d3b5bSober #include <dev/wscons/wsconsio.h>
42953d3b5bSober #include <dev/wscons/wskbdvar.h>
43953d3b5bSober #include <dev/wscons/wsksymdef.h>
44953d3b5bSober #include <dev/wscons/wsksymvar.h>
45953d3b5bSober
46953d3b5bSober #include <zaurus/zaurus/zaurus_var.h>
47003bdf4cSnonaka #include <zaurus/dev/zkbdmap.h>
486145ba81Stsutsui #if NLCDCTL > 0
496145ba81Stsutsui #include <zaurus/dev/lcdctlvar.h>
506145ba81Stsutsui #endif
51953d3b5bSober
52953d3b5bSober static const int gpio_sense_pins_c3000[] = {
53953d3b5bSober 12,
54953d3b5bSober 17,
55953d3b5bSober 91,
56953d3b5bSober 34,
57953d3b5bSober 36,
58953d3b5bSober 38,
59953d3b5bSober 39,
60953d3b5bSober -1
61953d3b5bSober };
62953d3b5bSober
63953d3b5bSober static const int gpio_strobe_pins_c3000[] = {
64953d3b5bSober 88,
65953d3b5bSober 23,
66953d3b5bSober 24,
67953d3b5bSober 25,
68953d3b5bSober 26,
69953d3b5bSober 27,
70953d3b5bSober 52,
71953d3b5bSober 103,
72953d3b5bSober 107,
73953d3b5bSober -1,
74953d3b5bSober 108,
75953d3b5bSober 114
76953d3b5bSober };
77953d3b5bSober
788a6a7696Snonaka static const int stuck_keys_c3000[] = {
798a6a7696Snonaka 1, 7, 15, 22, 23, 31, 39, 47,
808a6a7696Snonaka 53, 55, 60, 63, 66, 67, 69, 71,
818a6a7696Snonaka 72, 73, 74, 75, 76, 77, 78, 79,
828a6a7696Snonaka 82, 85, 86, 87, 90, 91, 92, 94,
838a6a7696Snonaka 95
848a6a7696Snonaka };
858a6a7696Snonaka
86533071c4Stsutsui static const int gpio_sense_pins_c860[] = {
87533071c4Stsutsui 58,
88533071c4Stsutsui 59,
89533071c4Stsutsui 60,
90533071c4Stsutsui 61,
91533071c4Stsutsui 62,
92533071c4Stsutsui 63,
93533071c4Stsutsui 64,
94533071c4Stsutsui 65
95533071c4Stsutsui };
96533071c4Stsutsui
97533071c4Stsutsui static const int gpio_strobe_pins_c860[] = {
98533071c4Stsutsui 66,
99533071c4Stsutsui 67,
100533071c4Stsutsui 68,
101533071c4Stsutsui 69,
102533071c4Stsutsui 70,
103533071c4Stsutsui 71,
104533071c4Stsutsui 72,
105533071c4Stsutsui 73,
106533071c4Stsutsui 74,
107533071c4Stsutsui 75,
108533071c4Stsutsui 76,
109533071c4Stsutsui 77
110533071c4Stsutsui };
111533071c4Stsutsui
1128a6a7696Snonaka static const int stuck_keys_c860[] = {
1138a6a7696Snonaka 0, 1, 47, 53, 55, 60, 63, 66,
1148a6a7696Snonaka 67, 69, 71, 72, 73, 74, 76, 77,
1158a6a7696Snonaka 78, 79, 80, 81, 82, 83, 85, 86,
1168a6a7696Snonaka 87, 88, 89, 90, 91, 92, 94, 95
117953d3b5bSober };
118953d3b5bSober
119953d3b5bSober #define REP_DELAY1 400
120953d3b5bSober #define REP_DELAYN 100
121953d3b5bSober
122953d3b5bSober struct zkbd_softc {
1231a686006Snonaka device_t sc_dev;
124953d3b5bSober
125953d3b5bSober const int *sc_sense_array;
126953d3b5bSober const int *sc_strobe_array;
127533071c4Stsutsui const int *sc_stuck_keys;
128953d3b5bSober int sc_nsense;
129953d3b5bSober int sc_nstrobe;
130533071c4Stsutsui int sc_nstuck;
131953d3b5bSober
132953d3b5bSober short sc_onkey_pin;
133953d3b5bSober short sc_sync_pin;
134953d3b5bSober short sc_swa_pin;
135953d3b5bSober short sc_swb_pin;
136953d3b5bSober char *sc_okeystate;
137953d3b5bSober char *sc_keystate;
138953d3b5bSober char sc_hinge; /* 0=open, 1=nonsense, 2=backwards, 3=closed */
139953d3b5bSober char sc_maxkbdcol;
140953d3b5bSober
141953d3b5bSober struct callout sc_roll_to;
142953d3b5bSober
143953d3b5bSober /* console stuff */
144953d3b5bSober int sc_polling;
145953d3b5bSober int sc_pollUD;
146953d3b5bSober int sc_pollkey;
147953d3b5bSober
148953d3b5bSober /* wskbd bits */
149cbab9cadSchs device_t sc_wskbddev;
150533071c4Stsutsui struct wskbd_mapdata *sc_keymapdata;
151953d3b5bSober int sc_rawkbd;
152953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
153953d3b5bSober const char *sc_xt_keymap;
154953d3b5bSober struct callout sc_rawrepeat_ch;
155953d3b5bSober #define MAXKEYS 20
156953d3b5bSober char sc_rep[MAXKEYS];
157953d3b5bSober int sc_nrep;
158953d3b5bSober #endif
159953d3b5bSober };
160953d3b5bSober
161f19ed1a8Speter static struct zkbd_softc *zkbd_sc;
162953d3b5bSober
1631a686006Snonaka static int zkbd_match(device_t, cfdata_t, void *);
1641a686006Snonaka static void zkbd_attach(device_t, device_t, void *);
165953d3b5bSober
1661a686006Snonaka CFATTACH_DECL_NEW(zkbd, sizeof(struct zkbd_softc),
167953d3b5bSober zkbd_match, zkbd_attach, NULL, NULL);
168953d3b5bSober
1698a6a7696Snonaka static int zkbd_irq_c3000(void *v);
1708a6a7696Snonaka static int zkbd_irq_c860(void *v);
171953d3b5bSober static void zkbd_poll(void *v);
172953d3b5bSober static int zkbd_on(void *v);
173953d3b5bSober static int zkbd_sync(void *v);
174953d3b5bSober static int zkbd_hinge(void *v);
175c1b390d4Sdyoung static bool zkbd_resume(device_t dv, const pmf_qual_t *);
176953d3b5bSober
177953d3b5bSober int zkbd_modstate;
178953d3b5bSober
179953d3b5bSober static int zkbd_enable(void *, int);
180953d3b5bSober static void zkbd_set_leds(void *, int);
18153524e44Schristos static int zkbd_ioctl(void *, u_long, void *, int, struct lwp *);
182953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
183953d3b5bSober static void zkbd_rawrepeat(void *v);
184953d3b5bSober #endif
185953d3b5bSober
186f19ed1a8Speter static struct wskbd_accessops zkbd_accessops = {
187953d3b5bSober zkbd_enable,
188953d3b5bSober zkbd_set_leds,
189953d3b5bSober zkbd_ioctl,
190953d3b5bSober };
191953d3b5bSober
192953d3b5bSober static void zkbd_cngetc(void *, u_int *, int *);
193953d3b5bSober static void zkbd_cnpollc(void *, int);
194953d3b5bSober
195f19ed1a8Speter static struct wskbd_consops zkbd_consops = {
196953d3b5bSober zkbd_cngetc,
197953d3b5bSober zkbd_cnpollc,
198953d3b5bSober };
199953d3b5bSober
200f19ed1a8Speter static struct wskbd_mapdata zkbd_keymapdata = {
201953d3b5bSober zkbd_keydesctab,
202953d3b5bSober KB_US,
203953d3b5bSober };
204953d3b5bSober
205533071c4Stsutsui static struct wskbd_mapdata zkbd_keymapdata_c860 = {
206533071c4Stsutsui zkbd_keydesctab_c860,
207533071c4Stsutsui KB_US,
208533071c4Stsutsui };
209533071c4Stsutsui
210953d3b5bSober static int
zkbd_match(device_t parent,cfdata_t cf,void * aux)2111a686006Snonaka zkbd_match(device_t parent, cfdata_t cf, void *aux)
212953d3b5bSober {
213953d3b5bSober
2145113d007Snonaka if (zkbd_sc)
2155113d007Snonaka return 0;
2165113d007Snonaka
217953d3b5bSober return 1;
218953d3b5bSober }
219953d3b5bSober
220953d3b5bSober static void
zkbd_attach(device_t parent,device_t self,void * aux)2211a686006Snonaka zkbd_attach(device_t parent, device_t self, void *aux)
222953d3b5bSober {
2231a686006Snonaka struct zkbd_softc *sc = device_private(self);
224953d3b5bSober struct wskbddev_attach_args a;
225953d3b5bSober int pin, i;
226953d3b5bSober
2271a686006Snonaka sc->sc_dev = self;
228f19ed1a8Speter zkbd_sc = sc;
2295113d007Snonaka
2301a686006Snonaka aprint_normal("\n");
2311a686006Snonaka aprint_naive("\n");
2325113d007Snonaka
233953d3b5bSober sc->sc_polling = 0;
234953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
235953d3b5bSober sc->sc_rawkbd = 0;
236953d3b5bSober #endif
237953d3b5bSober
238c3fdd97bSnonaka callout_init(&sc->sc_roll_to, 0);
239c3fdd97bSnonaka callout_setfunc(&sc->sc_roll_to, zkbd_poll, sc);
240c3fdd97bSnonaka #ifdef WSDISPLAY_COMPAT_RAWKBD
241c3fdd97bSnonaka callout_init(&sc->sc_rawrepeat_ch, 0);
242c3fdd97bSnonaka callout_setfunc(&sc->sc_rawrepeat_ch, zkbd_rawrepeat, sc);
243c3fdd97bSnonaka #endif
244c3fdd97bSnonaka
245003bdf4cSnonaka if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
246953d3b5bSober sc->sc_sense_array = gpio_sense_pins_c3000;
247953d3b5bSober sc->sc_strobe_array = gpio_strobe_pins_c3000;
248f19ed1a8Speter sc->sc_nsense = __arraycount(gpio_sense_pins_c3000);
249f19ed1a8Speter sc->sc_nstrobe = __arraycount(gpio_strobe_pins_c3000);
2508a6a7696Snonaka sc->sc_stuck_keys = stuck_keys_c3000;
2518a6a7696Snonaka sc->sc_nstuck = __arraycount(stuck_keys_c3000);
252953d3b5bSober sc->sc_maxkbdcol = 10;
253953d3b5bSober sc->sc_onkey_pin = 95;
254953d3b5bSober sc->sc_sync_pin = 16;
255953d3b5bSober sc->sc_swa_pin = 97;
256953d3b5bSober sc->sc_swb_pin = 96;
257533071c4Stsutsui sc->sc_keymapdata = &zkbd_keymapdata;
258953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
259953d3b5bSober sc->sc_xt_keymap = xt_keymap;
260953d3b5bSober #endif
261533071c4Stsutsui } else if (ZAURUS_ISC860) {
262533071c4Stsutsui sc->sc_sense_array = gpio_sense_pins_c860;
263533071c4Stsutsui sc->sc_strobe_array = gpio_strobe_pins_c860;
264533071c4Stsutsui sc->sc_nsense = __arraycount(gpio_sense_pins_c860);
265533071c4Stsutsui sc->sc_nstrobe = __arraycount(gpio_strobe_pins_c860);
2668a6a7696Snonaka sc->sc_stuck_keys = stuck_keys_c860;
2678a6a7696Snonaka sc->sc_nstuck = __arraycount(stuck_keys_c860);
268533071c4Stsutsui sc->sc_maxkbdcol = 0;
269533071c4Stsutsui sc->sc_onkey_pin = -1;
270533071c4Stsutsui sc->sc_sync_pin = -1;
271533071c4Stsutsui sc->sc_swa_pin = -1;
272533071c4Stsutsui sc->sc_swb_pin = -1;
273533071c4Stsutsui sc->sc_keymapdata = &zkbd_keymapdata_c860;
274533071c4Stsutsui #ifdef WSDISPLAY_COMPAT_RAWKBD
275533071c4Stsutsui sc->sc_xt_keymap = xt_keymap_c860;
276533071c4Stsutsui #endif
2775113d007Snonaka } else {
2785113d007Snonaka /* XXX */
2795113d007Snonaka return;
2805113d007Snonaka }
2815113d007Snonaka
282664df27bSnonaka if (!pmf_device_register(sc->sc_dev, NULL, zkbd_resume))
283664df27bSnonaka aprint_error_dev(sc->sc_dev,
284664df27bSnonaka "couldn't establish power handler\n");
285953d3b5bSober
286b8a5a356Sthorpej sc->sc_okeystate = kmem_zalloc(sc->sc_nsense * sc->sc_nstrobe,
287b8a5a356Sthorpej KM_SLEEP);
288b8a5a356Sthorpej sc->sc_keystate = kmem_zalloc(sc->sc_nsense * sc->sc_nstrobe,
289b8a5a356Sthorpej KM_SLEEP);
290953d3b5bSober
291953d3b5bSober /* set all the strobe bits */
292953d3b5bSober for (i = 0; i < sc->sc_nstrobe; i++) {
293953d3b5bSober pin = sc->sc_strobe_array[i];
2945113d007Snonaka if (pin == -1)
295953d3b5bSober continue;
296953d3b5bSober pxa2x0_gpio_set_function(pin, GPIO_SET|GPIO_OUT);
297953d3b5bSober }
298f19ed1a8Speter
299953d3b5bSober /* set all the sense bits */
300953d3b5bSober for (i = 0; i < sc->sc_nsense; i++) {
301953d3b5bSober pin = sc->sc_sense_array[i];
3025113d007Snonaka if (pin == -1)
303953d3b5bSober continue;
304953d3b5bSober pxa2x0_gpio_set_function(pin, GPIO_IN);
3058a6a7696Snonaka if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
3068a6a7696Snonaka pxa2x0_gpio_intr_establish(pin, IST_EDGE_BOTH,
3078a6a7696Snonaka IPL_TTY, zkbd_irq_c3000, sc);
3088a6a7696Snonaka } else if (ZAURUS_ISC860) {
3098a6a7696Snonaka pxa2x0_gpio_intr_establish(pin, IST_EDGE_RISING,
3108a6a7696Snonaka IPL_TTY, zkbd_irq_c860, sc);
3118a6a7696Snonaka }
312953d3b5bSober }
313f19ed1a8Speter
314533071c4Stsutsui if (sc->sc_onkey_pin >= 0)
315533071c4Stsutsui pxa2x0_gpio_intr_establish(sc->sc_onkey_pin, IST_EDGE_BOTH,
316533071c4Stsutsui IPL_TTY, zkbd_on, sc);
317533071c4Stsutsui if (sc->sc_sync_pin >= 0)
318533071c4Stsutsui pxa2x0_gpio_intr_establish(sc->sc_sync_pin, IST_EDGE_RISING,
319533071c4Stsutsui IPL_TTY, zkbd_sync, sc);
320533071c4Stsutsui if (sc->sc_swa_pin >= 0)
321533071c4Stsutsui pxa2x0_gpio_intr_establish(sc->sc_swa_pin, IST_EDGE_BOTH,
322533071c4Stsutsui IPL_TTY, zkbd_hinge, sc);
323533071c4Stsutsui if (sc->sc_swb_pin >= 0)
324533071c4Stsutsui pxa2x0_gpio_intr_establish(sc->sc_swb_pin, IST_EDGE_BOTH,
325533071c4Stsutsui IPL_TTY, zkbd_hinge, sc);
326953d3b5bSober
327953d3b5bSober if (glass_console) {
328533071c4Stsutsui wskbd_cnattach(&zkbd_consops, sc, sc->sc_keymapdata);
329953d3b5bSober a.console = 1;
330953d3b5bSober } else {
331953d3b5bSober a.console = 0;
332953d3b5bSober }
333533071c4Stsutsui a.keymap = sc->sc_keymapdata;
334953d3b5bSober a.accessops = &zkbd_accessops;
335953d3b5bSober a.accesscookie = sc;
336953d3b5bSober
337953d3b5bSober zkbd_hinge(sc); /* to initialize sc_hinge */
338953d3b5bSober
339*c7fb772bSthorpej sc->sc_wskbddev = config_found(self, &a, wskbddevprint, CFARGS_NONE);
340953d3b5bSober }
341953d3b5bSober
342953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
343953d3b5bSober static void
zkbd_rawrepeat(void * v)344953d3b5bSober zkbd_rawrepeat(void *v)
345953d3b5bSober {
346953d3b5bSober struct zkbd_softc *sc = (struct zkbd_softc *)v;
347953d3b5bSober int s;
348953d3b5bSober
349953d3b5bSober s = spltty();
350953d3b5bSober wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
351953d3b5bSober splx(s);
352953d3b5bSober callout_schedule(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000);
353953d3b5bSober }
354953d3b5bSober #endif
355953d3b5bSober
356953d3b5bSober /* XXX only deal with keys that can be pressed when display is open? */
357953d3b5bSober /* XXX are some not in the array? */
358953d3b5bSober /* handle keypress interrupt */
359953d3b5bSober static int
zkbd_irq_c3000(void * v)3608a6a7696Snonaka zkbd_irq_c3000(void *v)
361953d3b5bSober {
362953d3b5bSober
363953d3b5bSober zkbd_poll(v);
364953d3b5bSober
365953d3b5bSober return 1;
366953d3b5bSober }
367953d3b5bSober
3688a6a7696Snonaka /* Avoid chattering only for SL-C7x0/860 */
3698a6a7696Snonaka static int
zkbd_irq_c860(void * v)3708a6a7696Snonaka zkbd_irq_c860(void *v)
3718a6a7696Snonaka {
3728a6a7696Snonaka struct zkbd_softc *sc = (struct zkbd_softc *)v;
3738a6a7696Snonaka
3748a6a7696Snonaka if (!callout_pending(&sc->sc_roll_to)) {
3758a6a7696Snonaka zkbd_poll(v);
3768a6a7696Snonaka }
3778a6a7696Snonaka
3788a6a7696Snonaka return 1;
3798a6a7696Snonaka }
3808a6a7696Snonaka
381953d3b5bSober static void
zkbd_poll(void * v)382953d3b5bSober zkbd_poll(void *v)
383953d3b5bSober {
384953d3b5bSober struct zkbd_softc *sc = (struct zkbd_softc *)v;
385f19ed1a8Speter int i, j, col, pin, type, keysdown = 0;
3869bb80a5bSnonaka int stuck;
387953d3b5bSober int keystate;
388f19ed1a8Speter int s;
389953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
3909bb80a5bSnonaka int npress = 0, ncbuf = 0, c;
391953d3b5bSober char cbuf[MAXKEYS * 2];
392953d3b5bSober #endif
393953d3b5bSober
394953d3b5bSober s = spltty();
395953d3b5bSober
396953d3b5bSober /* discharge all */
397953d3b5bSober for (i = 0; i < sc->sc_nstrobe; i++) {
398953d3b5bSober pin = sc->sc_strobe_array[i];
3995113d007Snonaka if (pin == -1)
4005113d007Snonaka continue;
401953d3b5bSober pxa2x0_gpio_clear_bit(pin);
402953d3b5bSober pxa2x0_gpio_set_dir(pin, GPIO_IN);
403953d3b5bSober }
404953d3b5bSober
405953d3b5bSober delay(10);
406953d3b5bSober for (col = 0; col < sc->sc_nstrobe; col++) {
407953d3b5bSober pin = sc->sc_strobe_array[col];
408f19ed1a8Speter if (pin == -1)
409f19ed1a8Speter continue;
410953d3b5bSober
411953d3b5bSober /* activate_col */
412953d3b5bSober pxa2x0_gpio_set_bit(pin);
413953d3b5bSober pxa2x0_gpio_set_dir(pin, GPIO_OUT);
414953d3b5bSober
415953d3b5bSober /* wait activate delay */
416953d3b5bSober delay(10);
417953d3b5bSober
418953d3b5bSober /* read row */
419953d3b5bSober for (i = 0; i < sc->sc_nsense; i++) {
420953d3b5bSober int bit;
421953d3b5bSober
422953d3b5bSober if (sc->sc_sense_array[i] == -1)
423953d3b5bSober continue;
424953d3b5bSober bit = pxa2x0_gpio_get_bit(sc->sc_sense_array[i]);
425953d3b5bSober if (bit && sc->sc_hinge && col < sc->sc_maxkbdcol)
426953d3b5bSober continue;
427953d3b5bSober sc->sc_keystate[i + (col * sc->sc_nsense)] = bit;
428953d3b5bSober }
429953d3b5bSober
430953d3b5bSober /* reset_col */
431953d3b5bSober pxa2x0_gpio_set_dir(pin, GPIO_IN);
432f19ed1a8Speter
433953d3b5bSober /* wait discharge delay */
434953d3b5bSober delay(10);
435953d3b5bSober }
436f19ed1a8Speter
437953d3b5bSober /* charge all */
438953d3b5bSober for (i = 0; i < sc->sc_nstrobe; i++) {
439953d3b5bSober pin = sc->sc_strobe_array[i];
4405113d007Snonaka if (pin == -1)
4415113d007Snonaka continue;
442953d3b5bSober pxa2x0_gpio_set_bit(pin);
443953d3b5bSober pxa2x0_gpio_set_dir(pin, GPIO_OUT);
444953d3b5bSober }
445953d3b5bSober
446953d3b5bSober /* force the irqs to clear as we have just played with them. */
447f19ed1a8Speter for (i = 0; i < sc->sc_nsense; i++) {
4485113d007Snonaka pin = sc->sc_sense_array[i];
4495113d007Snonaka if (pin == -1)
4505113d007Snonaka continue;
4515113d007Snonaka pxa2x0_gpio_clear_intr(pin);
452f19ed1a8Speter }
453953d3b5bSober
454953d3b5bSober /* process after resetting interrupt */
455953d3b5bSober zkbd_modstate = (
456953d3b5bSober (sc->sc_keystate[84] ? (1 << 0) : 0) | /* shift */
457953d3b5bSober (sc->sc_keystate[93] ? (1 << 1) : 0) | /* Fn */
458953d3b5bSober (sc->sc_keystate[14] ? (1 << 2) : 0)); /* 'alt' */
459953d3b5bSober
460f19ed1a8Speter for (i = 0; i < sc->sc_nsense * sc->sc_nstrobe; i++) {
4619bb80a5bSnonaka stuck = 0;
462953d3b5bSober /* extend xt_keymap to do this faster. */
463953d3b5bSober /* ignore 'stuck' keys' */
464533071c4Stsutsui for (j = 0; j < sc->sc_nstuck; j++) {
465533071c4Stsutsui if (sc->sc_stuck_keys[j] == i) {
466953d3b5bSober stuck = 1;
467953d3b5bSober break;
468953d3b5bSober }
469953d3b5bSober }
470953d3b5bSober if (stuck)
471953d3b5bSober continue;
472953d3b5bSober
473f19ed1a8Speter keystate = sc->sc_keystate[i];
474953d3b5bSober keysdown |= keystate; /* if any keys held */
475953d3b5bSober
476953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
4779bb80a5bSnonaka if (sc->sc_polling == 0 && sc->sc_rawkbd) {
4789bb80a5bSnonaka if ((keystate) || (sc->sc_okeystate[i] != keystate)) {
4799bb80a5bSnonaka c = sc->sc_xt_keymap[i];
480953d3b5bSober if (c & 0x80) {
481953d3b5bSober cbuf[ncbuf++] = 0xe0;
482953d3b5bSober }
483953d3b5bSober cbuf[ncbuf] = c & 0x7f;
484953d3b5bSober
485953d3b5bSober if (keystate) {
486953d3b5bSober if (c & 0x80) {
487953d3b5bSober sc->sc_rep[npress++] = 0xe0;
488953d3b5bSober }
489953d3b5bSober sc->sc_rep[npress++] = c & 0x7f;
490953d3b5bSober } else {
491953d3b5bSober cbuf[ncbuf] |= 0x80;
492953d3b5bSober }
493953d3b5bSober ncbuf++;
494953d3b5bSober sc->sc_okeystate[i] = keystate;
495953d3b5bSober }
496953d3b5bSober }
497953d3b5bSober #endif
498953d3b5bSober
4999bb80a5bSnonaka if ((!sc->sc_rawkbd) && (sc->sc_okeystate[i] != keystate)) {
500953d3b5bSober type = keystate ? WSCONS_EVENT_KEY_DOWN :
501953d3b5bSober WSCONS_EVENT_KEY_UP;
502953d3b5bSober
503953d3b5bSober if (sc->sc_polling) {
504953d3b5bSober sc->sc_pollkey = i;
505953d3b5bSober sc->sc_pollUD = type;
506953d3b5bSober } else {
507953d3b5bSober wskbd_input(sc->sc_wskbddev, type, i);
508953d3b5bSober }
509953d3b5bSober
510953d3b5bSober sc->sc_okeystate[i] = keystate;
511953d3b5bSober }
512953d3b5bSober }
513953d3b5bSober
514953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
5159bb80a5bSnonaka if (sc->sc_polling == 0 && sc->sc_rawkbd) {
516953d3b5bSober wskbd_rawinput(sc->sc_wskbddev, cbuf, ncbuf);
517953d3b5bSober sc->sc_nrep = npress;
518953d3b5bSober if (npress != 0)
519953d3b5bSober callout_schedule(&sc->sc_rawrepeat_ch,
520953d3b5bSober hz * REP_DELAY1 / 1000);
521953d3b5bSober else
522953d3b5bSober callout_stop(&sc->sc_rawrepeat_ch);
523953d3b5bSober }
524953d3b5bSober #endif
525953d3b5bSober if (keysdown)
526953d3b5bSober callout_schedule(&sc->sc_roll_to, hz * REP_DELAYN / 1000 / 2);
527953d3b5bSober else
528953d3b5bSober callout_stop(&sc->sc_roll_to); /* always cancel? */
529953d3b5bSober
530953d3b5bSober splx(s);
531953d3b5bSober }
532953d3b5bSober
533953d3b5bSober #if NAPM > 0
534953d3b5bSober extern int kbd_reset;
535953d3b5bSober extern int apm_suspends;
536953d3b5bSober static int zkbdondown; /* on key is pressed */
537953d3b5bSober static struct timeval zkbdontv = { 0, 0 }; /* last on key event */
538953d3b5bSober const struct timeval zkbdhalttv = { 3, 0 }; /* 3s for safe shutdown */
539953d3b5bSober const struct timeval zkbdsleeptv = { 0, 250000 }; /* .25s for suspend */
540953d3b5bSober extern int lid_suspend;
541953d3b5bSober #endif
542953d3b5bSober
543953d3b5bSober static int
zkbd_on(void * v)544953d3b5bSober zkbd_on(void *v)
545953d3b5bSober {
546953d3b5bSober #if NAPM > 0
547953d3b5bSober struct zkbd_softc *sc = (struct zkbd_softc *)v;
548533071c4Stsutsui int down;
549533071c4Stsutsui
550533071c4Stsutsui if (sc->sc_onkey_pin < 0)
551533071c4Stsutsui return 1;
552533071c4Stsutsui
553533071c4Stsutsui down = pxa2x0_gpio_get_bit(sc->sc_onkey_pin) ? 1 : 0;
554953d3b5bSober
555953d3b5bSober /*
556953d3b5bSober * Change run mode depending on how long the key is held down.
557953d3b5bSober * Ignore the key if it gets pressed while the lid is closed.
558953d3b5bSober *
559953d3b5bSober * Keys can bounce and we have to work around missed interrupts.
560953d3b5bSober * Only the second edge is detected upon exit from sleep mode.
561953d3b5bSober */
562953d3b5bSober if (down) {
563953d3b5bSober if (sc->sc_hinge == 3) {
564953d3b5bSober zkbdondown = 0;
565953d3b5bSober } else {
566953d3b5bSober microuptime(&zkbdontv);
567953d3b5bSober zkbdondown = 1;
568953d3b5bSober }
569953d3b5bSober } else if (zkbdondown) {
570953d3b5bSober if (ratecheck(&zkbdontv, &zkbdhalttv)) {
571953d3b5bSober if (kbd_reset == 1) {
572953d3b5bSober kbd_reset = 0;
573953d3b5bSober psignal(initproc, SIGUSR1);
574953d3b5bSober }
575953d3b5bSober } else if (ratecheck(&zkbdontv, &zkbdsleeptv)) {
576953d3b5bSober apm_suspends++;
577953d3b5bSober }
578953d3b5bSober zkbdondown = 0;
579953d3b5bSober }
580953d3b5bSober #endif
581953d3b5bSober return 1;
582953d3b5bSober }
583953d3b5bSober
584953d3b5bSober static int
zkbd_sync(void * v)585953d3b5bSober zkbd_sync(void *v)
586953d3b5bSober {
587953d3b5bSober
588953d3b5bSober return 1;
589953d3b5bSober }
590953d3b5bSober
591953d3b5bSober static int
zkbd_hinge(void * v)592953d3b5bSober zkbd_hinge(void *v)
593953d3b5bSober {
594953d3b5bSober struct zkbd_softc *sc = (struct zkbd_softc *)v;
595533071c4Stsutsui int a, b;
596533071c4Stsutsui
597533071c4Stsutsui if (sc->sc_swa_pin < 0 || sc->sc_swb_pin < 0)
598533071c4Stsutsui return 1;
599533071c4Stsutsui
600533071c4Stsutsui a = pxa2x0_gpio_get_bit(sc->sc_swa_pin) ? 1 : 0;
601533071c4Stsutsui b = pxa2x0_gpio_get_bit(sc->sc_swb_pin) ? 2 : 0;
602953d3b5bSober
603953d3b5bSober sc->sc_hinge = a | b;
604953d3b5bSober
605953d3b5bSober if (sc->sc_hinge == 3) {
606953d3b5bSober #if NAPM > 0
607953d3b5bSober if (lid_suspend)
608953d3b5bSober apm_suspends++;
609953d3b5bSober #endif
6106145ba81Stsutsui #if NLCDCTL > 0
6116145ba81Stsutsui lcdctl_blank(true);
6126145ba81Stsutsui #endif
613953d3b5bSober } else {
6146145ba81Stsutsui #if NLCDCTL > 0
6156145ba81Stsutsui lcdctl_blank(false);
6166145ba81Stsutsui #endif
617953d3b5bSober }
618953d3b5bSober
619953d3b5bSober return 1;
620953d3b5bSober }
621953d3b5bSober
622953d3b5bSober static int
zkbd_enable(void * v,int on)623953d3b5bSober zkbd_enable(void *v, int on)
624953d3b5bSober {
625953d3b5bSober
626953d3b5bSober return 0;
627953d3b5bSober }
628953d3b5bSober
629953d3b5bSober void
zkbd_set_leds(void * v,int on)630953d3b5bSober zkbd_set_leds(void *v, int on)
631953d3b5bSober {
632953d3b5bSober }
633953d3b5bSober
634953d3b5bSober static int
zkbd_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)63553524e44Schristos zkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
636953d3b5bSober {
637953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
638953d3b5bSober struct zkbd_softc *sc = (struct zkbd_softc *)v;
639953d3b5bSober #endif
640953d3b5bSober
641953d3b5bSober switch (cmd) {
642953d3b5bSober case WSKBDIO_GTYPE:
643953d3b5bSober *(int *)data = WSKBD_TYPE_ZAURUS;
644953d3b5bSober return 0;
645953d3b5bSober
646953d3b5bSober case WSKBDIO_SETLEDS:
647953d3b5bSober return 0;
648953d3b5bSober
649953d3b5bSober case WSKBDIO_GETLEDS:
650953d3b5bSober *(int *)data = 0;
651953d3b5bSober return 0;
652953d3b5bSober
653953d3b5bSober #ifdef WSDISPLAY_COMPAT_RAWKBD
654953d3b5bSober case WSKBDIO_SETMODE:
655953d3b5bSober sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
656953d3b5bSober callout_stop(&sc->sc_rawrepeat_ch);
657953d3b5bSober return 0;
658953d3b5bSober #endif
659953d3b5bSober
660953d3b5bSober }
661f19ed1a8Speter return EPASSTHROUGH;
662953d3b5bSober }
663953d3b5bSober
664953d3b5bSober /* implement polling for zaurus_kbd */
665953d3b5bSober static void
zkbd_cngetc(void * v,u_int * type,int * data)666953d3b5bSober zkbd_cngetc(void *v, u_int *type, int *data)
667953d3b5bSober {
668f19ed1a8Speter struct zkbd_softc *sc = (struct zkbd_softc *)zkbd_sc;
669953d3b5bSober
670953d3b5bSober sc->sc_pollkey = -1;
671953d3b5bSober sc->sc_pollUD = -1;
672953d3b5bSober sc->sc_polling = 1;
673953d3b5bSober while (sc->sc_pollkey == -1) {
674f19ed1a8Speter zkbd_poll(sc);
675953d3b5bSober DELAY(10000); /* XXX */
676953d3b5bSober }
677953d3b5bSober sc->sc_polling = 0;
678953d3b5bSober *data = sc->sc_pollkey;
679953d3b5bSober *type = sc->sc_pollUD;
680953d3b5bSober }
681953d3b5bSober
682953d3b5bSober static void
zkbd_cnpollc(void * v,int on)683953d3b5bSober zkbd_cnpollc(void *v, int on)
684953d3b5bSober {
685953d3b5bSober }
686953d3b5bSober
687664df27bSnonaka static bool
zkbd_resume(device_t dv,const pmf_qual_t * qual)688c1b390d4Sdyoung zkbd_resume(device_t dv, const pmf_qual_t *qual)
689953d3b5bSober {
690664df27bSnonaka struct zkbd_softc *sc = device_private(dv);
691953d3b5bSober
692664df27bSnonaka zkbd_hinge(sc);
693664df27bSnonaka
694664df27bSnonaka return true;
695953d3b5bSober }
696