xref: /netbsd-src/sys/arch/zaurus/dev/zkbd.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
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