xref: /openbsd/sys/dev/hil/hilms.c (revision 471aeecf)
1 /*	$OpenBSD: hilms.c,v 1.7 2022/04/06 18:59:28 naddy Exp $	*/
2 /*
3  * Copyright (c) 2003, Miodrag Vallat.
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  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/ioctl.h>
33 
34 #include <machine/autoconf.h>
35 #include <machine/bus.h>
36 #include <machine/cpu.h>
37 
38 #include <dev/hil/hilreg.h>
39 #include <dev/hil/hilvar.h>
40 #include <dev/hil/hildevs.h>
41 
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsmousevar.h>
44 
45 struct hilms_softc {
46 	struct hildev_softc sc_hildev;
47 
48 	int		sc_features;
49 	u_int		sc_buttons;
50 	u_int		sc_axes;
51 	int		sc_enabled;
52 	int		sc_buttonstate;
53 
54 	struct device	*sc_wsmousedev;
55 };
56 
57 int	hilmsprobe(struct device *, void *, void *);
58 void	hilmsattach(struct device *, struct device *, void *);
59 int	hilmsdetach(struct device *, int);
60 
61 struct cfdriver hilms_cd = {
62 	NULL, "hilms", DV_DULL
63 };
64 
65 const struct cfattach hilms_ca = {
66 	sizeof(struct hilms_softc), hilmsprobe, hilmsattach, hilmsdetach,
67 };
68 
69 int	hilms_enable(void *);
70 int	hilms_ioctl(void *, u_long, caddr_t, int, struct proc *);
71 void	hilms_disable(void *);
72 
73 const struct wsmouse_accessops hilms_accessops = {
74 	hilms_enable,
75 	hilms_ioctl,
76 	hilms_disable,
77 };
78 
79 void	hilms_callback(struct hildev_softc *, u_int, u_int8_t *);
80 
81 int
hilmsprobe(struct device * parent,void * match,void * aux)82 hilmsprobe(struct device *parent, void *match, void *aux)
83 {
84 	struct hil_attach_args *ha = aux;
85 
86 	if (ha->ha_type != HIL_DEVICE_MOUSE)
87 		return (0);
88 
89 	/*
90 	 * Reject anything that has only buttons - they are handled as
91 	 * keyboards, really.
92 	 */
93 	if (ha->ha_infolen > 1 && (ha->ha_info[1] & HIL_AXMASK) == 0)
94 		return (0);
95 
96 	return (1);
97 }
98 
99 void
hilmsattach(struct device * parent,struct device * self,void * aux)100 hilmsattach(struct device *parent, struct device *self, void *aux)
101 {
102 	struct hilms_softc *sc = (void *)self;
103 	struct hil_attach_args *ha = aux;
104 	struct wsmousedev_attach_args a;
105 	int iob, rx, ry;
106 
107 	sc->hd_code = ha->ha_code;
108 	sc->hd_type = ha->ha_type;
109 	sc->hd_infolen = ha->ha_infolen;
110 	bcopy(ha->ha_info, sc->hd_info, ha->ha_infolen);
111 	sc->hd_fn = hilms_callback;
112 
113 	/*
114 	 * Interpret the identification bytes, if any
115 	 */
116 	rx = ry = 0;
117 	if (ha->ha_infolen > 1) {
118 		sc->sc_features = ha->ha_info[1];
119 		sc->sc_axes = sc->sc_features & HIL_AXMASK;
120 
121 		if (sc->sc_features & HIL_IOB) {
122 			/* skip resolution bytes */
123 			iob = 4;
124 			if (sc->sc_features & HIL_ABSOLUTE) {
125 				/* skip ranges */
126 				rx = ha->ha_info[4] | (ha->ha_info[5] << 8);
127 				if (sc->sc_axes > 1)
128 					ry = ha->ha_info[6] |
129 					    (ha->ha_info[7] << 8);
130 				iob += 2 * sc->sc_axes;
131 			}
132 
133 			if (iob >= ha->ha_infolen) {
134 				sc->sc_features &= ~(HIL_IOB | HILIOB_PIO);
135 			} else {
136 				iob = ha->ha_info[iob];
137 				sc->sc_buttons = iob & HILIOB_BMASK;
138 				sc->sc_features |= (iob & HILIOB_PIO);
139 			}
140 		}
141 	}
142 
143 	printf(", %d axes", sc->sc_axes);
144 	if (sc->sc_buttons == 1)
145 		printf(", 1 button");
146 	else if (sc->sc_buttons > 1)
147 		printf(", %d buttons", sc->sc_buttons);
148 	if (sc->sc_features & HILIOB_PIO)
149 		printf(", pressure sensor");
150 	if (sc->sc_features & HIL_ABSOLUTE) {
151 		printf ("\n%s: %d", self->dv_xname, rx);
152 		if (ry != 0)
153 			printf("x%d", ry);
154 		else
155 			printf(" linear");
156 		printf(" fixed area");
157 	}
158 
159 	printf("\n");
160 
161 	sc->sc_enabled = 0;
162 
163 	a.accessops = &hilms_accessops;
164 	a.accesscookie = sc;
165 
166 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
167 }
168 
169 int
hilmsdetach(struct device * self,int flags)170 hilmsdetach(struct device *self, int flags)
171 {
172 	struct hilms_softc *sc = (void *)self;
173 
174 	if (sc->sc_wsmousedev != NULL)
175 		return config_detach(sc->sc_wsmousedev, flags);
176 
177 	return (0);
178 }
179 
180 int
hilms_enable(void * v)181 hilms_enable(void *v)
182 {
183 	struct hilms_softc *sc = v;
184 
185 	if (sc->sc_enabled)
186 		return EBUSY;
187 
188 	sc->sc_enabled = 1;
189 	sc->sc_buttonstate = 0;
190 
191 	return (0);
192 }
193 
194 void
hilms_disable(void * v)195 hilms_disable(void *v)
196 {
197 	struct hilms_softc *sc = v;
198 
199 	sc->sc_enabled = 0;
200 }
201 
202 int
hilms_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)203 hilms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
204 {
205 #if 0
206 	struct hilms_softc *sc = v;
207 #endif
208 
209 	switch (cmd) {
210 	case WSMOUSEIO_GTYPE:
211 		*(int *)data = WSMOUSE_TYPE_HIL;
212 		return 0;
213 	}
214 
215 	return -1;
216 }
217 
218 void
hilms_callback(struct hildev_softc * dev,u_int buflen,u_int8_t * buf)219 hilms_callback(struct hildev_softc *dev, u_int buflen, u_int8_t *buf)
220 {
221 	struct hilms_softc *sc = (struct hilms_softc *)dev;
222 	int type;
223 	int dx, dy, dz, button;
224 #ifdef DIAGNOSTIC
225 	int minlen;
226 #endif
227 
228 	/*
229 	 * Ignore packet if we don't need it
230 	 */
231 	if (sc->sc_enabled == 0)
232 		return;
233 
234 	type = *buf++;
235 
236 #ifdef DIAGNOSTIC
237 	/*
238 	 * Check that the packet contains all the expected data,
239 	 * ignore it if too short.
240 	 */
241 	minlen = 1;
242 	if (type & HIL_MOUSEMOTION) {
243 		minlen += sc->sc_axes <<
244 		    (sc->sc_features & HIL_16_BITS) ? 1 : 0;
245 	}
246 	if (type & HIL_MOUSEBUTTON)
247 		minlen++;
248 
249 	if (minlen > buflen)
250 		return;
251 #endif
252 
253 	/*
254 	 * The packet can contain both a mouse motion and a button event.
255 	 * In this case, the motion data comes first.
256 	 */
257 
258 	if (type & HIL_MOUSEMOTION) {
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 	}
303 
304 	if (type & HIL_MOUSEBUTTON) {
305 		button = *buf;
306 		/*
307 		 * The pressure sensor is very primitive and only has
308 		 * a boolean behaviour, as an extra mouse button, which is
309 		 * down if there is pressure or the pen is near the tablet,
310 		 * and up if there is no pressure or the pen is far from the
311 		 * tablet - at least for Tablet id 0x94, P/N 46088B
312 		 *
313 		 * The corresponding codes are 0x8f and 0x8e. Convert them
314 		 * to a pseudo fourth button - even if the tablet never
315 		 * has three buttons.
316 		 */
317 		button = (button - 0x80) >> 1;
318 		if (button > 4)
319 			button = 4;
320 
321 		if (*buf & 1) {
322 			/* Button released, or no pressure */
323 			sc->sc_buttonstate &= ~(1 << button);
324 		} else {
325 			/* Button pressed, or pressure */
326 			sc->sc_buttonstate |= (1 << button);
327 		}
328 		/* buf++; */
329 	}
330 
331 	if (sc->sc_wsmousedev == NULL)
332 		return;
333 
334 	wsmouse_buttons(sc->sc_wsmousedev, sc->sc_buttonstate);
335 	if (type & HIL_MOUSEMOTION) {
336 		if ((sc->sc_features & HIL_ABSOLUTE) == 0) {
337 			wsmouse_motion(sc->sc_wsmousedev, dx, dy, dz, 0);
338 		} else {
339 			wsmouse_position(sc->sc_wsmousedev, dx, dy);
340 			if (sc->sc_axes > 2)
341 				wsmouse_touch(sc->sc_wsmousedev, dz, 0);
342 		}
343 	}
344 	wsmouse_input_sync(sc->sc_wsmousedev);
345 }
346