root/dev/usb/uts.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uts_match
  2. uts_attach
  3. uts_detach
  4. uts_activate
  5. uts_enable
  6. uts_disable
  7. uts_ioctl
  8. uts_get_pos
  9. uts_intr

    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 }

/* [<][>][^][v][top][bottom][index][help] */