xref: /netbsd-src/sys/arch/hpcarm/dev/nbpkbd.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1 /*	$NetBSD: nbpkbd.c,v 1.3 2021/08/07 16:18:53 thorpej Exp $ */
2 /*
3  * Copyright (c) 2011 KIYOHARA Takashi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: nbpkbd.c,v 1.3 2021/08/07 16:18:53 thorpej Exp $");
29 
30 #include <sys/param.h>
31 #include <sys/callout.h>
32 #include <sys/device.h>
33 #include <sys/errno.h>
34 #include <sys/kernel.h>
35 
36 #include <machine/platid.h>
37 #include <machine/platid_mask.h>
38 
39 #include <arm/xscale/pxa2x0_i2c.h>
40 
41 #include <hpcarm/dev/nbppconvar.h>
42 
43 #include <dev/hpc/hpckbdvar.h>
44 
45 #include <dev/i2c/i2cvar.h>
46 
47 #include "locators.h"
48 
49 #ifdef NBPKBD_DEBUG
50 #define DPRINTF(x)	printf x
51 #else
52 #define DPRINTF(x)
53 #endif
54 
55 #define IS_KEY_DOWN(x)	(((x) & 0x80) == 0x00)
56 #define KEY_CODE(x)	((x) & 0x7f)
57 #define KEY_INITIAL_INTERVAL	(500 * hz / 1000)	/* 500ms */
58 #define KEY_REPEAT_INTERVAL	(200 * hz / 1000)	/* 200ms */
59 
60 struct nbpkbd_softc {
61 	device_t sc_dev;
62 	device_t sc_parent;
63 	int sc_tag;
64 
65 	struct hpckbd_ic_if sc_if;
66 	struct hpckbd_if *sc_hpckbd;
67 
68 	int sc_enabled;
69 
70 	callout_t  sc_callout;
71 	uint8_t sc_last_scancode;
72 };
73 
74 static int nbpkbd_match(device_t, cfdata_t, void *);
75 static void nbpkbd_attach(device_t, device_t, void *);
76 
77 static int nbpkbd_input_establish(void *, struct hpckbd_if *);
78 static int nbpkbd_input(void *, int, char *);
79 static int nbpkbd_poll(void *);
80 
81 static void nbpkbd_key_repeat(void *);
82 
83 CFATTACH_DECL_NEW(nbpkbd, sizeof(struct nbpkbd_softc),
84     nbpkbd_match, nbpkbd_attach, NULL, NULL);
85 
86 
87 /* ARGSUSED */
88 static int
nbpkbd_match(device_t parent,cfdata_t match,void * aux)89 nbpkbd_match(device_t parent, cfdata_t match, void *aux)
90 {
91 	struct nbppcon_attach_args *pcon = aux;
92 
93 	if (strcmp(pcon->aa_name, match->cf_name) ||
94 	    pcon->aa_tag == NBPPCONCF_TAG_DEFAULT)
95 		return 0;
96 
97 	return 1;
98 }
99 
100 static void
nbpkbd_attach(device_t parent,device_t self,void * aux)101 nbpkbd_attach(device_t parent, device_t self, void *aux)
102 {
103 	struct nbpkbd_softc *sc = device_private(self);
104 	struct nbppcon_attach_args *pcon = aux;
105 	struct hpckbd_attach_args haa;
106 
107 	aprint_normal(": NETBOOK PRO Keyboard\n");
108 	aprint_naive("\n");
109 
110 	sc->sc_dev = self;
111 	sc->sc_parent = parent;
112 	sc->sc_tag = pcon->aa_tag;
113 	sc->sc_if.hii_ctx = sc;
114 	sc->sc_if.hii_establish = nbpkbd_input_establish;
115 	sc->sc_if.hii_poll = nbpkbd_poll;
116 
117 	hpckbd_cnattach(&sc->sc_if);
118 
119 	callout_init(&sc->sc_callout, 0);
120 	callout_setfunc(&sc->sc_callout, nbpkbd_key_repeat, sc);
121 
122 	/* Attach hpckbd */
123 	haa.haa_ic = &sc->sc_if;
124 	config_found(self, &haa, hpckbd_print, CFARGS_NONE);
125 
126 	if (nbppcon_regist_callback(parent, sc->sc_tag, nbpkbd_input, sc) ==
127 	    NULL)
128 		aprint_error_dev(self, "callback regist failed\n");
129 }
130 
131 
132 static int
nbpkbd_input_establish(void * arg,struct hpckbd_if * kbdif)133 nbpkbd_input_establish(void *arg, struct hpckbd_if *kbdif)
134 {
135 	struct nbpkbd_softc *sc = arg;
136 
137 	sc->sc_hpckbd = kbdif;
138 	sc->sc_enabled = 1;
139 
140 	return 0;
141 }
142 
143 static int
nbpkbd_input(void * arg,int buflen,char * buf)144 nbpkbd_input(void *arg, int buflen, char *buf)
145 {
146 	struct nbpkbd_softc *sc = arg;
147 
148 #ifdef NBPKBD_DEBUG
149 	{
150 		int i;
151 
152 		printf("%s:", __func__);
153 		for (i = 0; i < buflen; i++)
154 			printf(" %02x", buf[i]);
155 		printf("\n");
156 	}
157 #endif
158 
159 	if (buflen != 2) {
160 		aprint_error_dev(sc->sc_dev, "ugly length %d\n", buflen);
161 		return -1;
162 	}
163 
164 	hpckbd_input(sc->sc_hpckbd, IS_KEY_DOWN(buf[1]), KEY_CODE(buf[1]));
165 
166 	sc->sc_last_scancode = buf[1];
167 	if (IS_KEY_DOWN(buf[1]))
168 		callout_schedule(&sc->sc_callout, KEY_INITIAL_INTERVAL);
169 	else
170 		callout_stop(&sc->sc_callout);
171 
172 	delay(50);	/* XXXX */
173 
174 	if (nbppcon_kbd_ready(sc->sc_parent) != 0)
175 		aprint_error_dev(sc->sc_dev,
176 		    "%s: kbd-ready failed\n", __func__);
177 
178 	return 0;
179 }
180 
181 static int
nbpkbd_poll(void * arg)182 nbpkbd_poll(void *arg)
183 {
184 	struct nbpkbd_softc *sc = arg;
185 	int rv, s;
186 	char buf[2];
187 
188 	if (!sc->sc_enabled)
189 		return 0;
190 
191 	s = spltty();
192 
193 	rv = nbppcon_poll(sc->sc_parent, sc->sc_tag, sizeof(buf), buf);
194 
195 	DPRINTF(("%s: received %02x %02x\n",
196 	    device_xname(sc->sc_dev), buf[0], buf[1]));
197 
198 	hpckbd_input(sc->sc_hpckbd, IS_KEY_DOWN(buf[1]), KEY_CODE(buf[1]));
199 
200 	delay(50);	/* XXXX */
201 
202 	rv = nbppcon_kbd_ready(sc->sc_parent);
203 
204 	splx(s);
205 
206 	if (rv != 0)
207 		aprint_error_dev(sc->sc_dev,
208 		    "%s: kbd-ready failed\n", __func__);
209 
210 	return 0;
211 }
212 
213 static void
nbpkbd_key_repeat(void * arg)214 nbpkbd_key_repeat(void *arg)
215 {
216 	struct nbpkbd_softc *sc = arg;
217 
218 	hpckbd_input(sc->sc_hpckbd, IS_KEY_DOWN(sc->sc_last_scancode),
219 	    KEY_CODE(sc->sc_last_scancode));
220 
221 	if (IS_KEY_DOWN(sc->sc_last_scancode))
222 		callout_schedule(&sc->sc_callout, KEY_REPEAT_INTERVAL);
223 }
224