hilms.c revision 1.1
1/*	$NetBSD: hilms.c,v 1.1 2011/02/06 18:26:54 tsutsui 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
58int	hilmsprobe(device_t, cfdata_t, void *);
59void	hilmsattach(device_t, device_t, void *);
60int	hilmsdetach(device_t, int);
61
62CFATTACH_DECL_NEW(hilms, sizeof(struct hilms_softc),
63    hilmsprobe, hilmsattach, hilmsdetach, NULL);
64
65int	hilms_enable(void *);
66int	hilms_ioctl(void *, u_long, void *, int, struct lwp *);
67void	hilms_disable(void *);
68
69const struct wsmouse_accessops hilms_accessops = {
70	hilms_enable,
71	hilms_ioctl,
72	hilms_disable,
73};
74
75void	hilms_callback(struct hildev_softc *, u_int, u_int8_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	printf(", %d axes", sc->sc_axes);
141	if (sc->sc_buttons == 1)
142		printf(", 1 button");
143	else if (sc->sc_buttons > 1)
144		printf(", %d buttons", sc->sc_buttons);
145	if (sc->sc_features & HILIOB_PIO)
146		printf(", pressure sensor");
147	if (sc->sc_features & HIL_ABSOLUTE) {
148		printf ("\n%s: %d", device_xname(self), rx);
149		if (ry != 0)
150			printf("x%d", ry);
151		else
152			printf(" linear");
153		printf(" fixed area");
154	}
155
156	printf("\n");
157
158	sc->sc_enabled = 0;
159
160	a.accessops = &hilms_accessops;
161	a.accesscookie = sc;
162
163	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
164}
165
166int
167hilmsdetach(device_t self, int flags)
168{
169	struct hilms_softc *sc = device_private(self);
170
171	if (sc->sc_wsmousedev != NULL)
172		return config_detach(sc->sc_wsmousedev, flags);
173
174	return (0);
175}
176
177int
178hilms_enable(void *v)
179{
180	struct hilms_softc *sc = v;
181
182	if (sc->sc_enabled)
183		return EBUSY;
184
185	sc->sc_enabled = 1;
186	sc->sc_buttonstate = 0;
187
188	return (0);
189}
190
191void
192hilms_disable(void *v)
193{
194	struct hilms_softc *sc = v;
195
196	sc->sc_enabled = 0;
197}
198
199int
200hilms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
201{
202#if 0
203	struct hilms_softc *sc = v;
204#endif
205
206	switch (cmd) {
207	case WSMOUSEIO_GTYPE:
208		*(int *)data = WSMOUSE_TYPE_HIL;
209		return 0;
210	}
211
212	return EPASSTHROUGH;
213}
214
215void
216hilms_callback(struct hildev_softc *hdsc, u_int buflen, u_int8_t *buf)
217{
218	struct hilms_softc *sc = device_private(hdsc->sc_dev);
219	int type, flags;
220	int dx, dy, dz, button;
221#ifdef DIAGNOSTIC
222	int minlen;
223#endif
224
225	/*
226	 * Ignore packet if we don't need it
227	 */
228	if (sc->sc_enabled == 0)
229		return;
230
231	type = *buf++;
232
233#ifdef DIAGNOSTIC
234	/*
235	 * Check that the packet contains all the expected data,
236	 * ignore it if too short.
237	 */
238	minlen = 1;
239	if (type & HIL_MOUSEMOTION) {
240		minlen += sc->sc_axes <<
241		    (sc->sc_features & HIL_16_BITS) ? 1 : 0;
242	}
243	if (type & HIL_MOUSEBUTTON)
244		minlen++;
245
246	if (minlen > buflen)
247		return;
248#endif
249
250	/*
251	 * The packet can contain both a mouse motion and a button event.
252	 * In this case, the motion data comes first.
253	 */
254
255	if (type & HIL_MOUSEMOTION) {
256		flags = sc->sc_features & HIL_ABSOLUTE ?
257		    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
258		    WSMOUSE_INPUT_ABSOLUTE_Z : WSMOUSE_INPUT_DELTA;
259		if (sc->sc_features & HIL_16_BITS) {
260			dx = *buf++;
261			dx |= (*buf++) << 8;
262			if (!(sc->sc_features & HIL_ABSOLUTE))
263				dx = (int16_t)dx;
264		} else {
265			dx = *buf++;
266			if (!(sc->sc_features & HIL_ABSOLUTE))
267				dx = (int8_t)dx;
268		}
269		if (sc->sc_axes > 1) {
270			if (sc->sc_features & HIL_16_BITS) {
271				dy = *buf++;
272				dy |= (*buf++) << 8;
273				if (!(sc->sc_features & HIL_ABSOLUTE))
274					dy = (int16_t)dy;
275			} else {
276				dy = *buf++;
277				if (!(sc->sc_features & HIL_ABSOLUTE))
278					dy = (int8_t)dy;
279			}
280			if (sc->sc_axes > 2) {
281				if (sc->sc_features & HIL_16_BITS) {
282					dz = *buf++;
283					dz |= (*buf++) << 8;
284					if (!(sc->sc_features & HIL_ABSOLUTE))
285						dz = (int16_t)dz;
286				} else {
287					dz = *buf++;
288					if (!(sc->sc_features & HIL_ABSOLUTE))
289						dz = (int8_t)dz;
290				}
291			} else
292				dz = 0;
293		} else
294			dy = dz = 0;
295
296		/*
297		 * Correct Y direction for button boxes.
298		 */
299		if ((sc->sc_features & HIL_ABSOLUTE) == 0 &&
300		    sc->sc_buttons == 0)
301			dy = -dy;
302	} else
303		dx = dy = dz = flags = 0;
304
305	if (type & HIL_MOUSEBUTTON) {
306		button = *buf;
307		/*
308		 * The pressure sensor is very primitive and only has
309		 * a boolean behaviour, as an extra mouse button, which is
310		 * down if there is pressure or the pen is near the tablet,
311		 * and up if there is no pressure or the pen is far from the
312		 * tablet - at least for Tablet id 0x94, P/N 46088B
313		 *
314		 * The corresponding codes are 0x8f and 0x8e. Convert them
315		 * to a pseudo fourth button - even if the tablet never
316		 * has three buttons.
317		 */
318		button = (button - 0x80) >> 1;
319		if (button > 4)
320			button = 4;
321
322		if (*buf & 1) {
323			/* Button released, or no pressure */
324			sc->sc_buttonstate &= ~(1 << button);
325		} else {
326			/* Button pressed, or pressure */
327			sc->sc_buttonstate |= (1 << button);
328		}
329		/* buf++; */
330	}
331
332	if (sc->sc_wsmousedev != NULL)
333		wsmouse_input(sc->sc_wsmousedev,
334		    sc->sc_buttonstate, dx, dy, dz, 0, flags);
335}
336