Annotation of sys/dev/usb/uts.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uts.c,v 1.17 2007/06/14 10:11:16 mbalmer 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:
30: #include <machine/bus.h>
31: #include <machine/endian.h>
32: #include <machine/intr.h>
33:
34: #include <dev/usb/usb.h>
35: #include <dev/usb/usbdi.h>
36: #include <dev/usb/usbdi_util.h>
37: #include <dev/usb/usbdevs.h>
38:
39: #include <dev/wscons/wsconsio.h>
40: #include <dev/wscons/wsmousevar.h>
41:
42: #ifdef USB_DEBUG
43: #define UTS_DEBUG
44: #endif
45:
46: #ifdef UTS_DEBUG
47: #define DPRINTF(x) do { printf x; } while (0)
48: #else
49: #define DPRINTF(x)
50: #endif
51:
52: #define UTS_CONFIG_INDEX 0
53:
54: struct tsscale {
55: int minx, maxx;
56: int miny, maxy;
57: int swapxy;
58: int resx, resy;
59: } def_scale = {
60: 67, 1931, 102, 1937, 0, 1024, 768
61: };
62:
63: struct uts_softc {
64: struct device sc_dev;
65: usbd_device_handle sc_udev;
66: usbd_interface_handle sc_iface;
67: int sc_iface_number;
68: int sc_product;
69: int sc_vendor;
70:
71: int sc_intr_number;
72: usbd_pipe_handle sc_intr_pipe;
73: u_char *sc_ibuf;
74: int sc_isize;
75: u_int8_t sc_pkts;
76:
77: struct device *sc_wsmousedev;
78:
79: int sc_enabled;
80: int sc_buttons;
81: int sc_dying;
82: int sc_oldx;
83: int sc_oldy;
84: int sc_rawmode;
85:
86: struct tsscale sc_tsscale;
87: };
88:
89: struct uts_pos {
90: int x;
91: int y;
92: int z; /* touch pressure */
93: };
94:
95: const struct usb_devno uts_devs[] = {
96: { USB_VENDOR_FTDI, USB_PRODUCT_FTDI_ITM_TOUCH },
97: { USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL },
98: { USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2 },
99: { USB_VENDOR_GUNZE, USB_PRODUCT_GUNZE_TOUCHPANEL }
100: };
101:
102: void uts_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
103: struct uts_pos uts_get_pos(usbd_private_handle addr, struct uts_pos tp);
104:
105: int uts_enable(void *);
106: void uts_disable(void *);
107: int uts_ioctl(void *, u_long, caddr_t, int, struct proc *);
108:
109: const struct wsmouse_accessops uts_accessops = {
110: uts_enable,
111: uts_ioctl,
112: uts_disable,
113: };
114:
115: int uts_match(struct device *, void *, void *);
116: void uts_attach(struct device *, struct device *, void *);
117: int uts_detach(struct device *, int);
118: int uts_activate(struct device *, enum devact);
119:
120: struct cfdriver uts_cd = {
121: NULL, "uts", DV_DULL
122: };
123:
124: const struct cfattach uts_ca = {
125: sizeof(struct uts_softc),
126: uts_match,
127: uts_attach,
128: uts_detach,
129: uts_activate,
130: };
131:
132: int
133: uts_match(struct device *parent, void *match, void *aux)
134: {
135: struct usb_attach_arg *uaa = aux;
136:
137: if (uaa->iface == NULL)
138: return UMATCH_NONE;
139:
140: return (usb_lookup(uts_devs, uaa->vendor, uaa->product) != NULL) ?
141: UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
142: }
143:
144: void
145: uts_attach(struct device *parent, struct device *self, void *aux)
146: {
147: struct uts_softc *sc = (struct uts_softc *)self;
148: struct usb_attach_arg *uaa = aux;
149: usb_config_descriptor_t *cdesc;
150: usb_interface_descriptor_t *id;
151: usb_endpoint_descriptor_t *ed;
152: struct wsmousedev_attach_args a;
153: char *devinfop;
154: int i, found;
155:
156: sc->sc_udev = uaa->device;
157: sc->sc_product = uaa->product;
158: sc->sc_vendor = uaa->vendor;
159: sc->sc_intr_number = -1;
160: sc->sc_intr_pipe = NULL;
161: sc->sc_enabled = sc->sc_isize = 0;
162:
163: /* Copy the default scalue values to each softc */
164: bcopy(&def_scale, &sc->sc_tsscale, sizeof(sc->sc_tsscale));
165:
166: /* Display device info string */
167: printf("\n");
168: devinfop = usbd_devinfo_alloc(uaa->device, 0);
169: printf("%s: %s\n", sc->sc_dev.dv_xname, devinfop);
170: usbd_devinfo_free(devinfop);
171:
172: /* Move the device into the configured state. */
173: if (usbd_set_config_index(uaa->device, UTS_CONFIG_INDEX, 1) != 0) {
174: printf("%s: could not set configuartion no\n",
175: sc->sc_dev.dv_xname);
176: sc->sc_dying = 1;
177: return;
178: }
179:
180: /* get the config descriptor */
181: cdesc = usbd_get_config_descriptor(sc->sc_udev);
182: if (cdesc == NULL) {
183: printf("%s: failed to get configuration descriptor\n",
184: sc->sc_dev.dv_xname);
185: sc->sc_dying = 1;
186: return;
187: }
188:
189: /* get the interface */
190: if (usbd_device2interface_handle(uaa->device, 0, &sc->sc_iface) != 0) {
191: printf("%s: failed to get interface\n",
192: sc->sc_dev.dv_xname);
193: sc->sc_dying = 1;
194: return;
195: }
196:
197: /* Find the interrupt endpoint */
198: id = usbd_get_interface_descriptor(sc->sc_iface);
199: sc->sc_iface_number = id->bInterfaceNumber;
200: found = 0;
201:
202: for (i = 0; i < id->bNumEndpoints; i++) {
203: ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
204: if (ed == NULL) {
205: printf("%s: no endpoint descriptor for %d\n",
206: sc->sc_dev.dv_xname, i);
207: sc->sc_dying = 1;
208: return;
209: }
210:
211: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
212: UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
213: sc->sc_intr_number = ed->bEndpointAddress;
214: sc->sc_isize = UGETW(ed->wMaxPacketSize);
215: }
216: }
217:
218: if (sc->sc_intr_number== -1) {
219: printf("%s: Could not find interrupt in\n",
220: sc->sc_dev.dv_xname);
221: sc->sc_dying = 1;
222: return;
223: }
224:
225: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
226: &sc->sc_dev);
227:
228: a.accessops = &uts_accessops;
229: a.accesscookie = sc;
230:
231: sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
232: }
233:
234: int
235: uts_detach(struct device *self, int flags)
236: {
237: struct uts_softc *sc = (struct uts_softc *)self;
238: int rv = 0;
239:
240: if (sc->sc_intr_pipe != NULL) {
241: usbd_abort_pipe(sc->sc_intr_pipe);
242: usbd_close_pipe(sc->sc_intr_pipe);
243: sc->sc_intr_pipe = NULL;
244: }
245:
246: sc->sc_dying = 1;
247:
248: if (sc->sc_wsmousedev != NULL) {
249: rv = config_detach(sc->sc_wsmousedev, flags);
250: sc->sc_wsmousedev = NULL;
251: }
252:
253: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
254: &sc->sc_dev);
255:
256: return (rv);
257: }
258:
259: int
260: uts_activate(struct device *self, enum devact act)
261: {
262: struct uts_softc *sc = (struct uts_softc *)self;
263: int rv = 0;
264:
265: switch (act) {
266: case DVACT_ACTIVATE:
267: break;
268:
269: case DVACT_DEACTIVATE:
270: if (sc->sc_wsmousedev != NULL)
271: rv = config_deactivate(sc->sc_wsmousedev);
272: sc->sc_dying = 1;
273: break;
274: }
275:
276: return (rv);
277: }
278:
279: int
280: uts_enable(void *v)
281: {
282: struct uts_softc *sc = v;
283: int err;
284:
285: if (sc->sc_dying)
286: return (EIO);
287:
288: if (sc->sc_enabled)
289: return (EBUSY);
290:
291: if (sc->sc_isize == 0)
292: return 0;
293: sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
294: err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_intr_number,
295: USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_ibuf,
296: sc->sc_isize, uts_intr, USBD_DEFAULT_INTERVAL);
297: if (err) {
298: free(sc->sc_ibuf, M_USBDEV);
299: sc->sc_intr_pipe = NULL;
300: return EIO;
301: }
302:
303: sc->sc_enabled = 1;
304: sc->sc_buttons = 0;
305:
306: return (0);
307: }
308:
309: void
310: uts_disable(void *v)
311: {
312: struct uts_softc *sc = v;
313:
314: if (!sc->sc_enabled) {
315: printf("uts_disable: already disabled!\n");
316: return;
317: }
318:
319: /* Disable interrupts. */
320: if (sc->sc_intr_pipe != NULL) {
321: usbd_abort_pipe(sc->sc_intr_pipe);
322: usbd_close_pipe(sc->sc_intr_pipe);
323: sc->sc_intr_pipe = NULL;
324: }
325:
326: if (sc->sc_ibuf != NULL) {
327: free(sc->sc_ibuf, M_USBDEV);
328: sc->sc_ibuf = NULL;
329: }
330:
331: sc->sc_enabled = 0;
332: }
333:
334: int
335: uts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *l)
336: {
337: int error = 0;
338: struct uts_softc *sc = v;
339: struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
340:
341: DPRINTF(("uts_ioctl(%d, '%c', %d)\n",
342: IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));
343:
344: switch (cmd) {
345: case WSMOUSEIO_SCALIBCOORDS:
346: if (!(wsmc->minx >= 0 && wsmc->maxx >= 0 &&
347: wsmc->miny >= 0 && wsmc->maxy >= 0 &&
348: wsmc->resx >= 0 && wsmc->resy >= 0 &&
349: wsmc->minx < 32768 && wsmc->maxx < 32768 &&
350: wsmc->miny < 32768 && wsmc->maxy < 32768 &&
351: wsmc->resx < 32768 && wsmc->resy < 32768 &&
352: wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
353: wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
354: return (EINVAL);
355:
356: sc->sc_tsscale.minx = wsmc->minx;
357: sc->sc_tsscale.maxx = wsmc->maxx;
358: sc->sc_tsscale.miny = wsmc->miny;
359: sc->sc_tsscale.maxy = wsmc->maxy;
360: sc->sc_tsscale.swapxy = wsmc->swapxy;
361: sc->sc_tsscale.resx = wsmc->resx;
362: sc->sc_tsscale.resy = wsmc->resy;
363: sc->sc_rawmode = wsmc->samplelen;
364: break;
365: case WSMOUSEIO_GCALIBCOORDS:
366: wsmc->minx = sc->sc_tsscale.minx;
367: wsmc->maxx = sc->sc_tsscale.maxx;
368: wsmc->miny = sc->sc_tsscale.miny;
369: wsmc->maxy = sc->sc_tsscale.maxy;
370: wsmc->swapxy = sc->sc_tsscale.swapxy;
371: wsmc->resx = sc->sc_tsscale.resx;
372: wsmc->resy = sc->sc_tsscale.resy;
373: wsmc->samplelen = sc->sc_rawmode;
374: break;
375: case WSMOUSEIO_GTYPE:
376: *(u_int *)data = WSMOUSE_TYPE_TPANEL;
377: break;
378: default:
379: error = ENOTTY;
380: break;
381: }
382:
383: return (error);
384: }
385:
386: struct uts_pos
387: uts_get_pos(usbd_private_handle addr, struct uts_pos tp)
388: {
389: struct uts_softc *sc = addr;
390: u_char *p = sc->sc_ibuf;
391: int down, x, y;
392:
393: switch (sc->sc_product) {
394: case USB_PRODUCT_FTDI_ITM_TOUCH:
395: down = (~p[7] & 0x20);
396: x = ((p[0] & 0x1f) << 7) | (p[3] & 0x7f);
397: /* Invert the Y coordinate */
398: y = 0x0fff - abs(((p[1] & 0x1f) << 7) | (p[4] & 0x7f));
399: sc->sc_pkts = 0x8;
400: break;
401: case USB_PRODUCT_EGALAX_TPANEL:
402: case USB_PRODUCT_EGALAX_TPANEL2:
403: /*
404: * eGalax and Gunze USB touch panels have the same device ID,
405: * so decide upon the vendor ID.
406: */
407: switch (sc->sc_vendor) {
408: case USB_VENDOR_EGALAX:
409: down = (p[0] & 0x01);
410: /* Invert the X coordiate */
411: x = 0x07ff - abs(((p[3] & 0x0f) << 7) | (p[4] & 0x7f));
412: y = ((p[1] & 0x0f) << 7) | (p[2] & 0x7f);
413: sc->sc_pkts = 0x5;
414: break;
415: case USB_VENDOR_GUNZE:
416: down = (~p[7] & 0x20);
417: /* Invert the X coordinate */
418: x = 0x0fff - abs(((p[0] & 0x1f) << 7) | (p[2] & 0x7f));
419: y = ((p[1] & 0x1f) << 7) | (p[3] & 0x7f);
420: sc->sc_pkts = 0x4;
421: break;
422: }
423: break;
424: }
425:
426: DPRINTF(("%s: down = 0x%x, sc->sc_pkts = 0x%x\n",
427: sc->sc_dev.dv_xname, down, sc->sc_pkts));
428:
429: /* x/y values are not reliable if there is no pressure */
430: if (down) {
431: if (sc->sc_tsscale.swapxy) { /* Swap X/Y-Axis */
432: tp.y = x;
433: tp.x = y;
434: } else {
435: tp.x = x;
436: tp.y = y;
437: }
438:
439: if (!sc->sc_rawmode) {
440: /* Scale down to the screen resolution. */
441: tp.x = ((tp.x - sc->sc_tsscale.minx) *
442: sc->sc_tsscale.resx) /
443: (sc->sc_tsscale.maxx - sc->sc_tsscale.minx);
444: tp.y = ((tp.y - sc->sc_tsscale.miny) *
445: sc->sc_tsscale.resy) /
446: (sc->sc_tsscale.maxy - sc->sc_tsscale.miny);
447: }
448: tp.z = 1;
449: } else {
450: tp.x = sc->sc_oldx;
451: tp.y = sc->sc_oldy;
452: tp.z = 0;
453: }
454:
455: return (tp);
456: }
457:
458: void
459: uts_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
460: {
461: struct uts_softc *sc = addr;
462: u_int32_t len;
463: int s;
464: struct uts_pos tp;
465:
466: usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
467:
468: s = spltty();
469:
470: if (status == USBD_CANCELLED)
471: return;
472:
473: if (status != USBD_NORMAL_COMPLETION) {
474: printf("%s: status %d\n", sc->sc_dev.dv_xname, status);
475: usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
476: return;
477: }
478:
479: tp = uts_get_pos(sc, tp);
480:
481: if (len != sc->sc_pkts) {
482: DPRINTF(("%s: bad input length %d != %d\n",
483: sc->sc_dev.dv_xname, len, sc->sc_isize));
484: return;
485: }
486:
487: DPRINTF(("%s: tp.z = %d, tp.x = %d, tp.y = %d\n",
488: sc->sc_dev.dv_xname, tp.z, tp.x, tp.y));
489:
490: wsmouse_input(sc->sc_wsmousedev, tp.z, tp.x, tp.y, 0, 0,
491: WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
492: WSMOUSE_INPUT_ABSOLUTE_Z);
493: sc->sc_oldy = tp.y;
494: sc->sc_oldx = tp.x;
495:
496: splx(s);
497: }
CVSweb