hilms.c revision 1.3
1/*	$NetBSD: hilms.c,v 1.3 2021/04/24 23:36:54 thorpej Exp $	*/
2/*	$OpenBSD: hilms.c,v 1.5 2007/04/10 22:37:17 miod Exp $	*/
3/*
4 * Copyright (c) 2003, Miodrag Vallat.
5 * All rights reserved.
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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/device.h>
33#include <sys/ioctl.h>
34#include <sys/bus.h>
35#include <sys/cpu.h>
36
37#include <machine/autoconf.h>
38
39#include <dev/hil/hilreg.h>
40#include <dev/hil/hilvar.h>
41#include <dev/hil/hildevs.h>
42
43#include <dev/wscons/wsconsio.h>
44#include <dev/wscons/wsmousevar.h>
45
46struct hilms_softc {
47	struct hildev_softc sc_hildev;
48
49	int		sc_features;
50	u_int		sc_buttons;
51	u_int		sc_axes;
52	int		sc_enabled;
53	int		sc_buttonstate;
54
55	device_t	sc_wsmousedev;
56};
57
58static int	hilmsprobe(device_t, cfdata_t, void *);
59static void	hilmsattach(device_t, device_t, void *);
60static int	hilmsdetach(device_t, int);
61
62CFATTACH_DECL_NEW(hilms, sizeof(struct hilms_softc),
63    hilmsprobe, hilmsattach, hilmsdetach, NULL);
64
65static int	hilms_enable(void *);
66static int	hilms_ioctl(void *, u_long, void *, int, struct lwp *);
67static void	hilms_disable(void *);
68
69static const struct wsmouse_accessops hilms_accessops = {
70	hilms_enable,
71	hilms_ioctl,
72	hilms_disable,
73};
74
75static void	hilms_callback(struct hildev_softc *, u_int, uint8_t *);
76
77int
78hilmsprobe(device_t parent, cfdata_t cf, void *aux)
79{
80	struct hil_attach_args *ha = aux;
81
82	if (ha->ha_type != HIL_DEVICE_MOUSE)
83		return 0;
84
85	/*
86	 * Reject anything that has only buttons - they are handled as
87	 * keyboards, really.
88	 */
89	if (ha->ha_infolen > 1 && (ha->ha_info[1] & HIL_AXMASK) == 0)
90		return 0;
91
92	return 1;
93}
94
95void
96hilmsattach(device_t parent, device_t self, void *aux)
97{
98	struct hilms_softc *sc = device_private(self);
99	struct hil_attach_args *ha = aux;
100	struct wsmousedev_attach_args a;
101	int iob, rx, ry;
102
103	sc->sc_hildev.sc_dev = self;
104	sc->hd_code = ha->ha_code;
105	sc->hd_type = ha->ha_type;
106	sc->hd_infolen = ha->ha_infolen;
107	memcpy(sc->hd_info, ha->ha_info, ha->ha_infolen);
108	sc->hd_fn = hilms_callback;
109
110	/*
111	 * Interpret the identification bytes, if any
112	 */
113	rx = ry = 0;
114	if (ha->ha_infolen > 1) {
115		sc->sc_features = ha->ha_info[1];
116		sc->sc_axes = sc->sc_features & HIL_AXMASK;
117
118		if (sc->sc_features & HIL_IOB) {
119			/* skip resolution bytes */
120			iob = 4;
121			if (sc->sc_features & HIL_ABSOLUTE) {
122				/* skip ranges */
123				rx = ha->ha_info[4] | (ha->ha_info[5] << 8);
124				if (sc->sc_axes > 1)
125					ry = ha->ha_info[6] |
126					    (ha->ha_info[7] << 8);
127				iob += 2 * sc->sc_axes;
128			}
129
130			if (iob >= ha->ha_infolen) {
131				sc->sc_features &= ~(HIL_IOB | HILIOB_PIO);
132			} else {
133				iob = ha->ha_info[iob];
134				sc->sc_buttons = iob & HILIOB_BMASK;
135				sc->sc_features |= (iob & HILIOB_PIO);
136			}
137		}
138	}
139
140	aprint_normal(", %d axes", sc->sc_axes);
141	if (sc->sc_buttons == 1)
142		aprint_normal(", 1 button");
143	else if (sc->sc_buttons > 1)
144		aprint_normal(", %d buttons", sc->sc_buttons);
145	if (sc->sc_features & HILIOB_PIO)
146		aprint_normal(", pressure sensor");
147	if (sc->sc_features & HIL_ABSOLUTE) {
148		aprint_normal("\n");
149		aprint_normal_dev(self, "%d", rx);
150		if (ry != 0)
151			aprint_normal("x%d", ry);
152		else
153			aprint_normal(" linear");
154		aprint_normal(" fixed area");
155	}
156
157	aprint_normal("\n");
158
159	sc->sc_enabled = 0;
160
161	a.accessops = &hilms_accessops;
162	a.accesscookie = sc;
163
164	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARG_EOL);
165}
166
167int
168hilmsdetach(device_t self, int flags)
169{
170	struct hilms_softc *sc = device_private(self);
171
172	if (sc->sc_wsmousedev != NULL)
173		return config_detach(sc->sc_wsmousedev, flags);
174
175	return 0;
176}
177
178int
179hilms_enable(void *v)
180{
181	struct hilms_softc *sc = v;
182
183	if (sc->sc_enabled)
184		return EBUSY;
185
186	sc->sc_enabled = 1;
187	sc->sc_buttonstate = 0;
188
189	return 0;
190}
191
192void
193hilms_disable(void *v)
194{
195	struct hilms_softc *sc = v;
196
197	sc->sc_enabled = 0;
198}
199
200int
201hilms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
202{
203#if 0
204	struct hilms_softc *sc = v;
205#endif
206
207	switch (cmd) {
208	case WSMOUSEIO_GTYPE:
209		*(int *)data = WSMOUSE_TYPE_HIL;
210		return 0;
211	}
212
213	return EPASSTHROUGH;
214}
215
216void
217hilms_callback(struct hildev_softc *hdsc, u_int buflen, uint8_t *buf)
218{
219	struct hilms_softc *sc = device_private(hdsc->sc_dev);
220	int type, flags;
221	int dx, dy, dz, button;
222#ifdef DIAGNOSTIC
223	int minlen;
224#endif
225
226	/*
227	 * Ignore packet if we don't need it
228	 */
229	if (sc->sc_enabled == 0)
230		return;
231
232	type = *buf++;
233
234#ifdef DIAGNOSTIC
235	/*
236	 * Check that the packet contains all the expected data,
237	 * ignore it if too short.
238	 */
239	minlen = 1;
240	if (type & HIL_MOUSEMOTION) {
241		minlen += sc->sc_axes <<
242		    (sc->sc_features & HIL_16_BITS) ? 1 : 0;
243	}
244	if (type & HIL_MOUSEBUTTON)
245		minlen++;
246
247	if (minlen > buflen)
248		return;
249#endif
250
251	/*
252	 * The packet can contain both a mouse motion and a button event.
253	 * In this case, the motion data comes first.
254	 */
255
256	if (type & HIL_MOUSEMOTION) {
257		flags = sc->sc_features & HIL_ABSOLUTE ?
258		    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
259		    WSMOUSE_INPUT_ABSOLUTE_Z : WSMOUSE_INPUT_DELTA;
260		if (sc->sc_features & HIL_16_BITS) {
261			dx = *buf++;
262			dx |= (*buf++) << 8;
263			if (!(sc->sc_features & HIL_ABSOLUTE))
264				dx = (int16_t)dx;
265		} else {
266			dx = *buf++;
267			if (!(sc->sc_features & HIL_ABSOLUTE))
268				dx = (int8_t)dx;
269		}
270		if (sc->sc_axes > 1) {
271			if (sc->sc_features & HIL_16_BITS) {
272				dy = *buf++;
273				dy |= (*buf++) << 8;
274				if (!(sc->sc_features & HIL_ABSOLUTE))
275					dy = (int16_t)dy;
276			} else {
277				dy = *buf++;
278				if (!(sc->sc_features & HIL_ABSOLUTE))
279					dy = (int8_t)dy;
280			}
281			if (sc->sc_axes > 2) {
282				if (sc->sc_features & HIL_16_BITS) {
283					dz = *buf++;
284					dz |= (*buf++) << 8;
285					if (!(sc->sc_features & HIL_ABSOLUTE))
286						dz = (int16_t)dz;
287				} else {
288					dz = *buf++;
289					if (!(sc->sc_features & HIL_ABSOLUTE))
290						dz = (int8_t)dz;
291				}
292			} else
293				dz = 0;
294		} else
295			dy = dz = 0;
296
297		/*
298		 * Correct Y direction for button boxes.
299		 */
300		if ((sc->sc_features & HIL_ABSOLUTE) == 0 &&
301		    sc->sc_buttons == 0)
302			dy = -dy;
303	} else
304		dx = dy = dz = flags = 0;
305
306	if (type & HIL_MOUSEBUTTON) {
307		button = *buf;
308		/*
309		 * The pressure sensor is very primitive and only has
310		 * a boolean behaviour, as an extra mouse button, which is
311		 * down if there is pressure or the pen is near the tablet,
312		 * and up if there is no pressure or the pen is far from the
313		 * tablet - at least for Tablet id 0x94, P/N 46088B
314		 *
315		 * The corresponding codes are 0x8f and 0x8e. Convert them
316		 * to a pseudo fourth button - even if the tablet never
317		 * has three buttons.
318		 */
319		button = (button - 0x80) >> 1;
320		if (button > 4)
321			button = 4;
322
323		if (*buf & 1) {
324			/* Button released, or no pressure */
325			sc->sc_buttonstate &= ~(1 << button);
326		} else {
327			/* Button pressed, or pressure */
328			sc->sc_buttonstate |= (1 << button);
329		}
330		/* buf++; */
331	}
332
333	if (sc->sc_wsmousedev != NULL)
334		wsmouse_input(sc->sc_wsmousedev,
335		    sc->sc_buttonstate, dx, dy, dz, 0, flags);
336}
337