Line data Source code
1 : /* $OpenBSD: uts.c,v 1.41 2018/03/15 00:42:41 kevlo Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2007 Robert Nagy <robert@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include <sys/param.h>
20 : #include <sys/sockio.h>
21 : #include <sys/mbuf.h>
22 : #include <sys/kernel.h>
23 : #include <sys/socket.h>
24 : #include <sys/systm.h>
25 : #include <sys/malloc.h>
26 : #include <sys/timeout.h>
27 : #include <sys/conf.h>
28 : #include <sys/device.h>
29 : #include <sys/endian.h>
30 :
31 : #include <machine/intr.h>
32 :
33 : #include <dev/usb/usb.h>
34 : #include <dev/usb/usbdi.h>
35 : #include <dev/usb/usbdi_util.h>
36 : #include <dev/usb/usbdevs.h>
37 :
38 : #include <dev/wscons/wsconsio.h>
39 : #include <dev/wscons/wsmousevar.h>
40 :
41 : #ifdef UTS_DEBUG
42 : #define DPRINTF(x) do { printf x; } while (0)
43 : #else
44 : #define DPRINTF(x)
45 : #endif
46 :
47 : struct tsscale {
48 : int minx, maxx;
49 : int miny, maxy;
50 : int swapxy;
51 : int resx, resy;
52 : } def_scale = {
53 : 67, 1931, 102, 1937, 0, 1024, 768
54 : };
55 :
56 : struct uts_softc {
57 : struct device sc_dev;
58 : struct usbd_device *sc_udev;
59 : struct usbd_interface *sc_iface;
60 : int sc_product;
61 : int sc_vendor;
62 :
63 : int sc_intr_number;
64 : struct usbd_pipe *sc_intr_pipe;
65 : u_char *sc_ibuf;
66 : int sc_isize;
67 : u_int8_t sc_pkts;
68 :
69 : struct device *sc_wsmousedev;
70 :
71 : int sc_enabled;
72 : int sc_buttons;
73 : int sc_oldx;
74 : int sc_oldy;
75 : int sc_rawmode;
76 :
77 : struct tsscale sc_tsscale;
78 : };
79 :
80 : struct uts_pos {
81 : int down;
82 : int x;
83 : int y;
84 : int z; /* touch pressure */
85 : };
86 :
87 : const struct usb_devno uts_devs[] = {
88 : { USB_VENDOR_FTDI, USB_PRODUCT_FTDI_ITM_TOUCH },
89 : { USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL },
90 : { USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2 },
91 : { USB_VENDOR_GUNZE, USB_PRODUCT_GUNZE_TOUCHPANEL }
92 : };
93 :
94 : void uts_intr(struct usbd_xfer *, void *, usbd_status);
95 : void uts_get_pos(void *addr, struct uts_pos *tp);
96 :
97 : int uts_enable(void *);
98 : void uts_disable(void *);
99 : int uts_ioctl(void *, u_long, caddr_t, int, struct proc *);
100 :
101 : const struct wsmouse_accessops uts_accessops = {
102 : uts_enable,
103 : uts_ioctl,
104 : uts_disable,
105 : };
106 :
107 : int uts_match(struct device *, void *, void *);
108 : void uts_attach(struct device *, struct device *, void *);
109 : int uts_detach(struct device *, int);
110 : int uts_activate(struct device *, int);
111 :
112 : struct cfdriver uts_cd = {
113 : NULL, "uts", DV_DULL
114 : };
115 :
116 : const struct cfattach uts_ca = {
117 : sizeof(struct uts_softc),
118 : uts_match,
119 : uts_attach,
120 : uts_detach,
121 : uts_activate,
122 : };
123 :
124 : int
125 0 : uts_match(struct device *parent, void *match, void *aux)
126 : {
127 0 : struct usb_attach_arg *uaa = aux;
128 : usb_interface_descriptor_t *id;
129 :
130 0 : if (uaa->iface == NULL)
131 0 : return (UMATCH_NONE);
132 :
133 : /* Some eGalax touch screens are HID devices. ignore them */
134 0 : id = usbd_get_interface_descriptor(uaa->iface);
135 0 : if (id != NULL && id->bInterfaceClass == UICLASS_HID)
136 0 : return (UMATCH_NONE);
137 :
138 0 : return (usb_lookup(uts_devs, uaa->vendor, uaa->product) != NULL) ?
139 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
140 0 : }
141 :
142 : void
143 0 : uts_attach(struct device *parent, struct device *self, void *aux)
144 : {
145 0 : struct uts_softc *sc = (struct uts_softc *)self;
146 0 : struct usb_attach_arg *uaa = aux;
147 : usb_config_descriptor_t *cdesc;
148 : usb_interface_descriptor_t *id;
149 : usb_endpoint_descriptor_t *ed;
150 0 : struct wsmousedev_attach_args a;
151 : int i;
152 :
153 0 : sc->sc_udev = uaa->device;
154 0 : sc->sc_product = uaa->product;
155 0 : sc->sc_vendor = uaa->vendor;
156 0 : sc->sc_intr_number = -1;
157 0 : sc->sc_intr_pipe = NULL;
158 0 : sc->sc_enabled = sc->sc_isize = 0;
159 :
160 : /* Copy the default scalue values to each softc */
161 0 : bcopy(&def_scale, &sc->sc_tsscale, sizeof(sc->sc_tsscale));
162 :
163 : /* get the config descriptor */
164 0 : cdesc = usbd_get_config_descriptor(sc->sc_udev);
165 0 : if (cdesc == NULL) {
166 0 : printf("%s: failed to get configuration descriptor\n",
167 0 : sc->sc_dev.dv_xname);
168 0 : usbd_deactivate(sc->sc_udev);
169 0 : return;
170 : }
171 :
172 : /* get the interface */
173 0 : if (usbd_device2interface_handle(uaa->device, 0, &sc->sc_iface) != 0) {
174 0 : printf("%s: failed to get interface\n",
175 0 : sc->sc_dev.dv_xname);
176 0 : usbd_deactivate(sc->sc_udev);
177 0 : return;
178 : }
179 :
180 : /* Find the interrupt endpoint */
181 0 : id = usbd_get_interface_descriptor(sc->sc_iface);
182 :
183 0 : for (i = 0; i < id->bNumEndpoints; i++) {
184 0 : ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
185 0 : if (ed == NULL) {
186 0 : printf("%s: no endpoint descriptor for %d\n",
187 0 : sc->sc_dev.dv_xname, i);
188 0 : usbd_deactivate(sc->sc_udev);
189 0 : return;
190 : }
191 :
192 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
193 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
194 0 : sc->sc_intr_number = ed->bEndpointAddress;
195 0 : sc->sc_isize = UGETW(ed->wMaxPacketSize);
196 0 : }
197 : }
198 :
199 0 : if (sc->sc_intr_number== -1) {
200 0 : printf("%s: Could not find interrupt in\n",
201 0 : sc->sc_dev.dv_xname);
202 0 : usbd_deactivate(sc->sc_udev);
203 0 : return;
204 : }
205 :
206 0 : a.accessops = &uts_accessops;
207 0 : a.accesscookie = sc;
208 :
209 0 : sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
210 0 : }
211 :
212 : int
213 0 : uts_detach(struct device *self, int flags)
214 : {
215 0 : struct uts_softc *sc = (struct uts_softc *)self;
216 : int rv = 0;
217 :
218 0 : if (sc->sc_intr_pipe != NULL) {
219 0 : usbd_abort_pipe(sc->sc_intr_pipe);
220 0 : usbd_close_pipe(sc->sc_intr_pipe);
221 0 : sc->sc_intr_pipe = NULL;
222 0 : }
223 :
224 0 : if (sc->sc_wsmousedev != NULL) {
225 0 : rv = config_detach(sc->sc_wsmousedev, flags);
226 0 : sc->sc_wsmousedev = NULL;
227 0 : }
228 :
229 0 : return (rv);
230 : }
231 :
232 : int
233 0 : uts_activate(struct device *self, int act)
234 : {
235 0 : struct uts_softc *sc = (struct uts_softc *)self;
236 : int rv = 0;
237 :
238 0 : switch (act) {
239 : case DVACT_DEACTIVATE:
240 0 : if (sc->sc_wsmousedev != NULL)
241 0 : rv = config_deactivate(sc->sc_wsmousedev);
242 0 : usbd_deactivate(sc->sc_udev);
243 0 : break;
244 : }
245 :
246 0 : return (rv);
247 : }
248 :
249 : int
250 0 : uts_enable(void *v)
251 : {
252 0 : struct uts_softc *sc = v;
253 : int err;
254 :
255 0 : if (usbd_is_dying(sc->sc_udev))
256 0 : return (EIO);
257 :
258 0 : if (sc->sc_enabled)
259 0 : return (EBUSY);
260 :
261 0 : if (sc->sc_isize == 0)
262 0 : return (0);
263 0 : sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
264 0 : err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
265 0 : USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_ibuf,
266 0 : sc->sc_isize, uts_intr, USBD_DEFAULT_INTERVAL);
267 0 : if (err) {
268 0 : free(sc->sc_ibuf, M_USBDEV, sc->sc_isize);
269 0 : sc->sc_intr_pipe = NULL;
270 0 : return (EIO);
271 : }
272 :
273 0 : sc->sc_enabled = 1;
274 0 : sc->sc_buttons = 0;
275 :
276 0 : return (0);
277 0 : }
278 :
279 : void
280 0 : uts_disable(void *v)
281 : {
282 0 : struct uts_softc *sc = v;
283 :
284 0 : if (!sc->sc_enabled) {
285 0 : printf("uts_disable: already disabled!\n");
286 0 : return;
287 : }
288 :
289 : /* Disable interrupts. */
290 0 : if (sc->sc_intr_pipe != NULL) {
291 0 : usbd_abort_pipe(sc->sc_intr_pipe);
292 0 : usbd_close_pipe(sc->sc_intr_pipe);
293 0 : sc->sc_intr_pipe = NULL;
294 0 : }
295 :
296 0 : if (sc->sc_ibuf != NULL) {
297 0 : free(sc->sc_ibuf, M_USBDEV, sc->sc_isize);
298 0 : sc->sc_ibuf = NULL;
299 0 : }
300 :
301 0 : sc->sc_enabled = 0;
302 0 : }
303 :
304 : int
305 0 : uts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *l)
306 : {
307 : int error = 0;
308 0 : struct uts_softc *sc = v;
309 0 : struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
310 :
311 : DPRINTF(("uts_ioctl(%d, '%c', %d)\n",
312 : IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));
313 :
314 0 : switch (cmd) {
315 : case WSMOUSEIO_SCALIBCOORDS:
316 0 : if (!(wsmc->minx >= -32768 && wsmc->maxx >= 0 &&
317 0 : wsmc->miny >= -32768 && wsmc->maxy >= 0 &&
318 0 : wsmc->resx >= 0 && wsmc->resy >= 0 &&
319 0 : wsmc->minx < 32768 && wsmc->maxx < 32768 &&
320 0 : wsmc->miny < 32768 && wsmc->maxy < 32768 &&
321 0 : (wsmc->maxx - wsmc->minx) != 0 &&
322 0 : (wsmc->maxy - wsmc->miny) != 0 &&
323 0 : wsmc->resx < 32768 && wsmc->resy < 32768 &&
324 0 : wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
325 0 : wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
326 0 : return (EINVAL);
327 :
328 0 : sc->sc_tsscale.minx = wsmc->minx;
329 0 : sc->sc_tsscale.maxx = wsmc->maxx;
330 0 : sc->sc_tsscale.miny = wsmc->miny;
331 0 : sc->sc_tsscale.maxy = wsmc->maxy;
332 0 : sc->sc_tsscale.swapxy = wsmc->swapxy;
333 0 : sc->sc_tsscale.resx = wsmc->resx;
334 0 : sc->sc_tsscale.resy = wsmc->resy;
335 0 : sc->sc_rawmode = wsmc->samplelen;
336 0 : break;
337 : case WSMOUSEIO_GCALIBCOORDS:
338 0 : wsmc->minx = sc->sc_tsscale.minx;
339 0 : wsmc->maxx = sc->sc_tsscale.maxx;
340 0 : wsmc->miny = sc->sc_tsscale.miny;
341 0 : wsmc->maxy = sc->sc_tsscale.maxy;
342 0 : wsmc->swapxy = sc->sc_tsscale.swapxy;
343 0 : wsmc->resx = sc->sc_tsscale.resx;
344 0 : wsmc->resy = sc->sc_tsscale.resy;
345 0 : wsmc->samplelen = sc->sc_rawmode;
346 0 : break;
347 : case WSMOUSEIO_GTYPE:
348 0 : *(u_int *)data = WSMOUSE_TYPE_TPANEL;
349 0 : break;
350 : default:
351 : error = ENOTTY;
352 0 : break;
353 : }
354 :
355 0 : return (error);
356 0 : }
357 :
358 : void
359 0 : uts_get_pos(void *addr, struct uts_pos *tp)
360 : {
361 0 : struct uts_softc *sc = addr;
362 0 : u_char *p = sc->sc_ibuf;
363 : int down, x, y, z;
364 :
365 0 : switch (sc->sc_product) {
366 : case USB_PRODUCT_FTDI_ITM_TOUCH:
367 0 : down = (~p[7] & 0x20);
368 0 : x = ((p[0] & 0x1f) << 7) | (p[3] & 0x7f);
369 : /* Invert the Y coordinate */
370 0 : y = 0x0fff - abs(((p[1] & 0x1f) << 7) | (p[4] & 0x7f));
371 0 : z = ((p[2] & 0x1) << 7) | (p[5] & 0x7f);
372 0 : sc->sc_pkts = 0x8;
373 0 : break;
374 : case USB_PRODUCT_EGALAX_TPANEL:
375 : case USB_PRODUCT_EGALAX_TPANEL2:
376 : /*
377 : * eGalax and Gunze USB touch panels have the same device ID,
378 : * so decide upon the vendor ID.
379 : */
380 0 : switch (sc->sc_vendor) {
381 : case USB_VENDOR_EGALAX:
382 0 : down = (p[0] & 0x01);
383 : /* Invert the X coordinate */
384 0 : x = 0x07ff - abs(((p[3] & 0x0f) << 7) | (p[4] & 0x7f));
385 0 : y = ((p[1] & 0x0f) << 7) | (p[2] & 0x7f);
386 : z = down;
387 0 : sc->sc_pkts = 0x5;
388 0 : break;
389 : case USB_VENDOR_GUNZE:
390 0 : down = (~p[7] & 0x20);
391 : /* Invert the X coordinate */
392 0 : x = 0x0fff - abs(((p[0] & 0x1f) << 7) | (p[2] & 0x7f));
393 0 : y = ((p[1] & 0x1f) << 7) | (p[3] & 0x7f);
394 0 : z = (down != 0);
395 0 : sc->sc_pkts = 0x4;
396 0 : break;
397 : }
398 : break;
399 : }
400 :
401 : DPRINTF(("%s: down = 0x%x, sc->sc_pkts = 0x%x\n",
402 : sc->sc_dev.dv_xname, down, sc->sc_pkts));
403 :
404 : /* x/y values are not reliable if there is no pressure */
405 0 : if (down) {
406 0 : if (sc->sc_tsscale.swapxy && !sc->sc_rawmode) {
407 : /* Swap X/Y-Axis */
408 0 : tp->y = x;
409 0 : tp->x = y;
410 0 : } else {
411 0 : tp->x = x;
412 0 : tp->y = y;
413 : }
414 0 : if (!sc->sc_rawmode &&
415 0 : (sc->sc_tsscale.maxx - sc->sc_tsscale.minx) != 0 &&
416 0 : (sc->sc_tsscale.maxy - sc->sc_tsscale.miny) != 0) {
417 : /* Scale down to the screen resolution. */
418 0 : tp->x = ((tp->x - sc->sc_tsscale.minx) *
419 0 : sc->sc_tsscale.resx) /
420 : (sc->sc_tsscale.maxx - sc->sc_tsscale.minx);
421 0 : tp->y = ((tp->y - sc->sc_tsscale.miny) *
422 0 : sc->sc_tsscale.resy) /
423 0 : (sc->sc_tsscale.maxy - sc->sc_tsscale.miny);
424 0 : }
425 : } else {
426 0 : tp->x = sc->sc_oldx;
427 0 : tp->y = sc->sc_oldy;
428 : }
429 0 : tp->z = z;
430 0 : tp->down = down;
431 0 : }
432 :
433 : void
434 0 : uts_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
435 : {
436 0 : struct uts_softc *sc = addr;
437 0 : u_int32_t len;
438 : int s;
439 0 : struct uts_pos tp;
440 :
441 0 : if (status == USBD_CANCELLED)
442 0 : return;
443 :
444 0 : if (status != USBD_NORMAL_COMPLETION) {
445 0 : printf("%s: status %d\n", sc->sc_dev.dv_xname, status);
446 0 : if (status == USBD_STALLED)
447 0 : usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
448 0 : return;
449 : }
450 :
451 0 : usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
452 :
453 0 : s = spltty();
454 :
455 0 : uts_get_pos(sc, &tp);
456 :
457 0 : if (len != sc->sc_pkts) {
458 : DPRINTF(("%s: bad input length %d != %d\n",
459 : sc->sc_dev.dv_xname, len, sc->sc_isize));
460 0 : splx(s);
461 0 : return;
462 : }
463 :
464 : DPRINTF(("%s: tp.down = %d, tp.z = %d, tp.x = %d, tp.y = %d\n",
465 : sc->sc_dev.dv_xname, tp.down, tp.z, tp.x, tp.y));
466 :
467 0 : WSMOUSE_TOUCH(sc->sc_wsmousedev, tp.down, tp.x, tp.y, tp.z, 0);
468 0 : sc->sc_oldy = tp.y;
469 0 : sc->sc_oldx = tp.x;
470 :
471 0 : splx(s);
472 0 : }
|