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/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 /*      $NetBSD: uhid.c,v 1.60.2.2 2004/07/02 17:17:06 he Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (lennart@augustsson.net) at
    9  * Carlstedt Research & Technology.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.60.2.2 2004/07/02 17:17:06 he Exp $");
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/kernel.h>
   50 #include <sys/malloc.h>
   51 #include <sys/signalvar.h>
   52 #include <sys/device.h>
   53 #include <sys/ioctl.h>
   54 #include <sys/conf.h>
   55 #include <sys/tty.h>
   56 #include <sys/file.h>
   57 #include <sys/select.h>
   58 #include <sys/proc.h>
   59 #include <sys/vnode.h>
   60 #include <sys/poll.h>
   61 
   62 #include <dev/usb/usb.h>
   63 #include <dev/usb/usbhid.h>
   64 
   65 #include <dev/usb/usbdevs.h>
   66 #include <dev/usb/usbdi.h>
   67 #include <dev/usb/usbdi_util.h>
   68 #include <dev/usb/hid.h>
   69 #include <dev/usb/usb_quirks.h>
   70 
   71 #include <dev/usb/uhidev.h>
   72 
   73 #ifdef UHID_DEBUG
   74 #define DPRINTF(x)      if (uhiddebug) logprintf x
   75 #define DPRINTFN(n,x)   if (uhiddebug>(n)) logprintf x
   76 int     uhiddebug = 0;
   77 #else
   78 #define DPRINTF(x)
   79 #define DPRINTFN(n,x)
   80 #endif
   81 
   82 struct uhid_softc {
   83         struct uhidev sc_hdev;
   84 
   85         int sc_isize;
   86         int sc_osize;
   87         int sc_fsize;
   88 
   89         u_char *sc_obuf;
   90 
   91         struct clist sc_q;
   92         struct selinfo sc_rsel;
   93         usb_proc_ptr sc_async;  /* process that wants SIGIO */
   94         u_char sc_state;        /* driver state */
   95 #define UHID_ASLP       0x01    /* waiting for device data */
   96 #define UHID_IMMED      0x02    /* return read data immediately */
   97 
   98         int sc_refcnt;
   99         u_char sc_dying;
  100 };
  101 
  102 #define UHIDUNIT(dev)   (minor(dev))
  103 #define UHID_CHUNK      128     /* chunk size for read */
  104 #define UHID_BSIZE      1020    /* buffer size */
  105 
  106 dev_type_open(uhidopen);
  107 dev_type_close(uhidclose);
  108 dev_type_read(uhidread);
  109 dev_type_write(uhidwrite);
  110 dev_type_ioctl(uhidioctl);
  111 dev_type_poll(uhidpoll);
  112 dev_type_kqfilter(uhidkqfilter);
  113 
  114 const struct cdevsw uhid_cdevsw = {
  115         uhidopen, uhidclose, uhidread, uhidwrite, uhidioctl,
  116         nostop, notty, uhidpoll, nommap, uhidkqfilter,
  117 };
  118 
  119 Static void uhid_intr(struct uhidev *, void *, u_int len);
  120 
  121 Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int);
  122 Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int);
  123 Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int, usb_proc_ptr);
  124 
  125 USB_DECLARE_DRIVER(uhid);
  126 
  127 int
  128 uhid_match(struct device *parent, struct cfdata *match, void *aux)
  129 {
  130         struct uhidev_attach_arg *uha = aux;
  131 
  132         DPRINTF(("uhid_match: report=%d\n", uha->reportid));
  133 
  134         if (uha->matchlvl)
  135                 return (uha->matchlvl);
  136         return (UMATCH_IFACECLASS_GENERIC);
  137 }
  138 
  139 void
  140 uhid_attach(struct device *parent, struct device *self, void *aux)
  141 {
  142         struct uhid_softc *sc = (struct uhid_softc *)self;
  143         struct uhidev_attach_arg *uha = aux;
  144         int size, repid;
  145         void *desc;
  146 
  147         sc->sc_hdev.sc_intr = uhid_intr;
  148         sc->sc_hdev.sc_parent = uha->parent;
  149         sc->sc_hdev.sc_report_id = uha->reportid;
  150 
  151         uhidev_get_report_desc(uha->parent, &desc, &size);
  152         repid = uha->reportid;
  153         sc->sc_isize = hid_report_size(desc, size, hid_input,   repid);
  154         sc->sc_osize = hid_report_size(desc, size, hid_output,  repid);
  155         sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid);
  156 
  157         printf(": input=%d, output=%d, feature=%d\n",
  158                sc->sc_isize, sc->sc_osize, sc->sc_fsize);
  159 
  160         USB_ATTACH_SUCCESS_RETURN;
  161 }
  162 
  163 int
  164 uhid_activate(device_ptr_t self, enum devact act)
  165 {
  166         struct uhid_softc *sc = (struct uhid_softc *)self;
  167 
  168         switch (act) {
  169         case DVACT_ACTIVATE:
  170                 return (EOPNOTSUPP);
  171 
  172         case DVACT_DEACTIVATE:
  173                 sc->sc_dying = 1;
  174                 break;
  175         }
  176         return (0);
  177 }
  178 
  179 int
  180 uhid_detach(struct device *self, int flags)
  181 {
  182         struct uhid_softc *sc = (struct uhid_softc *)self;
  183         int s;
  184         int maj, mn;
  185 
  186         DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
  187 
  188         sc->sc_dying = 1;
  189 
  190         if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
  191                 s = splusb();
  192                 if (--sc->sc_refcnt >= 0) {
  193                         /* Wake everyone */
  194                         wakeup(&sc->sc_q);
  195                         /* Wait for processes to go away. */
  196                         usb_detach_wait(USBDEV(sc->sc_hdev.sc_dev));
  197                 }
  198                 splx(s);
  199         }
  200 
  201         /* locate the major number */
  202 #if defined(__NetBSD__)
  203         maj = cdevsw_lookup_major(&uhid_cdevsw);
  204 #elif defined(__OpenBSD__)
  205         for (maj = 0; maj < nchrdev; maj++)
  206                 if (cdevsw[maj].d_open == uhidopen)
  207                         break;
  208 #endif
  209 
  210         /* Nuke the vnodes for any open instances (calls close). */
  211         mn = self->dv_unit;
  212         vdevgone(maj, mn, mn, VCHR);
  213 
  214 #if 0
  215         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH,
  216                            sc->sc_hdev.sc_parent->sc_udev,
  217                            USBDEV(sc->sc_hdev.sc_dev));
  218 #endif
  219 
  220         return (0);
  221 }
  222 
  223 void
  224 uhid_intr(struct uhidev *addr, void *data, u_int len)
  225 {
  226         struct uhid_softc *sc = (struct uhid_softc *)addr;
  227 
  228 #ifdef UHID_DEBUG
  229         if (uhiddebug > 5) {
  230                 u_int32_t i;
  231 
  232                 DPRINTF(("uhid_intr: data ="));
  233                 for (i = 0; i < len; i++)
  234                         DPRINTF((" %02x", ((u_char *)data)[i]));
  235                 DPRINTF(("\n"));
  236         }
  237 #endif
  238 
  239         (void)b_to_q(data, len, &sc->sc_q);
  240 
  241         if (sc->sc_state & UHID_ASLP) {
  242                 sc->sc_state &= ~UHID_ASLP;
  243                 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
  244                 wakeup(&sc->sc_q);
  245         }
  246         selnotify(&sc->sc_rsel, 0);
  247         if (sc->sc_async != NULL) {
  248                 DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async));
  249                 psignal(sc->sc_async, SIGIO);
  250         }
  251 }
  252 
  253 int
  254 uhidopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
  255 {
  256         struct uhid_softc *sc;
  257         int error;
  258 
  259         USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc);
  260 
  261         DPRINTF(("uhidopen: sc=%p\n", sc));
  262 
  263         if (sc->sc_dying)
  264                 return (ENXIO);
  265 
  266         error = uhidev_open(&sc->sc_hdev);
  267         if (error)
  268                 return (error);
  269 
  270         if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
  271                 uhidev_close(&sc->sc_hdev);
  272                 return (ENOMEM);
  273         }
  274         sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
  275         sc->sc_state &= ~UHID_IMMED;
  276         sc->sc_async = NULL;
  277 
  278         return (0);
  279 }
  280 
  281 int
  282 uhidclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
  283 {
  284         struct uhid_softc *sc;
  285 
  286         USB_GET_SC(uhid, UHIDUNIT(dev), sc);
  287 
  288         DPRINTF(("uhidclose: sc=%p\n", sc));
  289 
  290         clfree(&sc->sc_q);
  291         free(sc->sc_obuf, M_USBDEV);
  292         sc->sc_async = NULL;
  293         uhidev_close(&sc->sc_hdev);
  294 
  295         return (0);
  296 }
  297 
  298 int
  299 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
  300 {
  301         int s;
  302         int error = 0;
  303         int extra;
  304         size_t length;
  305         u_char buffer[UHID_CHUNK];
  306         usbd_status err;
  307 
  308         DPRINTFN(1, ("uhidread\n"));
  309         if (sc->sc_state & UHID_IMMED) {
  310                 DPRINTFN(1, ("uhidread immed\n"));
  311                 extra = sc->sc_hdev.sc_report_id != 0;
  312                 err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
  313                                         buffer, sc->sc_isize + extra);
  314                 if (err)
  315                         return (EIO);
  316                 return (uiomove(buffer+extra, sc->sc_isize, uio));
  317         }
  318 
  319         s = splusb();
  320         while (sc->sc_q.c_cc == 0) {
  321                 if (flag & IO_NDELAY) {
  322                         splx(s);
  323                         return (EWOULDBLOCK);
  324                 }
  325                 sc->sc_state |= UHID_ASLP;
  326                 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
  327                 error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0);
  328                 DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
  329                 if (sc->sc_dying)
  330                         error = EIO;
  331                 if (error) {
  332                         sc->sc_state &= ~UHID_ASLP;
  333                         break;
  334                 }
  335         }
  336         splx(s);
  337 
  338         /* Transfer as many chunks as possible. */
  339         while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
  340                 length = min(sc->sc_q.c_cc, uio->uio_resid);
  341                 if (length > sizeof(buffer))
  342                         length = sizeof(buffer);
  343 
  344                 /* Remove a small chunk from the input queue. */
  345                 (void) q_to_b(&sc->sc_q, buffer, length);
  346                 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length));
  347 
  348                 /* Copy the data to the user process. */
  349                 if ((error = uiomove(buffer, length, uio)) != 0)
  350                         break;
  351         }
  352 
  353         return (error);
  354 }
  355 
  356 int
  357 uhidread(dev_t dev, struct uio *uio, int flag)
  358 {
  359         struct uhid_softc *sc;
  360         int error;
  361 
  362         USB_GET_SC(uhid, UHIDUNIT(dev), sc);
  363 
  364         sc->sc_refcnt++;
  365         error = uhid_do_read(sc, uio, flag);
  366         if (--sc->sc_refcnt < 0)
  367                 usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev));
  368         return (error);
  369 }
  370 
  371 int
  372 uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
  373 {
  374         int error;
  375         int size;
  376         usbd_status err;
  377 
  378         DPRINTFN(1, ("uhidwrite\n"));
  379 
  380         if (sc->sc_dying)
  381                 return (EIO);
  382 
  383         size = sc->sc_osize;
  384         error = 0;
  385         if (uio->uio_resid != size)
  386                 return (EINVAL);
  387         error = uiomove(sc->sc_obuf, size, uio);
  388         if (!error) {
  389                 err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT,
  390                                         sc->sc_obuf, size);
  391                 if (err)
  392                         error = EIO;
  393         }
  394 
  395         return (error);
  396 }
  397 
  398 int
  399 uhidwrite(dev_t dev, struct uio *uio, int flag)
  400 {
  401         struct uhid_softc *sc;
  402         int error;
  403 
  404         USB_GET_SC(uhid, UHIDUNIT(dev), sc);
  405 
  406         sc->sc_refcnt++;
  407         error = uhid_do_write(sc, uio, flag);
  408         if (--sc->sc_refcnt < 0)
  409                 usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev));
  410         return (error);
  411 }
  412 
  413 int
  414 uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
  415               int flag, usb_proc_ptr p)
  416 {
  417         struct usb_ctl_report_desc *rd;
  418         struct usb_ctl_report *re;
  419         u_char buffer[UHID_CHUNK];
  420         int size, extra;
  421         usbd_status err;
  422         void *desc;
  423 
  424         DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
  425 
  426         if (sc->sc_dying)
  427                 return (EIO);
  428 
  429         switch (cmd) {
  430         case FIONBIO:
  431                 /* All handled in the upper FS layer. */
  432                 break;
  433 
  434         case FIOASYNC:
  435                 if (*(int *)addr) {
  436                         if (sc->sc_async != NULL)
  437                                 return (EBUSY);
  438                         sc->sc_async = p;
  439                         DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", p));
  440                 } else
  441                         sc->sc_async = NULL;
  442                 break;
  443 
  444         /* XXX this is not the most general solution. */
  445         case TIOCSPGRP:
  446                 if (sc->sc_async == NULL)
  447                         return (EINVAL);
  448                 if (*(int *)addr != sc->sc_async->p_pgid)
  449                         return (EPERM);
  450                 break;
  451 
  452         case FIOSETOWN:
  453                 if (sc->sc_async == NULL)
  454                         return (EINVAL);
  455                 if (-*(int *)addr != sc->sc_async->p_pgid
  456                     && *(int *)addr != sc->sc_async->p_pid);
  457                         return (EPERM);
  458                 break;
  459 
  460         case USB_GET_REPORT_DESC:
  461                 uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
  462                 rd = (struct usb_ctl_report_desc *)addr;
  463                 size = min(size, sizeof rd->ucrd_data);
  464                 rd->ucrd_size = size;
  465                 memcpy(rd->ucrd_data, desc, size);
  466                 break;
  467 
  468         case USB_SET_IMMED:
  469                 if (*(int *)addr) {
  470                         extra = sc->sc_hdev.sc_report_id != 0;
  471                         err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
  472                                                 buffer, sc->sc_isize + extra);
  473                         if (err)
  474                                 return (EOPNOTSUPP);
  475 
  476                         sc->sc_state |=  UHID_IMMED;
  477                 } else
  478                         sc->sc_state &= ~UHID_IMMED;
  479                 break;
  480 
  481         case USB_GET_REPORT:
  482                 re = (struct usb_ctl_report *)addr;
  483                 switch (re->ucr_report) {
  484                 case UHID_INPUT_REPORT:
  485                         size = sc->sc_isize;
  486                         break;
  487                 case UHID_OUTPUT_REPORT:
  488                         size = sc->sc_osize;
  489                         break;
  490                 case UHID_FEATURE_REPORT:
  491                         size = sc->sc_fsize;
  492                         break;
  493                 default:
  494                         return (EINVAL);
  495                 }
  496                 extra = sc->sc_hdev.sc_report_id != 0;
  497                 err = uhidev_get_report(&sc->sc_hdev, re->ucr_report,
  498                     re->ucr_data, size + extra);
  499                 if (extra)
  500                         memcpy(re->ucr_data, re->ucr_data+1, size);
  501                 if (err)
  502                         return (EIO);
  503                 break;
  504 
  505         case USB_SET_REPORT:
  506                 re = (struct usb_ctl_report *)addr;
  507                 switch (re->ucr_report) {
  508                 case UHID_INPUT_REPORT:
  509                         size = sc->sc_isize;
  510                         break;
  511                 case UHID_OUTPUT_REPORT:
  512                         size = sc->sc_osize;
  513                         break;
  514                 case UHID_FEATURE_REPORT:
  515                         size = sc->sc_fsize;
  516                         break;
  517                 default:
  518                         return (EINVAL);
  519                 }
  520                 err = uhidev_set_report(&sc->sc_hdev, re->ucr_report,
  521                     re->ucr_data, size);
  522                 if (err)
  523                         return (EIO);
  524                 break;
  525 
  526         case USB_GET_REPORT_ID:
  527                 *(int *)addr = sc->sc_hdev.sc_report_id;
  528                 break;
  529 
  530         case USB_GET_DEVICEINFO:
  531                 usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev,
  532                                      (struct usb_device_info *)addr, 1);
  533                 break;
  534 
  535         case USB_GET_STRING_DESC:
  536             {
  537                 struct usb_string_desc *si = (struct usb_string_desc *)addr;
  538                 err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev,
  539                         si->usd_string_index,
  540                         si->usd_language_id, &si->usd_desc, &size);
  541                 if (err)
  542                         return (EINVAL);
  543                 break;
  544             }
  545 
  546         default:
  547                 return (EINVAL);
  548         }
  549         return (0);
  550 }
  551 
  552 int
  553 uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
  554 {
  555         struct uhid_softc *sc;
  556         int error;
  557 
  558         USB_GET_SC(uhid, UHIDUNIT(dev), sc);
  559 
  560         sc->sc_refcnt++;
  561         error = uhid_do_ioctl(sc, cmd, addr, flag, p);
  562         if (--sc->sc_refcnt < 0)
  563                 usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev));
  564         return (error);
  565 }
  566 
  567 int
  568 uhidpoll(dev_t dev, int events, usb_proc_ptr p)
  569 {
  570         struct uhid_softc *sc;
  571         int revents = 0;
  572         int s;
  573 
  574         USB_GET_SC(uhid, UHIDUNIT(dev), sc);
  575 
  576         if (sc->sc_dying)
  577                 return (EIO);
  578 
  579         s = splusb();
  580         if (events & (POLLOUT | POLLWRNORM))
  581                 revents |= events & (POLLOUT | POLLWRNORM);
  582         if (events & (POLLIN | POLLRDNORM)) {
  583                 if (sc->sc_q.c_cc > 0)
  584                         revents |= events & (POLLIN | POLLRDNORM);
  585                 else
  586                         selrecord(p, &sc->sc_rsel);
  587         }
  588 
  589         splx(s);
  590         return (revents);
  591 }
  592 
  593 static void
  594 filt_uhidrdetach(struct knote *kn)
  595 {
  596         struct uhid_softc *sc = kn->kn_hook;
  597         int s;
  598 
  599         s = splusb();
  600         SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
  601         splx(s);
  602 }
  603 
  604 static int
  605 filt_uhidread(struct knote *kn, long hint)
  606 {
  607         struct uhid_softc *sc = kn->kn_hook;
  608 
  609         kn->kn_data = sc->sc_q.c_cc;
  610         return (kn->kn_data > 0);
  611 }
  612 
  613 static const struct filterops uhidread_filtops =
  614         { 1, NULL, filt_uhidrdetach, filt_uhidread };
  615 
  616 static const struct filterops uhid_seltrue_filtops =
  617         { 1, NULL, filt_uhidrdetach, filt_seltrue };
  618 
  619 int
  620 uhidkqfilter(dev_t dev, struct knote *kn)
  621 {
  622         struct uhid_softc *sc;
  623         struct klist *klist;
  624         int s;
  625 
  626         USB_GET_SC(uhid, UHIDUNIT(dev), sc);
  627 
  628         if (sc->sc_dying)
  629                 return (EIO);
  630 
  631         switch (kn->kn_filter) {
  632         case EVFILT_READ:
  633                 klist = &sc->sc_rsel.sel_klist;
  634                 kn->kn_fop = &uhidread_filtops;
  635                 break;
  636 
  637         case EVFILT_WRITE:
  638                 klist = &sc->sc_rsel.sel_klist;
  639                 kn->kn_fop = &uhid_seltrue_filtops;
  640                 break;
  641 
  642         default:
  643                 return (1);
  644         }
  645 
  646         kn->kn_hook = sc;
  647 
  648         s = splusb();
  649         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  650         splx(s);
  651 
  652         return (0);
  653 }

Cache object: 3d4938b49591836f1a554b0c9f31f908


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