Annotation of sys/dev/usb/uts.c, Revision 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