The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/input/uep.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 2010, Gleb Smirnoff <glebius@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 /*
   32  *  http://www.eeti.com.tw/pdf/Software%20Programming%20Guide_v2.0.pdf
   33  */
   34 
   35 #include "opt_evdev.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/bus.h>
   39 #include <sys/callout.h>
   40 #include <sys/conf.h>
   41 #include <sys/kernel.h>
   42 #include <sys/lock.h>
   43 #include <sys/module.h>
   44 #include <sys/mutex.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/systm.h>
   47 
   48 #include <dev/usb/usb.h>
   49 #include <dev/usb/usbdi.h>
   50 #include <dev/usb/usbdi_util.h>
   51 #include <dev/usb/usbhid.h>
   52 #include "usbdevs.h"
   53 
   54 #ifdef EVDEV_SUPPORT
   55 #include <dev/evdev/input.h>
   56 #include <dev/evdev/evdev.h>
   57 #else
   58 #include <sys/ioccom.h>
   59 #include <sys/fcntl.h>
   60 #endif
   61 
   62 #define USB_DEBUG_VAR uep_debug
   63 #include <dev/usb/usb_debug.h>
   64 
   65 #ifdef USB_DEBUG
   66 static int uep_debug = 0;
   67 
   68 static SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   69     "USB uep");
   70 SYSCTL_INT(_hw_usb_uep, OID_AUTO, debug, CTLFLAG_RWTUN,
   71     &uep_debug, 0, "Debug level");
   72 #endif
   73 
   74 #define UEP_MAX_X               2047
   75 #define UEP_MAX_Y               2047
   76 
   77 #define UEP_DOWN                0x01
   78 #define UEP_PACKET_LEN_MAX      16
   79 #define UEP_PACKET_LEN_REPORT   5
   80 #define UEP_PACKET_LEN_REPORT2  6
   81 #define UEP_PACKET_DIAG         0x0a
   82 #define UEP_PACKET_REPORT_MASK          0xe0
   83 #define UEP_PACKET_REPORT               0x80
   84 #define UEP_PACKET_REPORT_PRESSURE      0xc0
   85 #define UEP_PACKET_REPORT_PLAYER        0xa0
   86 #define UEP_PACKET_LEN_MASK     
   87 
   88 #define UEP_FIFO_BUF_SIZE       8       /* bytes */
   89 #define UEP_FIFO_QUEUE_MAXLEN   50      /* units */
   90 
   91 enum {
   92         UEP_INTR_DT,
   93         UEP_N_TRANSFER,
   94 };
   95 
   96 struct uep_softc {
   97         struct mtx mtx;
   98 
   99         struct usb_xfer *xfer[UEP_N_TRANSFER];
  100 #ifdef EVDEV_SUPPORT
  101         struct evdev_dev *evdev;
  102 #else
  103         struct usb_fifo_sc fifo;
  104 
  105         u_int           pollrate;
  106         u_int           state;
  107 #define UEP_ENABLED     0x01
  108 #endif
  109 
  110         /* Reassembling buffer. */
  111         u_char          buf[UEP_PACKET_LEN_MAX];
  112         uint8_t         buf_len;
  113 };
  114 
  115 static usb_callback_t uep_intr_callback;
  116 
  117 static device_probe_t   uep_probe;
  118 static device_attach_t  uep_attach;
  119 static device_detach_t  uep_detach;
  120 
  121 #ifdef EVDEV_SUPPORT
  122 
  123 static evdev_open_t     uep_ev_open;
  124 static evdev_close_t    uep_ev_close;
  125 
  126 static const struct evdev_methods uep_evdev_methods = {
  127         .ev_open = &uep_ev_open,
  128         .ev_close = &uep_ev_close,
  129 };
  130 
  131 #else /* !EVDEV_SUPPORT */
  132 
  133 static usb_fifo_cmd_t   uep_start_read;
  134 static usb_fifo_cmd_t   uep_stop_read;
  135 static usb_fifo_open_t  uep_open;
  136 static usb_fifo_close_t uep_close;
  137 
  138 static void uep_put_queue(struct uep_softc *, u_char *);
  139 
  140 static struct usb_fifo_methods uep_fifo_methods = {
  141         .f_open = &uep_open,
  142         .f_close = &uep_close,
  143         .f_start_read = &uep_start_read,
  144         .f_stop_read = &uep_stop_read,
  145         .basename[0] = "uep",
  146 };
  147 #endif /* !EVDEV_SUPPORT */
  148 
  149 static int
  150 get_pkt_len(u_char *buf)
  151 {
  152         if (buf[0] == UEP_PACKET_DIAG) {
  153                 int len;
  154 
  155                 len = buf[1] + 2;
  156                 if (len > UEP_PACKET_LEN_MAX) {
  157                         DPRINTF("bad packet len %u\n", len);
  158                         return (UEP_PACKET_LEN_MAX);
  159                 }
  160 
  161                 return (len);
  162         }
  163 
  164         switch (buf[0] & UEP_PACKET_REPORT_MASK) {
  165         case UEP_PACKET_REPORT:
  166                 return (UEP_PACKET_LEN_REPORT);
  167         case UEP_PACKET_REPORT_PRESSURE:
  168         case UEP_PACKET_REPORT_PLAYER:
  169         case UEP_PACKET_REPORT_PRESSURE | UEP_PACKET_REPORT_PLAYER:
  170                 return (UEP_PACKET_LEN_REPORT2);
  171         default:
  172                 DPRINTF("bad packet len 0\n");
  173                 return (0);
  174         }
  175 }
  176 
  177 static void
  178 uep_process_pkt(struct uep_softc *sc, u_char *buf)
  179 {
  180         int32_t x __usbdebug_used, y __usbdebug_used;
  181 #ifdef EVDEV_SUPPORT
  182         int touch;
  183 #endif
  184 
  185         if ((buf[0] & 0xFE) != 0x80) {
  186                 DPRINTF("bad input packet format 0x%.2x\n", buf[0]);
  187                 return;
  188         }
  189 
  190         /*
  191          * Packet format is 5 bytes:
  192          *
  193          * 1000000T
  194          * 0000AAAA
  195          * 0AAAAAAA
  196          * 0000BBBB
  197          * 0BBBBBBB
  198          *
  199          * T: 1=touched 0=not touched
  200          * A: bits of axis A position, MSB to LSB
  201          * B: bits of axis B position, MSB to LSB
  202          *
  203          * For the unit I have, which is CTF1020-S from CarTFT.com,
  204          * A = X and B = Y. But in NetBSD uep(4) it is other way round :)
  205          *
  206          * The controller sends a stream of T=1 events while the
  207          * panel is touched, followed by a single T=0 event.
  208          *
  209          */
  210 
  211         x = (buf[1] << 7) | buf[2];
  212         y = (buf[3] << 7) | buf[4];
  213 
  214         DPRINTFN(2, "x %u y %u\n", x, y);
  215 
  216 #ifdef EVDEV_SUPPORT
  217         touch = buf[0] & (1 << 0);
  218         if (touch) {
  219                 evdev_push_abs(sc->evdev, ABS_X, x);
  220                 evdev_push_abs(sc->evdev, ABS_Y, y);
  221         }
  222         evdev_push_key(sc->evdev, BTN_TOUCH, touch);
  223         evdev_sync(sc->evdev);
  224 #else
  225         uep_put_queue(sc, buf);
  226 #endif
  227 }
  228 
  229 static void
  230 uep_intr_callback(struct usb_xfer *xfer, usb_error_t error)
  231 {
  232         struct uep_softc *sc = usbd_xfer_softc(xfer);
  233         int len;
  234 
  235         usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
  236 
  237         switch (USB_GET_STATE(xfer)) {
  238         case USB_ST_TRANSFERRED:
  239             {
  240                 struct usb_page_cache *pc;
  241                 u_char buf[17], *p;
  242                 int pkt_len;
  243 
  244                 if (len > (int)sizeof(buf)) {
  245                         DPRINTF("bad input length %d\n", len);
  246                         goto tr_setup;
  247                 }
  248 
  249                 pc = usbd_xfer_get_frame(xfer, 0);
  250                 usbd_copy_out(pc, 0, buf, len);
  251 
  252                 /*
  253                  * The below code mimics Linux a lot. I don't know
  254                  * why NetBSD reads complete packets, but we need
  255                  * to reassamble 'em like Linux does (tries?).
  256                  */
  257                 if (sc->buf_len > 0) {
  258                         int res;
  259 
  260                         if (sc->buf_len == 1)
  261                                 sc->buf[1] = buf[0];
  262 
  263                         if ((pkt_len = get_pkt_len(sc->buf)) == 0)
  264                                 goto tr_setup;
  265 
  266                         res = pkt_len - sc->buf_len;
  267                         memcpy(sc->buf + sc->buf_len, buf, res);
  268                         uep_process_pkt(sc, sc->buf);
  269                         sc->buf_len = 0;
  270 
  271                         p = buf + res;
  272                         len -= res;
  273                 } else
  274                         p = buf;
  275 
  276                 if (len == 1) {
  277                         sc->buf[0] = buf[0];
  278                         sc->buf_len = 1;
  279 
  280                         goto tr_setup;
  281                 }
  282 
  283                 while (len > 0) {
  284                         if ((pkt_len = get_pkt_len(p)) == 0)
  285                                 goto tr_setup;
  286 
  287                         /* full packet: process */
  288                         if (pkt_len <= len) {
  289                                 uep_process_pkt(sc, p);
  290                         } else {
  291                                 /* incomplete packet: save in buffer */
  292                                 memcpy(sc->buf, p, len);
  293                                 sc->buf_len = len;
  294                         }
  295                         p += pkt_len;
  296                         len -= pkt_len;
  297                 }
  298             }
  299         case USB_ST_SETUP:
  300         tr_setup:
  301 #ifndef EVDEV_SUPPORT
  302                 /* check if we can put more data into the FIFO */
  303                 if (usb_fifo_put_bytes_max(sc->fifo.fp[USB_FIFO_RX]) == 0)
  304                         break;
  305 #endif
  306                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  307                 usbd_transfer_submit(xfer);
  308                 break;
  309 
  310         default:
  311                 if (error != USB_ERR_CANCELLED) {
  312                         /* try clear stall first */
  313                         usbd_xfer_set_stall(xfer);
  314                         goto tr_setup;
  315                 }
  316                 break;
  317         }
  318 }
  319 
  320 static const struct usb_config uep_config[UEP_N_TRANSFER] = {
  321         [UEP_INTR_DT] = {
  322                 .type = UE_INTERRUPT,
  323                 .endpoint = UE_ADDR_ANY,
  324                 .direction = UE_DIR_IN,
  325                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  326                 .bufsize = 0,   /* use wMaxPacketSize */
  327                 .callback = &uep_intr_callback,
  328         },
  329 };
  330 
  331 static const STRUCT_USB_HOST_ID uep_devs[] = {
  332         {USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL, 0)},
  333         {USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2, 0)},
  334         {USB_VPI(USB_VENDOR_EGALAX2, USB_PRODUCT_EGALAX2_TPANEL, 0)},
  335 };
  336 
  337 static int
  338 uep_probe(device_t dev)
  339 {
  340         struct usb_attach_arg *uaa = device_get_ivars(dev);
  341 
  342         if (uaa->usb_mode != USB_MODE_HOST)
  343                 return (ENXIO);
  344         if (uaa->info.bConfigIndex != 0)
  345                 return (ENXIO);
  346         if (uaa->info.bIfaceIndex != 0)
  347                 return (ENXIO);
  348 
  349         return (usbd_lookup_id_by_uaa(uep_devs, sizeof(uep_devs), uaa));
  350 }
  351 
  352 static int
  353 uep_attach(device_t dev)
  354 {
  355         struct usb_attach_arg *uaa = device_get_ivars(dev);
  356         struct uep_softc *sc = device_get_softc(dev);
  357         int error;
  358 
  359         device_set_usb_desc(dev);
  360 
  361         mtx_init(&sc->mtx, "uep lock", NULL, MTX_DEF);
  362 
  363         error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
  364             sc->xfer, uep_config, UEP_N_TRANSFER, sc, &sc->mtx);
  365 
  366         if (error) {
  367                 DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error));
  368                 goto detach;
  369         }
  370 
  371 #ifdef EVDEV_SUPPORT
  372         sc->evdev = evdev_alloc();
  373         evdev_set_name(sc->evdev, device_get_desc(dev));
  374         evdev_set_phys(sc->evdev, device_get_nameunit(dev));
  375         evdev_set_id(sc->evdev, BUS_USB, uaa->info.idVendor,
  376             uaa->info.idProduct, 0);
  377         evdev_set_serial(sc->evdev, usb_get_serial(uaa->device));
  378         evdev_set_methods(sc->evdev, sc, &uep_evdev_methods);
  379         evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT);
  380         evdev_support_event(sc->evdev, EV_SYN);
  381         evdev_support_event(sc->evdev, EV_ABS);
  382         evdev_support_event(sc->evdev, EV_KEY);
  383         evdev_support_key(sc->evdev, BTN_TOUCH);
  384         evdev_support_abs(sc->evdev, ABS_X, 0, UEP_MAX_X, 0, 0, 0);
  385         evdev_support_abs(sc->evdev, ABS_Y, 0, UEP_MAX_Y, 0, 0, 0);
  386 
  387         error = evdev_register_mtx(sc->evdev, &sc->mtx);
  388         if (error) {
  389                 DPRINTF("evdev_register_mtx error=%s\n", usbd_errstr(error));
  390                 goto detach;
  391         }
  392 #else /* !EVDEV_SUPPORT */
  393         error = usb_fifo_attach(uaa->device, sc, &sc->mtx, &uep_fifo_methods,
  394             &sc->fifo, device_get_unit(dev), -1, uaa->info.bIfaceIndex,
  395             UID_ROOT, GID_OPERATOR, 0644);
  396 
  397         if (error) {
  398                 DPRINTF("usb_fifo_attach error=%s\n", usbd_errstr(error));
  399                 goto detach;
  400         }
  401 #endif /* !EVDEV_SUPPORT */
  402 
  403         sc->buf_len = 0;
  404 
  405         return (0);     
  406 
  407 detach:
  408         uep_detach(dev);
  409 
  410         return (ENOMEM); /* XXX */
  411 }
  412 
  413 static int
  414 uep_detach(device_t dev)
  415 {
  416         struct uep_softc *sc = device_get_softc(dev);
  417 
  418 #ifdef EVDEV_SUPPORT
  419         evdev_free(sc->evdev);
  420 #else
  421         usb_fifo_detach(&sc->fifo);
  422 #endif
  423 
  424         usbd_transfer_unsetup(sc->xfer, UEP_N_TRANSFER);
  425 
  426         mtx_destroy(&sc->mtx);
  427 
  428         return (0);
  429 }
  430 
  431 #ifdef EVDEV_SUPPORT
  432 
  433 static int
  434 uep_ev_close(struct evdev_dev *evdev)
  435 {
  436         struct uep_softc *sc = evdev_get_softc(evdev);
  437 
  438         mtx_assert(&sc->mtx, MA_OWNED);
  439         usbd_transfer_stop(sc->xfer[UEP_INTR_DT]);
  440 
  441         return (0);
  442 }
  443 
  444 static int
  445 uep_ev_open(struct evdev_dev *evdev)
  446 {
  447         struct uep_softc *sc = evdev_get_softc(evdev);
  448 
  449         mtx_assert(&sc->mtx, MA_OWNED);
  450         usbd_transfer_start(sc->xfer[UEP_INTR_DT]);
  451 
  452         return (0);
  453 }
  454 
  455 #else /* !EVDEV_SUPPORT */
  456 
  457 static void
  458 uep_start_read(struct usb_fifo *fifo)
  459 {
  460         struct uep_softc *sc = usb_fifo_softc(fifo);
  461         u_int rate;
  462 
  463         if ((rate = sc->pollrate) > 1000)
  464                 rate = 1000;
  465 
  466         if (rate > 0 && sc->xfer[UEP_INTR_DT] != NULL) {
  467                 usbd_transfer_stop(sc->xfer[UEP_INTR_DT]);
  468                 usbd_xfer_set_interval(sc->xfer[UEP_INTR_DT], 1000 / rate);
  469                 sc->pollrate = 0;
  470         }
  471 
  472         usbd_transfer_start(sc->xfer[UEP_INTR_DT]);
  473 }
  474 
  475 static void
  476 uep_stop_read(struct usb_fifo *fifo)
  477 {
  478         struct uep_softc *sc = usb_fifo_softc(fifo);
  479 
  480         usbd_transfer_stop(sc->xfer[UEP_INTR_DT]);
  481 }
  482 
  483 static void
  484 uep_put_queue(struct uep_softc *sc, u_char *buf)
  485 {
  486         usb_fifo_put_data_linear(sc->fifo.fp[USB_FIFO_RX], buf,
  487             UEP_PACKET_LEN_REPORT, 1);
  488 }
  489 
  490 static int
  491 uep_open(struct usb_fifo *fifo, int fflags)
  492 {
  493         if (fflags & FREAD) {
  494                 struct uep_softc *sc = usb_fifo_softc(fifo);
  495 
  496                 if (sc->state & UEP_ENABLED)
  497                         return (EBUSY);
  498                 if (usb_fifo_alloc_buffer(fifo, UEP_FIFO_BUF_SIZE,
  499                     UEP_FIFO_QUEUE_MAXLEN))
  500                         return (ENOMEM);
  501 
  502                 sc->state |= UEP_ENABLED;
  503         }
  504 
  505         return (0);
  506 }
  507 
  508 static void
  509 uep_close(struct usb_fifo *fifo, int fflags)
  510 {
  511         if (fflags & FREAD) {
  512                 struct uep_softc *sc = usb_fifo_softc(fifo);
  513 
  514                 sc->state &= ~(UEP_ENABLED);
  515                 usb_fifo_free_buffer(fifo);
  516         }
  517 }
  518 #endif /* !EVDEV_SUPPORT */
  519 
  520 static device_method_t uep_methods[] = {
  521         DEVMETHOD(device_probe, uep_probe),
  522         DEVMETHOD(device_attach, uep_attach),
  523         DEVMETHOD(device_detach, uep_detach),
  524         { 0, 0 },
  525 };
  526 
  527 static driver_t uep_driver = {
  528         .name = "uep",
  529         .methods = uep_methods,
  530         .size = sizeof(struct uep_softc),
  531 };
  532 
  533 DRIVER_MODULE(uep, uhub, uep_driver, NULL, NULL);
  534 MODULE_DEPEND(uep, usb, 1, 1, 1);
  535 #ifdef EVDEV_SUPPORT
  536 MODULE_DEPEND(uep, evdev, 1, 1, 1);
  537 #endif
  538 MODULE_VERSION(uep, 1);
  539 USB_PNP_HOST_INFO(uep_devs);

Cache object: 43b166f90983fd077d73d1d143402e75


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.