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