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/usbmisc/uhid/uhid.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  * $NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $
    3  * $FreeBSD: src/sys/dev/usb/uhid.c,v 1.65 2003/11/09 09:17:22 tanimura Exp $
    4  */
    5 
    6 /* Also already merged from NetBSD:
    7  *      $NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $
    8  */
    9 
   10 /*
   11  * Copyright (c) 1998 The NetBSD Foundation, Inc.
   12  * All rights reserved.
   13  *
   14  * This code is derived from software contributed to The NetBSD Foundation
   15  * by Lennart Augustsson (lennart@augustsson.net) at
   16  * Carlstedt Research & Technology.
   17  *
   18  * Redistribution and use in source and binary forms, with or without
   19  * modification, are permitted provided that the following conditions
   20  * are met:
   21  * 1. Redistributions of source code must retain the above copyright
   22  *    notice, this list of conditions and the following disclaimer.
   23  * 2. Redistributions in binary form must reproduce the above copyright
   24  *    notice, this list of conditions and the following disclaimer in the
   25  *    documentation and/or other materials provided with the distribution.
   26  * 3. All advertising materials mentioning features or use of this software
   27  *    must display the following acknowledgement:
   28  *        This product includes software developed by the NetBSD
   29  *        Foundation, Inc. and its contributors.
   30  * 4. Neither the name of The NetBSD Foundation nor the names of its
   31  *    contributors may be used to endorse or promote products derived
   32  *    from this software without specific prior written permission.
   33  *
   34  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   35  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   36  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   37  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   38  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   39  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   40  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   41  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   42  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   43  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   44  * POSSIBILITY OF SUCH DAMAGE.
   45  */
   46 
   47 /*
   48  * HID spec: http://www.usb.org/developers/data/usbhid10.pdf
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/kernel.h>
   54 #include <sys/lock.h>
   55 #include <sys/malloc.h>
   56 #include <sys/signalvar.h>
   57 #include <sys/filio.h>
   58 #include <sys/module.h>
   59 #include <sys/bus.h>
   60 #include <sys/conf.h>
   61 #include <sys/tty.h>
   62 #include <sys/proc.h>
   63 #include <sys/vnode.h>
   64 #include <sys/event.h>
   65 #include <sys/sysctl.h>
   66 #include <sys/thread2.h>
   67 
   68 #include <bus/usb/usb.h>
   69 #include <bus/usb/usbhid.h>
   70 
   71 #include <bus/usb/usbdi.h>
   72 #include <bus/usb/usbdi_util.h>
   73 #include <bus/usb/hid.h>
   74 
   75 /* Report descriptor for broken Wacom Graphire */
   76 #include <bus/usb/ugraphire_rdesc.h>
   77 
   78 #ifdef USB_DEBUG
   79 #define DPRINTF(x)      if (uhiddebug) kprintf x
   80 #define DPRINTFN(n,x)   if (uhiddebug>(n)) kprintf x
   81 int     uhiddebug = 0;
   82 SYSCTL_NODE(_hw_usb, OID_AUTO, uhid, CTLFLAG_RW, 0, "USB uhid");
   83 SYSCTL_INT(_hw_usb_uhid, OID_AUTO, debug, CTLFLAG_RW,
   84            &uhiddebug, 0, "uhid debug level");
   85 #else
   86 #define DPRINTF(x)
   87 #define DPRINTFN(n,x)
   88 #endif
   89 
   90 struct uhid_softc {
   91         device_t sc_dev;                        /* base device */
   92         usbd_device_handle sc_udev;
   93         usbd_interface_handle sc_iface; /* interface */
   94         usbd_pipe_handle sc_intrpipe;   /* interrupt pipe */
   95         int sc_ep_addr;
   96 
   97         int sc_isize;
   98         int sc_osize;
   99         int sc_fsize;
  100         u_int8_t sc_iid;
  101         u_int8_t sc_oid;
  102         u_int8_t sc_fid;
  103 
  104         u_char *sc_ibuf;
  105         u_char *sc_obuf;
  106 
  107         void *sc_repdesc;
  108         int sc_repdesc_size;
  109 
  110         struct clist sc_q;
  111         struct kqinfo sc_rkq;
  112         struct proc *sc_async;  /* process that wants SIGIO */
  113         u_char sc_state;        /* driver state */
  114 #define UHID_OPEN       0x01    /* device is open */
  115 #define UHID_ASLP       0x02    /* waiting for device data */
  116 #define UHID_NEEDCLEAR  0x04    /* needs clearing endpoint stall */
  117 #define UHID_IMMED      0x08    /* return read data immediately */
  118 
  119         int sc_refcnt;
  120         u_char sc_dying;
  121 };
  122 
  123 #define UHIDUNIT(dev)   (minor(dev))
  124 #define UHID_CHUNK      128     /* chunk size for read */
  125 #define UHID_BSIZE      1020    /* buffer size */
  126 
  127 d_open_t        uhidopen;
  128 d_close_t       uhidclose;
  129 d_read_t        uhidread;
  130 d_write_t       uhidwrite;
  131 d_ioctl_t       uhidioctl;
  132 d_kqfilter_t    uhidkqfilter;
  133 
  134 static void uhidfilt_detach(struct knote *);
  135 static int uhidfilt_read(struct knote *, long);
  136 static int uhidfilt_write(struct knote *, long);
  137 
  138 static struct dev_ops uhid_ops = {
  139         { "uhid", 0, 0 },
  140         .d_open =       uhidopen,
  141         .d_close =      uhidclose,
  142         .d_read =       uhidread,
  143         .d_write =      uhidwrite,
  144         .d_ioctl =      uhidioctl,
  145         .d_kqfilter =   uhidkqfilter
  146 };
  147 
  148 static void uhid_intr(usbd_xfer_handle, usbd_private_handle,
  149                            usbd_status);
  150 
  151 static int uhid_do_read(struct uhid_softc *, struct uio *uio, int);
  152 static int uhid_do_write(struct uhid_softc *, struct uio *uio, int);
  153 static int uhid_do_ioctl(struct uhid_softc *, u_long, caddr_t, int);
  154 
  155 static device_probe_t uhid_match;
  156 static device_attach_t uhid_attach;
  157 static device_detach_t uhid_detach;
  158 
  159 static devclass_t uhid_devclass;
  160 
  161 static kobj_method_t uhid_methods[] = {
  162         DEVMETHOD(device_probe, uhid_match),
  163         DEVMETHOD(device_attach, uhid_attach),
  164         DEVMETHOD(device_detach, uhid_detach),
  165         DEVMETHOD_END
  166 };
  167 
  168 static driver_t uhid_driver = {
  169         "uhid",
  170         uhid_methods,
  171         sizeof(struct uhid_softc)
  172 };
  173 
  174 MODULE_DEPEND(uhid, usb, 1, 1, 1);
  175 
  176 static int
  177 uhid_match(device_t self)
  178 {
  179         struct usb_attach_arg *uaa = device_get_ivars(self);
  180         usb_interface_descriptor_t *id;
  181 
  182         if (uaa->iface == NULL)
  183                 return (UMATCH_NONE);
  184         id = usbd_get_interface_descriptor(uaa->iface);
  185         if (id == NULL || id->bInterfaceClass != UICLASS_HID)
  186                 return (UMATCH_NONE);
  187         if (uaa->matchlvl)
  188                 return (uaa->matchlvl);
  189         return (UMATCH_IFACECLASS_GENERIC);
  190 }
  191 
  192 static int
  193 uhid_attach(device_t self)
  194 {
  195         struct uhid_softc *sc = device_get_softc(self);
  196         struct usb_attach_arg *uaa = device_get_ivars(self);
  197         usbd_interface_handle iface = uaa->iface;
  198         usb_endpoint_descriptor_t *ed;
  199         int size;
  200         void *desc;
  201         usbd_status err;
  202 
  203         sc->sc_udev = uaa->device;
  204         sc->sc_iface = iface;
  205         sc->sc_dev = self;
  206 
  207         ed = usbd_interface2endpoint_descriptor(iface, 0);
  208         if (ed == NULL) {
  209                 kprintf("%s: could not read endpoint descriptor\n",
  210                        device_get_nameunit(sc->sc_dev));
  211                 sc->sc_dying = 1;
  212                 return ENXIO;
  213         }
  214 
  215         DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d "
  216                      "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
  217                      " bInterval=%d\n",
  218                      ed->bLength, ed->bDescriptorType,
  219                      ed->bEndpointAddress & UE_ADDR,
  220                      UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
  221                      ed->bmAttributes & UE_XFERTYPE,
  222                      UGETW(ed->wMaxPacketSize), ed->bInterval));
  223 
  224         if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
  225             (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
  226                 kprintf("%s: unexpected endpoint\n", device_get_nameunit(sc->sc_dev));
  227                 sc->sc_dying = 1;
  228                 return ENXIO;
  229         }
  230 
  231         sc->sc_ep_addr = ed->bEndpointAddress;
  232 
  233         /* The report descriptor for the Wacom Graphire is broken. */
  234         if (uaa->vendor == 0x056a && uaa->product == 0x0010 /* &&
  235             uaa->revision == 0x???? */) { /* XXX should use revision */
  236                 size = sizeof uhid_graphire_report_descr;
  237                 desc = kmalloc(size, M_USBDEV, M_INTWAIT);
  238                 err = USBD_NORMAL_COMPLETION;
  239                 memcpy(desc, uhid_graphire_report_descr, size);
  240         } else {
  241                 desc = NULL;
  242                 err = usbd_read_report_desc(uaa->iface, &desc, &size,M_USBDEV);
  243         }
  244 
  245         if (err) {
  246                 kprintf("%s: no report descriptor\n", device_get_nameunit(sc->sc_dev));
  247                 sc->sc_dying = 1;
  248                 return ENXIO;
  249         }
  250 
  251         (void)usbd_set_idle(iface, 0, 0);
  252 
  253         sc->sc_isize = hid_report_size(desc, size, hid_input,   &sc->sc_iid);
  254         sc->sc_osize = hid_report_size(desc, size, hid_output,  &sc->sc_oid);
  255         sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid);
  256 
  257         sc->sc_repdesc = desc;
  258         sc->sc_repdesc_size = size;
  259 
  260         make_dev(&uhid_ops, device_get_unit(self),
  261                  UID_ROOT, GID_OPERATOR,
  262                  0644, "uhid%d", device_get_unit(self));
  263 
  264         return 0;
  265 }
  266 
  267 static int
  268 uhid_detach(device_t self)
  269 {
  270         struct uhid_softc *sc = device_get_softc(self);
  271 
  272         DPRINTF(("uhid_detach: sc=%p\n", sc));
  273 
  274         sc->sc_dying = 1;
  275         if (sc->sc_intrpipe != NULL)
  276                 usbd_abort_pipe(sc->sc_intrpipe);
  277 
  278         if (sc->sc_state & UHID_OPEN) {
  279                 crit_enter();
  280                 if (--sc->sc_refcnt >= 0) {
  281                         /* Wake everyone */
  282                         wakeup(&sc->sc_q);
  283                         /* Wait for processes to go away. */
  284                         usb_detach_wait(sc->sc_dev);
  285                 }
  286                 crit_exit();
  287         }
  288 
  289         dev_ops_remove_minor(&uhid_ops, device_get_unit(self));
  290 
  291         if (sc->sc_repdesc)
  292                 kfree(sc->sc_repdesc, M_USBDEV);
  293 
  294         return (0);
  295 }
  296 
  297 void
  298 uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
  299 {
  300         struct uhid_softc *sc = addr;
  301 
  302 #ifdef USB_DEBUG
  303         if (uhiddebug > 5) {
  304                 u_int32_t cc, i;
  305 
  306                 usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
  307                 DPRINTF(("uhid_intr: status=%d cc=%d\n", status, cc));
  308                 DPRINTF(("uhid_intr: data ="));
  309                 for (i = 0; i < cc; i++)
  310                         DPRINTF((" %02x", sc->sc_ibuf[i]));
  311                 DPRINTF(("\n"));
  312         }
  313 #endif
  314 
  315         if (status == USBD_CANCELLED)
  316                 return;
  317 
  318         if (status != USBD_NORMAL_COMPLETION) {
  319                 DPRINTF(("uhid_intr: status=%d\n", status));
  320                 if (status == USBD_STALLED)
  321                     sc->sc_state |= UHID_NEEDCLEAR;
  322                 return;
  323         }
  324 
  325         (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q);
  326 
  327         if (sc->sc_state & UHID_ASLP) {
  328                 sc->sc_state &= ~UHID_ASLP;
  329                 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
  330                 wakeup(&sc->sc_q);
  331         }
  332         KNOTE(&sc->sc_rkq.ki_note, 0);
  333         if (sc->sc_async != NULL) {
  334                 DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async));
  335                 ksignal(sc->sc_async, SIGIO);
  336         }
  337 }
  338 
  339 int
  340 uhidopen(struct dev_open_args *ap)
  341 {
  342         cdev_t dev = ap->a_head.a_dev;
  343         struct uhid_softc *sc;
  344         usbd_status err;
  345 
  346         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  347         if (sc == NULL)
  348                 return (ENXIO);
  349 
  350         DPRINTF(("uhidopen: sc=%p\n", sc));
  351 
  352         if (sc->sc_dying)
  353                 return (ENXIO);
  354 
  355         if (sc->sc_state & UHID_OPEN)
  356                 return (EBUSY);
  357         sc->sc_state |= UHID_OPEN;
  358 
  359         if ((clist_alloc_cblocks(&sc->sc_q, UHID_BSIZE,
  360                                  UHID_BSIZE), 0) == -1) {
  361                 sc->sc_state &= ~UHID_OPEN;
  362                 return (ENOMEM);
  363         }
  364 
  365         sc->sc_ibuf = kmalloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  366         sc->sc_obuf = kmalloc(sc->sc_osize, M_USBDEV, M_WAITOK);
  367 
  368         /* Set up interrupt pipe. */
  369         err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
  370                   USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf,
  371                   sc->sc_isize, uhid_intr, USBD_DEFAULT_INTERVAL);
  372         if (err) {
  373                 DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
  374                          "error=%d\n",err));
  375                 kfree(sc->sc_ibuf, M_USBDEV);
  376                 kfree(sc->sc_obuf, M_USBDEV);
  377                 sc->sc_ibuf = sc->sc_obuf = NULL;
  378 
  379                 sc->sc_state &= ~UHID_OPEN;
  380                 return (EIO);
  381         }
  382 
  383         sc->sc_state &= ~UHID_IMMED;
  384 
  385         sc->sc_async = NULL;
  386 
  387         return (0);
  388 }
  389 
  390 int
  391 uhidclose(struct dev_close_args *ap)
  392 {
  393         cdev_t dev = ap->a_head.a_dev;
  394         struct uhid_softc *sc;
  395 
  396         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  397 
  398         DPRINTF(("uhidclose: sc=%p\n", sc));
  399 
  400         /* Disable interrupts. */
  401         usbd_abort_pipe(sc->sc_intrpipe);
  402         usbd_close_pipe(sc->sc_intrpipe);
  403         sc->sc_intrpipe = 0;
  404 
  405         ndflush(&sc->sc_q, sc->sc_q.c_cc);
  406         clist_free_cblocks(&sc->sc_q);
  407 
  408         kfree(sc->sc_ibuf, M_USBDEV);
  409         kfree(sc->sc_obuf, M_USBDEV);
  410         sc->sc_ibuf = sc->sc_obuf = NULL;
  411 
  412         sc->sc_state &= ~UHID_OPEN;
  413 
  414         sc->sc_async = NULL;
  415 
  416         return (0);
  417 }
  418 
  419 int
  420 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
  421 {
  422         int error = 0;
  423         size_t length;
  424         u_char buffer[UHID_CHUNK];
  425         usbd_status err;
  426 
  427         DPRINTFN(1, ("uhidread\n"));
  428         if (sc->sc_state & UHID_IMMED) {
  429                 DPRINTFN(1, ("uhidread immed\n"));
  430 
  431                 err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
  432                           sc->sc_iid, buffer, sc->sc_isize);
  433                 if (err)
  434                         return (EIO);
  435                 return (uiomove(buffer, sc->sc_isize, uio));
  436         }
  437 
  438         crit_enter();
  439         while (sc->sc_q.c_cc == 0) {
  440                 if (flag & IO_NDELAY) {
  441                         crit_exit();
  442                         return (EWOULDBLOCK);
  443                 }
  444                 sc->sc_state |= UHID_ASLP;
  445                 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
  446                 error = tsleep(&sc->sc_q, PCATCH, "uhidrea", 0);
  447                 DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
  448                 if (sc->sc_dying)
  449                         error = EIO;
  450                 if (error) {
  451                         sc->sc_state &= ~UHID_ASLP;
  452                         break;
  453                 }
  454                 if (sc->sc_state & UHID_NEEDCLEAR) {
  455                         DPRINTFN(-1,("uhidread: clearing stall\n"));
  456                         sc->sc_state &= ~UHID_NEEDCLEAR;
  457                         usbd_clear_endpoint_stall(sc->sc_intrpipe);
  458                 }
  459         }
  460         crit_exit();
  461 
  462         /* Transfer as many chunks as possible. */
  463         while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
  464                 length = szmin(sc->sc_q.c_cc, uio->uio_resid);
  465                 if (length > sizeof(buffer))
  466                         length = sizeof(buffer);
  467 
  468                 /* Remove a small chunk from the input queue. */
  469                 (void) q_to_b(&sc->sc_q, buffer, length);
  470                 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length));
  471 
  472                 /* Copy the data to the user process. */
  473                 if ((error = uiomove(buffer, length, uio)) != 0)
  474                         break;
  475         }
  476 
  477         return (error);
  478 }
  479 
  480 int
  481 uhidread(struct dev_read_args *ap)
  482 {
  483         cdev_t dev = ap->a_head.a_dev;
  484         struct uhid_softc *sc;
  485         int error;
  486 
  487         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  488 
  489         sc->sc_refcnt++;
  490         error = uhid_do_read(sc, ap->a_uio, ap->a_ioflag);
  491         if (--sc->sc_refcnt < 0)
  492                 usb_detach_wakeup(sc->sc_dev);
  493         return (error);
  494 }
  495 
  496 int
  497 uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
  498 {
  499         int error;
  500         int size;
  501         usbd_status err;
  502 
  503         DPRINTFN(1, ("uhidwrite\n"));
  504 
  505         if (sc->sc_dying)
  506                 return (EIO);
  507 
  508         size = sc->sc_osize;
  509         if (uio->uio_resid != size)
  510                 return (EINVAL);
  511         error = uiomove(sc->sc_obuf, size, uio);
  512         if (!error) {
  513                 if (sc->sc_oid)
  514                         err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
  515                                   sc->sc_obuf[0], sc->sc_obuf+1, size-1);
  516                 else
  517                         err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
  518                                   0, sc->sc_obuf, size);
  519                 if (err)
  520                         error = EIO;
  521         }
  522 
  523         return (error);
  524 }
  525 
  526 int
  527 uhidwrite(struct dev_write_args *ap)
  528 {
  529         cdev_t dev = ap->a_head.a_dev;
  530         struct uhid_softc *sc;
  531         int error;
  532 
  533         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  534 
  535         sc->sc_refcnt++;
  536         error = uhid_do_write(sc, ap->a_uio, ap->a_ioflag);
  537         if (--sc->sc_refcnt < 0)
  538                 usb_detach_wakeup(sc->sc_dev);
  539         return (error);
  540 }
  541 
  542 int
  543 uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, int flag)
  544 {
  545         struct usb_ctl_report_desc *rd;
  546         struct usb_ctl_report *re;
  547         int size, id;
  548         usbd_status err;
  549 
  550         DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
  551 
  552         if (sc->sc_dying)
  553                 return (EIO);
  554 
  555         switch (cmd) {
  556         case FIOASYNC:
  557                 if (*(int *)addr) {
  558                         if (sc->sc_async != NULL)
  559                                 return (EBUSY);
  560                         sc->sc_async = curproc;
  561                         DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", sc->sc_async));
  562                 } else
  563                         sc->sc_async = NULL;
  564                 break;
  565 
  566         /* XXX this is not the most general solution. */
  567         case TIOCSPGRP:
  568                 if (sc->sc_async == NULL)
  569                         return (EINVAL);
  570                 if (*(int *)addr != sc->sc_async->p_pgid)
  571                         return (EPERM);
  572                 break;
  573 
  574         case USB_GET_REPORT_DESC:
  575                 rd = (struct usb_ctl_report_desc *)addr;
  576                 size = min(sc->sc_repdesc_size, sizeof rd->ucrd_data);
  577                 rd->ucrd_size = size;
  578                 memcpy(rd->ucrd_data, sc->sc_repdesc, size);
  579                 break;
  580 
  581         case USB_SET_IMMED:
  582                 if (*(int *)addr) {
  583                         /* XXX should read into ibuf, but does it matter? */
  584                         err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
  585                                   sc->sc_iid, sc->sc_ibuf, sc->sc_isize);
  586                         if (err)
  587                                 return (EOPNOTSUPP);
  588 
  589                         sc->sc_state |=  UHID_IMMED;
  590                 } else
  591                         sc->sc_state &= ~UHID_IMMED;
  592                 break;
  593 
  594         case USB_GET_REPORT:
  595                 re = (struct usb_ctl_report *)addr;
  596                 switch (re->ucr_report) {
  597                 case UHID_INPUT_REPORT:
  598                         size = sc->sc_isize;
  599                         id = sc->sc_iid;
  600                         break;
  601                 case UHID_OUTPUT_REPORT:
  602                         size = sc->sc_osize;
  603                         id = sc->sc_oid;
  604                         break;
  605                 case UHID_FEATURE_REPORT:
  606                         size = sc->sc_fsize;
  607                         id = sc->sc_fid;
  608                         break;
  609                 default:
  610                         return (EINVAL);
  611                 }
  612                 err = usbd_get_report(sc->sc_iface, re->ucr_report, id, re->ucr_data,
  613                           size);
  614                 if (err)
  615                         return (EIO);
  616                 break;
  617 
  618         case USB_SET_REPORT:
  619                 re = (struct usb_ctl_report *)addr;
  620                 switch (re->ucr_report) {
  621                 case UHID_INPUT_REPORT:
  622                         size = sc->sc_isize;
  623                         id = sc->sc_iid;
  624                         break;
  625                 case UHID_OUTPUT_REPORT:
  626                         size = sc->sc_osize;
  627                         id = sc->sc_oid;
  628                         break;
  629                 case UHID_FEATURE_REPORT:
  630                         size = sc->sc_fsize;
  631                         id = sc->sc_fid;
  632                         break;
  633                 default:
  634                         return (EINVAL);
  635                 }
  636                 err = usbd_set_report(sc->sc_iface, re->ucr_report, id, re->ucr_data,
  637                           size);
  638                 if (err)
  639                         return (EIO);
  640                 break;
  641 
  642         case USB_GET_REPORT_ID:
  643                 *(int *)addr = 0;       /* XXX: we only support reportid 0? */
  644                 break;
  645 
  646         default:
  647                 return (EINVAL);
  648         }
  649         return (0);
  650 }
  651 
  652 int
  653 uhidioctl(struct dev_ioctl_args *ap)
  654 {
  655         cdev_t dev = ap->a_head.a_dev;
  656         struct uhid_softc *sc;
  657         int error;
  658 
  659         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  660 
  661         sc->sc_refcnt++;
  662         error = uhid_do_ioctl(sc, ap->a_cmd, ap->a_data, ap->a_fflag);
  663         if (--sc->sc_refcnt < 0)
  664                 usb_detach_wakeup(sc->sc_dev);
  665         return (error);
  666 }
  667 
  668 static struct filterops uhidfiltops_read =
  669         { FILTEROP_ISFD, NULL, uhidfilt_detach, uhidfilt_read };
  670 static struct filterops uhidfiltops_write =
  671         { FILTEROP_ISFD, NULL, uhidfilt_detach, uhidfilt_write };
  672 
  673 int
  674 uhidkqfilter(struct dev_kqfilter_args *ap)
  675 {
  676         cdev_t dev = ap->a_head.a_dev;
  677         struct knote *kn = ap->a_kn;
  678         struct uhid_softc *sc;
  679         struct klist *klist;
  680 
  681         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  682 
  683         if (sc->sc_dying) {
  684                 ap->a_result = 1;
  685                 return (0);
  686         }
  687 
  688         ap->a_result = 0;
  689 
  690         switch (kn->kn_filter) {
  691         case EVFILT_READ:
  692                 kn->kn_fop = &uhidfiltops_read;
  693                 kn->kn_hook = (caddr_t)sc;
  694                 break;
  695         case EVFILT_WRITE:
  696                 kn->kn_fop = &uhidfiltops_write;
  697                 kn->kn_hook = (caddr_t)sc;
  698                 break;
  699         default:
  700                 ap->a_result = EOPNOTSUPP;
  701                 return (0);
  702         }
  703 
  704         klist = &sc->sc_rkq.ki_note;
  705         knote_insert(klist, kn);
  706 
  707         return (0);
  708 }
  709 
  710 static void
  711 uhidfilt_detach(struct knote *kn)
  712 {
  713         cdev_t dev = (cdev_t)kn->kn_hook;
  714         struct uhid_softc *sc;
  715         struct klist *klist;
  716 
  717         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  718 
  719         klist = &sc->sc_rkq.ki_note;
  720         knote_remove(klist, kn);
  721 }
  722 
  723 static int
  724 uhidfilt_read(struct knote *kn, long hint)
  725 {
  726         cdev_t dev = (cdev_t)kn->kn_hook;
  727         struct uhid_softc *sc;
  728         int ready = 0;
  729 
  730         sc = devclass_get_softc(uhid_devclass, UHIDUNIT(dev));
  731 
  732         crit_enter();
  733         if (sc->sc_q.c_cc > 0)
  734                 ready = 1;
  735         crit_exit();
  736 
  737         return (ready);
  738 }
  739 
  740 static int
  741 uhidfilt_write(struct knote *kn, long hint)
  742 {
  743         return (1);
  744 }
  745 
  746 DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, NULL);
  747 

Cache object: 6381c3e44cd741ab093aee75c1366fcb


[ 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.