xref: /netbsd-src/sys/arch/evbarm/netwalker/netwalker_btn.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1 /*	$NetBSD: netwalker_btn.c,v 1.4 2021/08/07 16:18:50 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2014  Genetec Corporation.  All rights reserved.
5  * Written by Hashimoto Kenichi for Genetec Corporation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netwalker_btn.c,v 1.4 2021/08/07 16:18:50 thorpej Exp $");
31 
32 #include "opt_imxspi.h"
33 #include "opt_mousebtn.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/lock.h>
40 #include <sys/callout.h>
41 #include <sys/gpio.h>
42 #include <sys/bus.h>
43 #include <sys/mutex.h>
44 
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wsmousevar.h>
47 
48 #include <dev/gpio/gpiovar.h>
49 
50 #define GPIO1_BASE		160
51 
52 #define MOUSEBTN_PIN_LEFT	0
53 #define MOUSEBTN_PIN_RIGHT	1
54 #define MOUSEBTN_NPINS		2
55 
56 #define POLLRATE (hz/10)
57 
58 struct mousebtn_softc
59 {
60 	device_t sc_dev;
61 	void *sc_gpio;
62 	void *sc_intr[MOUSEBTN_NPINS];
63 
64 	struct gpio_pinmap sc_map;
65 	int sc_map_pins[MOUSEBTN_NPINS];
66 
67 	int sc_buttons;
68 
69 	struct callout sc_c;
70 	kmutex_t sc_lock;
71 
72 	int sc_enabled;
73 	struct device *sc_wsmousedev;
74 };
75 
76 static int mousebtn_match(device_t, cfdata_t, void *);
77 static void mousebtn_attach(device_t, device_t, void *);
78 static int mousebtn_detach(device_t, int);
79 
80 CFATTACH_DECL_NEW(netwalker_btn, sizeof(struct mousebtn_softc),
81     mousebtn_match, mousebtn_attach, mousebtn_detach, NULL);
82 
83 static void mousebtn_poll(void *);
84 static int mousebtn_intr(void *);
85 
86 static int mousebtn_enable(void *v);
87 static void mousebtn_disable(void *v);
88 static int mousebtn_ioctl(void *, u_long, void *, int, struct lwp *);
89 
90 static bool mousebtn_resume(device_t, const pmf_qual_t *);
91 static bool mousebtn_suspend(device_t, const pmf_qual_t *);
92 
93 static const struct wsmouse_accessops mousebtn_accessops = {
94 	.enable	 = mousebtn_enable,
95 	.ioctl	 = mousebtn_ioctl,
96 	.disable = mousebtn_disable
97 };
98 
99 static int
mousebtn_match(device_t parent,cfdata_t cf,void * aux)100 mousebtn_match(device_t parent, cfdata_t cf, void * aux)
101 {
102 	struct gpio_attach_args *ga = aux;
103 
104 	if (strcmp(ga->ga_dvname, cf->cf_name))
105 		return 0;
106 	if (ga->ga_offset == -1)
107 		return 0;
108 
109 	/* check that we have enough pins */
110 	if (gpio_npins(ga->ga_mask) != MOUSEBTN_NPINS) {
111 		aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name,
112 		    ga->ga_mask);
113 		return 0;
114 	}
115 
116 	return 1;
117 }
118 
119 static void
mousebtn_attach(device_t parent,device_t self,void * aux)120 mousebtn_attach(device_t parent, device_t self, void *aux)
121 {
122 	struct mousebtn_softc *sc = device_private(self);
123 	struct gpio_attach_args *ga = aux;
124 	int caps;
125 	struct wsmousedev_attach_args a;
126 
127 	sc->sc_dev = self;
128 	sc->sc_gpio = ga->ga_gpio;
129 
130 	/* map pins */
131 	sc->sc_map.pm_map = sc->sc_map_pins;
132 	if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
133 		&sc->sc_map)) {
134 		aprint_error(": couldn't map the pins\n");
135 		return;
136 	}
137 
138 	/* configure left pin */
139 	caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, MOUSEBTN_PIN_LEFT);
140 	if (!(caps & GPIO_PIN_INPUT)) {
141 		aprint_error(": pin is unable to read input\n");
142 		gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
143 		return;
144 	}
145 	gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, MOUSEBTN_PIN_LEFT,
146 	    GPIO_PIN_INPUT);
147 
148 	/* configure right pin */
149 	caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, MOUSEBTN_PIN_RIGHT);
150 	if (!(caps & GPIO_PIN_INPUT)) {
151 		aprint_error(": pin is unable to read input\n");
152 		gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
153 		return;
154 	}
155 	gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, MOUSEBTN_PIN_RIGHT,
156 	    GPIO_PIN_INPUT);
157 
158 	/* interrupt settings */
159 	sc->sc_intr[0] = intr_establish(GPIO1_BASE + ga->ga_offset,
160 	    IPL_VM, IST_EDGE_BOTH, mousebtn_intr, sc);
161 	if (sc->sc_intr[0] == NULL) {
162 		aprint_error(": couldn't establish interrupt\n");
163 		return;
164 	}
165 	sc->sc_intr[1] = intr_establish(GPIO1_BASE + ga->ga_offset + 1,
166 	     IPL_VM, IST_EDGE_BOTH, mousebtn_intr, sc);
167 	if (sc->sc_intr[1] == NULL) {
168 		aprint_error(": couldn't establish interrupt\n");
169 		intr_disestablish(sc->sc_intr[0]);
170 		return;
171 	}
172 
173 	aprint_normal(": NetWalker mouse button\n");
174 	aprint_naive(": NetWalker mouse button\n");
175 
176 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
177 	callout_init(&sc->sc_c, 0);
178 
179 	a.accessops = &mousebtn_accessops;
180 	a.accesscookie = sc;
181 
182 	sc->sc_buttons = 0;
183 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE);
184 }
185 
186 static int
mousebtn_detach(device_t self,int flags)187 mousebtn_detach(device_t self, int flags)
188 {
189 	struct mousebtn_softc *sc = device_private(self);
190 
191 	if (sc->sc_intr[0] != NULL)
192 		intr_disestablish(sc->sc_intr[0]);
193 	if (sc->sc_intr[1] != NULL)
194 		intr_disestablish(sc->sc_intr[1]);
195 
196 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
197 
198 	return 0;
199 }
200 
201 static void
mousebtn_poll(void * arg)202 mousebtn_poll(void *arg)
203 {
204 	struct mousebtn_softc *sc = (struct mousebtn_softc *)arg;
205 	uint32_t buttons = 0;
206 	int s;
207 	int left;
208 	int right;
209 
210 	mutex_enter(&sc->sc_lock);
211 
212 	left = !gpio_pin_read(sc->sc_gpio, &sc->sc_map, MOUSEBTN_PIN_LEFT);
213 	right = !gpio_pin_read(sc->sc_gpio, &sc->sc_map, MOUSEBTN_PIN_RIGHT);
214 	buttons = (right << 2) | left;
215 
216 	if (sc->sc_buttons != buttons) {
217 		s = spltty();
218 		wsmouse_input(sc->sc_wsmousedev, buttons, 0, 0, 0, 0,
219 		    WSMOUSE_INPUT_DELTA);
220 		sc->sc_buttons = buttons;
221 		splx(s);
222 	}
223 
224 	mutex_exit(&sc->sc_lock);
225 
226 #if defined(MOUSEBTN_POLLING)
227 	if (sc->sc_enabled)
228 		callout_reset(&sc->sc_c, POLLRATE, mousebtn_poll, sc);
229 #endif
230 	return;
231 }
232 
233 static int
mousebtn_intr(void * v)234 mousebtn_intr(void *v)
235 {
236 	struct mousebtn_softc *sc = v;
237 
238 	if (sc->sc_enabled)
239 		callout_reset(&sc->sc_c, POLLRATE, mousebtn_poll, sc);
240 
241 	return 1;
242 }
243 
244 
245 int
mousebtn_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)246 mousebtn_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
247 {
248 	struct wsmouse_id *id;
249 
250 	switch (cmd) {
251 	case WSMOUSEIO_GTYPE:
252 		*(u_int *)data = WSMOUSE_TYPE_PS2;
253 		return 0;
254 	case WSMOUSEIO_GETID:
255 		id = (struct wsmouse_id *)data;
256 		if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
257 			return EINVAL;
258 		strlcpy(id->data, "NetWalker Mouse Button", WSMOUSE_ID_MAXLEN);
259 		id->length = strlen(id->data);
260 		return 0;
261 	}
262 
263 	return EPASSTHROUGH;
264 }
265 
266 int
mousebtn_enable(void * v)267 mousebtn_enable(void *v)
268 {
269 	struct mousebtn_softc *sc = (struct mousebtn_softc *)v;
270 
271 	if (sc->sc_enabled)
272 		return EBUSY;
273 
274 	if (!pmf_device_register(sc->sc_dev, mousebtn_suspend, mousebtn_resume))
275 		aprint_error_dev(sc->sc_dev,
276 		    "couldn't establish power handler\n");
277 
278 	sc->sc_enabled = 1;
279 #if defined(MOUSEBTN_POLLING)
280 	callout_reset(&sc->sc_c, POLLRATE, mousebtn_poll, sc);
281 #endif
282 
283 	return 0;
284 }
285 
286 void
mousebtn_disable(void * v)287 mousebtn_disable(void *v)
288 {
289 	struct mousebtn_softc *sc = (struct mousebtn_softc *)v;
290 
291 	if (!sc->sc_enabled)
292 		return;
293 
294 	pmf_device_deregister(sc->sc_dev);
295 
296 	sc->sc_enabled = 0;
297 
298 	return;
299 }
300 
301 static bool
mousebtn_suspend(device_t dv,const pmf_qual_t * qual)302 mousebtn_suspend(device_t dv, const pmf_qual_t *qual)
303 {
304 	struct mousebtn_softc *sc = device_private(dv);
305 
306 #if defined(MOUSEBTN_POLLING)
307 	callout_stop(&sc->sc_c);
308 #endif
309 	sc->sc_enabled = 0;
310 
311 	return true;
312 }
313 
314 static bool
mousebtn_resume(device_t dv,const pmf_qual_t * qual)315 mousebtn_resume(device_t dv, const pmf_qual_t *qual)
316 {
317 	struct mousebtn_softc *sc = device_private(dv);
318 
319 	sc->sc_enabled = 1;
320 #if defined(MOUSEBTN_POLLING)
321 	callout_reset(&sc->sc_c, POLLRATE, mousebtn_poll, sc);
322 #endif
323 	return true;
324 }
325 
326