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/hid/hidraw.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-NetBSD
    3  *
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Lennart Augustsson (lennart@augustsson.net) at
   10  * Carlstedt Research & Technology.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 /*
   35  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD$");
   40 
   41 #include "opt_hid.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/bus.h>
   45 #include <sys/conf.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/filio.h>
   48 #include <sys/ioccom.h>
   49 #include <sys/kernel.h>
   50 #include <sys/lock.h>
   51 #include <sys/malloc.h>
   52 #include <sys/module.h>
   53 #include <sys/mutex.h>
   54 #include <sys/poll.h>
   55 #include <sys/priv.h>
   56 #include <sys/proc.h>
   57 #include <sys/selinfo.h>
   58 #include <sys/sysctl.h>
   59 #include <sys/systm.h>
   60 #include <sys/tty.h>
   61 #include <sys/uio.h>
   62 
   63 #define HID_DEBUG_VAR   hidraw_debug
   64 #include <dev/hid/hid.h>
   65 #include <dev/hid/hidbus.h>
   66 #include <dev/hid/hidraw.h>
   67 
   68 #ifdef HID_DEBUG
   69 static int hidraw_debug = 0;
   70 static SYSCTL_NODE(_hw_hid, OID_AUTO, hidraw, CTLFLAG_RW, 0,
   71     "HID raw interface");
   72 SYSCTL_INT(_hw_hid_hidraw, OID_AUTO, debug, CTLFLAG_RWTUN,
   73     &hidraw_debug, 0, "Debug level");
   74 #endif
   75 
   76 #define HIDRAW_INDEX            0xFF    /* Arbitrary high value */
   77 
   78 #define HIDRAW_LOCAL_BUFSIZE    64      /* Size of on-stack buffer. */
   79 #define HIDRAW_LOCAL_ALLOC(local_buf, size)             \
   80         (sizeof(local_buf) > (size) ? (local_buf) :     \
   81             malloc((size), M_DEVBUF, M_ZERO | M_WAITOK))
   82 #define HIDRAW_LOCAL_FREE(local_buf, buf)               \
   83         if ((local_buf) != (buf)) {                     \
   84                 free((buf), M_DEVBUF);                  \
   85         }
   86 
   87 struct hidraw_softc {
   88         device_t sc_dev;                /* base device */
   89 
   90         struct mtx sc_mtx;              /* hidbus private mutex */
   91 
   92         struct hid_rdesc_info *sc_rdesc;
   93         const struct hid_device_info *sc_hw;
   94 
   95         uint8_t *sc_q;
   96         hid_size_t *sc_qlen;
   97         int sc_head;
   98         int sc_tail;
   99         int sc_sleepcnt;
  100 
  101         struct selinfo sc_rsel;
  102         struct proc *sc_async;  /* process that wants SIGIO */
  103         struct {                        /* driver state */
  104                 bool    open:1;         /* device is open */
  105                 bool    aslp:1;         /* waiting for device data in read() */
  106                 bool    sel:1;          /* waiting for device data in poll() */
  107                 bool    quiet:1;        /* Ignore input data */
  108                 bool    immed:1;        /* return read data immediately */
  109                 bool    uhid:1;         /* driver switched in to uhid mode */
  110                 bool    lock:1;         /* input queue sleepable lock */
  111                 bool    flush:1;        /* do not wait for data in read() */
  112         } sc_state;
  113         int sc_fflags;                  /* access mode for open lifetime */
  114 
  115         struct cdev *dev;
  116 };
  117 
  118 static d_open_t         hidraw_open;
  119 static d_read_t         hidraw_read;
  120 static d_write_t        hidraw_write;
  121 static d_ioctl_t        hidraw_ioctl;
  122 static d_poll_t         hidraw_poll;
  123 static d_kqfilter_t     hidraw_kqfilter;
  124 
  125 static d_priv_dtor_t    hidraw_dtor;
  126 
  127 static struct cdevsw hidraw_cdevsw = {
  128         .d_version =    D_VERSION,
  129         .d_open =       hidraw_open,
  130         .d_read =       hidraw_read,
  131         .d_write =      hidraw_write,
  132         .d_ioctl =      hidraw_ioctl,
  133         .d_poll =       hidraw_poll,
  134         .d_kqfilter =   hidraw_kqfilter,
  135         .d_name =       "hidraw",
  136 };
  137 
  138 static hid_intr_t       hidraw_intr;
  139 
  140 static device_identify_t hidraw_identify;
  141 static device_probe_t   hidraw_probe;
  142 static device_attach_t  hidraw_attach;
  143 static device_detach_t  hidraw_detach;
  144 
  145 static int              hidraw_kqread(struct knote *, long);
  146 static void             hidraw_kqdetach(struct knote *);
  147 static void             hidraw_notify(struct hidraw_softc *);
  148 
  149 static struct filterops hidraw_filterops_read = {
  150         .f_isfd =       1,
  151         .f_detach =     hidraw_kqdetach,
  152         .f_event =      hidraw_kqread,
  153 };
  154 
  155 static void
  156 hidraw_identify(driver_t *driver, device_t parent)
  157 {
  158         device_t child;
  159 
  160         if (device_find_child(parent, "hidraw", -1) == NULL) {
  161                 child = BUS_ADD_CHILD(parent, 0, "hidraw",
  162                     device_get_unit(parent));
  163                 if (child != NULL)
  164                         hidbus_set_index(child, HIDRAW_INDEX);
  165         }
  166 }
  167 
  168 static int
  169 hidraw_probe(device_t self)
  170 {
  171 
  172         if (hidbus_get_index(self) != HIDRAW_INDEX)
  173                 return (ENXIO);
  174 
  175         hidbus_set_desc(self, "Raw HID Device");
  176 
  177         return (BUS_PROBE_GENERIC);
  178 }
  179 
  180 static int
  181 hidraw_attach(device_t self)
  182 {
  183         struct hidraw_softc *sc = device_get_softc(self);
  184         struct make_dev_args mda;
  185         int error;
  186 
  187         sc->sc_dev = self;
  188         sc->sc_rdesc = hidbus_get_rdesc_info(self);
  189         sc->sc_hw = hid_get_device_info(self);
  190 
  191         /* Hidraw mode does not require report descriptor to work */
  192         if (sc->sc_rdesc->data == NULL || sc->sc_rdesc->len == 0)
  193                 device_printf(self, "no report descriptor\n");
  194 
  195         mtx_init(&sc->sc_mtx, "hidraw lock", NULL, MTX_DEF);
  196         knlist_init_mtx(&sc->sc_rsel.si_note, &sc->sc_mtx);
  197 
  198         make_dev_args_init(&mda);
  199         mda.mda_flags = MAKEDEV_WAITOK;
  200         mda.mda_devsw = &hidraw_cdevsw;
  201         mda.mda_uid = UID_ROOT;
  202         mda.mda_gid = GID_OPERATOR;
  203         mda.mda_mode = 0600;
  204         mda.mda_si_drv1 = sc;
  205 
  206         error = make_dev_s(&mda, &sc->dev, "hidraw%d", device_get_unit(self));
  207         if (error) {
  208                 device_printf(self, "Can not create character device\n");
  209                 hidraw_detach(self);
  210                 return (error);
  211         }
  212 #ifdef HIDRAW_MAKE_UHID_ALIAS
  213         (void)make_dev_alias(sc->dev, "uhid%d", device_get_unit(self));
  214 #endif
  215 
  216         hidbus_set_lock(self, &sc->sc_mtx);
  217         hidbus_set_intr(self, hidraw_intr, sc);
  218 
  219         return (0);
  220 }
  221 
  222 static int
  223 hidraw_detach(device_t self)
  224 {
  225         struct hidraw_softc *sc = device_get_softc(self);
  226 
  227         DPRINTF("sc=%p\n", sc);
  228 
  229         if (sc->dev != NULL) {
  230                 mtx_lock(&sc->sc_mtx);
  231                 sc->dev->si_drv1 = NULL;
  232                 /* Wake everyone */
  233                 hidraw_notify(sc);
  234                 mtx_unlock(&sc->sc_mtx);
  235                 destroy_dev(sc->dev);
  236         }
  237 
  238         knlist_clear(&sc->sc_rsel.si_note, 0);
  239         knlist_destroy(&sc->sc_rsel.si_note);
  240         seldrain(&sc->sc_rsel);
  241         mtx_destroy(&sc->sc_mtx);
  242 
  243         return (0);
  244 }
  245 
  246 void
  247 hidraw_intr(void *context, void *buf, hid_size_t len)
  248 {
  249         struct hidraw_softc *sc = context;
  250         int next;
  251 
  252         DPRINTFN(5, "len=%d\n", len);
  253         DPRINTFN(5, "data = %*D\n", len, buf, " ");
  254 
  255         next = (sc->sc_tail + 1) % HIDRAW_BUFFER_SIZE;
  256         if (sc->sc_state.quiet || next == sc->sc_head)
  257                 return;
  258 
  259         bcopy(buf, sc->sc_q + sc->sc_tail * sc->sc_rdesc->rdsize, len);
  260 
  261         /* Make sure we don't process old data */
  262         if (len < sc->sc_rdesc->rdsize)
  263                 bzero(sc->sc_q + sc->sc_tail * sc->sc_rdesc->rdsize + len,
  264                     sc->sc_rdesc->isize - len);
  265 
  266         sc->sc_qlen[sc->sc_tail] = len;
  267         sc->sc_tail = next;
  268 
  269         hidraw_notify(sc);
  270 }
  271 
  272 static inline int
  273 hidraw_lock_queue(struct hidraw_softc *sc, bool flush)
  274 {
  275         int error = 0;
  276 
  277         mtx_assert(&sc->sc_mtx, MA_OWNED);
  278 
  279         if (flush)
  280                 sc->sc_state.flush = true;
  281         ++sc->sc_sleepcnt;
  282         while (sc->sc_state.lock && error == 0) {
  283                 /* Flush is requested. Wakeup all readers and forbid sleeps */
  284                 if (flush && sc->sc_state.aslp) {
  285                         sc->sc_state.aslp = false;
  286                         DPRINTFN(5, "waking %p\n", &sc->sc_q);
  287                         wakeup(&sc->sc_q);
  288                 }
  289                 error = mtx_sleep(&sc->sc_sleepcnt, &sc->sc_mtx,
  290                     PZERO | PCATCH, "hidrawio", 0);
  291         }
  292         --sc->sc_sleepcnt;
  293         if (flush)
  294                 sc->sc_state.flush = false;
  295         if (error == 0)
  296                 sc->sc_state.lock = true;
  297 
  298         return (error);
  299 }
  300 
  301 static inline void
  302 hidraw_unlock_queue(struct hidraw_softc *sc)
  303 {
  304 
  305         mtx_assert(&sc->sc_mtx, MA_OWNED);
  306         KASSERT(sc->sc_state.lock, ("input buffer is not locked"));
  307 
  308         if (sc->sc_sleepcnt != 0)
  309                 wakeup_one(&sc->sc_sleepcnt);
  310         sc->sc_state.lock = false;
  311 }
  312 
  313 static int
  314 hidraw_open(struct cdev *dev, int flag, int mode, struct thread *td)
  315 {
  316         struct hidraw_softc *sc;
  317         int error;
  318 
  319         sc = dev->si_drv1;
  320         if (sc == NULL)
  321                 return (ENXIO);
  322 
  323         DPRINTF("sc=%p\n", sc);
  324 
  325         mtx_lock(&sc->sc_mtx);
  326         if (sc->sc_state.open) {
  327                 mtx_unlock(&sc->sc_mtx);
  328                 return (EBUSY);
  329         }
  330         sc->sc_state.open = true;
  331         mtx_unlock(&sc->sc_mtx);
  332 
  333         error = devfs_set_cdevpriv(sc, hidraw_dtor);
  334         if (error != 0) {
  335                 mtx_lock(&sc->sc_mtx);
  336                 sc->sc_state.open = false;
  337                 mtx_unlock(&sc->sc_mtx);
  338                 return (error);
  339         }
  340 
  341         sc->sc_q = malloc(sc->sc_rdesc->rdsize * HIDRAW_BUFFER_SIZE, M_DEVBUF,
  342             M_ZERO | M_WAITOK);
  343         sc->sc_qlen = malloc(sizeof(hid_size_t) * HIDRAW_BUFFER_SIZE, M_DEVBUF,
  344             M_ZERO | M_WAITOK);
  345 
  346         /* Set up interrupt pipe. */
  347         sc->sc_state.immed = false;
  348         sc->sc_async = 0;
  349         sc->sc_state.uhid = false;      /* hidraw mode is default */
  350         sc->sc_state.quiet = false;
  351         sc->sc_head = sc->sc_tail = 0;
  352         sc->sc_fflags = flag;
  353 
  354         hidbus_intr_start(sc->sc_dev);
  355 
  356         return (0);
  357 }
  358 
  359 static void
  360 hidraw_dtor(void *data)
  361 {
  362         struct hidraw_softc *sc = data;
  363 
  364         DPRINTF("sc=%p\n", sc);
  365 
  366         /* Disable interrupts. */
  367         hidbus_intr_stop(sc->sc_dev);
  368 
  369         sc->sc_tail = sc->sc_head = 0;
  370         sc->sc_async = 0;
  371         free(sc->sc_q, M_DEVBUF);
  372         free(sc->sc_qlen, M_DEVBUF);
  373         sc->sc_q = NULL;
  374 
  375         mtx_lock(&sc->sc_mtx);
  376         sc->sc_state.open = false;
  377         mtx_unlock(&sc->sc_mtx);
  378 }
  379 
  380 static int
  381 hidraw_read(struct cdev *dev, struct uio *uio, int flag)
  382 {
  383         struct hidraw_softc *sc;
  384         size_t length;
  385         int error;
  386 
  387         DPRINTFN(1, "\n");
  388 
  389         sc = dev->si_drv1;
  390         if (sc == NULL)
  391                 return (EIO);
  392 
  393         mtx_lock(&sc->sc_mtx);
  394         error = dev->si_drv1 == NULL ? EIO : hidraw_lock_queue(sc, false);
  395         if (error != 0) {
  396                 mtx_unlock(&sc->sc_mtx);
  397                 return (error);
  398         }
  399 
  400         if (sc->sc_state.immed) {
  401                 mtx_unlock(&sc->sc_mtx);
  402                 DPRINTFN(1, "immed\n");
  403 
  404                 error = hid_get_report(sc->sc_dev, sc->sc_q,
  405                     sc->sc_rdesc->isize, NULL, HID_INPUT_REPORT,
  406                     sc->sc_rdesc->iid);
  407                 if (error == 0)
  408                         error = uiomove(sc->sc_q, sc->sc_rdesc->isize, uio);
  409                 mtx_lock(&sc->sc_mtx);
  410                 goto exit;
  411         }
  412 
  413         while (sc->sc_tail == sc->sc_head && !sc->sc_state.flush) {
  414                 if (flag & O_NONBLOCK) {
  415                         error = EWOULDBLOCK;
  416                         goto exit;
  417                 }
  418                 sc->sc_state.aslp = true;
  419                 DPRINTFN(5, "sleep on %p\n", &sc->sc_q);
  420                 error = mtx_sleep(&sc->sc_q, &sc->sc_mtx, PZERO | PCATCH,
  421                     "hidrawrd", 0);
  422                 DPRINTFN(5, "woke, error=%d\n", error);
  423                 if (dev->si_drv1 == NULL)
  424                         error = EIO;
  425                 if (error) {
  426                         sc->sc_state.aslp = false;
  427                         goto exit;
  428                 }
  429         }
  430 
  431         while (sc->sc_tail != sc->sc_head && uio->uio_resid > 0) {
  432                 length = min(uio->uio_resid, sc->sc_state.uhid ?
  433                     sc->sc_rdesc->isize : sc->sc_qlen[sc->sc_head]);
  434                 mtx_unlock(&sc->sc_mtx);
  435 
  436                 /* Copy the data to the user process. */
  437                 DPRINTFN(5, "got %lu chars\n", (u_long)length);
  438                 error = uiomove(sc->sc_q + sc->sc_head * sc->sc_rdesc->rdsize,
  439                     length, uio);
  440 
  441                 mtx_lock(&sc->sc_mtx);
  442                 if (error != 0)
  443                         goto exit;
  444                 /* Remove a small chunk from the input queue. */
  445                 sc->sc_head = (sc->sc_head + 1) % HIDRAW_BUFFER_SIZE;
  446                 /*
  447                  * In uhid mode transfer as many chunks as possible. Hidraw
  448                  * packets are transferred one by one due to different length.
  449                  */
  450                 if (!sc->sc_state.uhid)
  451                         goto exit;
  452         }
  453 exit:
  454         hidraw_unlock_queue(sc);
  455         mtx_unlock(&sc->sc_mtx);
  456 
  457         return (error);
  458 }
  459 
  460 static int
  461 hidraw_write(struct cdev *dev, struct uio *uio, int flag)
  462 {
  463         uint8_t local_buf[HIDRAW_LOCAL_BUFSIZE], *buf;
  464         struct hidraw_softc *sc;
  465         int error;
  466         int size;
  467         size_t buf_offset;
  468         uint8_t id = 0;
  469 
  470         DPRINTFN(1, "\n");
  471 
  472         sc = dev->si_drv1;
  473         if (sc == NULL)
  474                 return (EIO);
  475 
  476         if (sc->sc_rdesc->osize == 0)
  477                 return (EOPNOTSUPP);
  478 
  479         buf_offset = 0;
  480         if (sc->sc_state.uhid) {
  481                 size = sc->sc_rdesc->osize;
  482                 if (uio->uio_resid != size)
  483                         return (EINVAL);
  484         } else {
  485                 size = uio->uio_resid;
  486                 if (size < 2)
  487                         return (EINVAL);
  488                 /* Strip leading 0 if the device doesnt use numbered reports */
  489                 error = uiomove(&id, 1, uio);
  490                 if (error)
  491                         return (error);
  492                 if (id != 0)
  493                         buf_offset++;
  494                 else
  495                         size--;
  496                 /* Check if underlying driver could process this request */
  497                 if (size > sc->sc_rdesc->wrsize)
  498                         return (ENOBUFS);
  499         }
  500         buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
  501         buf[0] = id;
  502         error = uiomove(buf + buf_offset, uio->uio_resid, uio);
  503         if (error == 0)
  504                 error = hid_write(sc->sc_dev, buf, size);
  505         HIDRAW_LOCAL_FREE(local_buf, buf);
  506 
  507         return (error);
  508 }
  509 
  510 static int
  511 hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
  512     struct thread *td)
  513 {
  514         uint8_t local_buf[HIDRAW_LOCAL_BUFSIZE];
  515         void *buf;
  516         struct hidraw_softc *sc;
  517         struct hidraw_gen_descriptor *hgd;
  518         struct hidraw_report_descriptor *hrd;
  519         struct hidraw_devinfo *hdi;
  520         uint32_t size;
  521         int id, len;
  522         int error = 0;
  523 
  524         DPRINTFN(2, "cmd=%lx\n", cmd);
  525 
  526         sc = dev->si_drv1;
  527         if (sc == NULL)
  528                 return (EIO);
  529 
  530         /* fixed-length ioctls handling */
  531         switch (cmd) {
  532         case FIONBIO:
  533                 /* All handled in the upper FS layer. */
  534                 return (0);
  535 
  536         case FIOASYNC:
  537                 mtx_lock(&sc->sc_mtx);
  538                 if (*(int *)addr) {
  539                         if (sc->sc_async == NULL) {
  540                                 sc->sc_async = td->td_proc;
  541                                 DPRINTF("FIOASYNC %p\n", sc->sc_async);
  542                         } else
  543                                 error = EBUSY;
  544                 } else
  545                         sc->sc_async = NULL;
  546                 mtx_unlock(&sc->sc_mtx);
  547                 return (error);
  548 
  549         /* XXX this is not the most general solution. */
  550         case TIOCSPGRP:
  551                 mtx_lock(&sc->sc_mtx);
  552                 if (sc->sc_async == NULL)
  553                         error = EINVAL;
  554                 else if (*(int *)addr != sc->sc_async->p_pgid)
  555                         error = EPERM;
  556                 mtx_unlock(&sc->sc_mtx);
  557                 return (error);
  558 
  559         case HIDRAW_GET_REPORT_DESC:
  560                 if (sc->sc_rdesc->data == NULL || sc->sc_rdesc->len == 0)
  561                         return (EOPNOTSUPP);
  562                 mtx_lock(&sc->sc_mtx);
  563                 sc->sc_state.uhid = true;
  564                 mtx_unlock(&sc->sc_mtx);
  565                 hgd = (struct hidraw_gen_descriptor *)addr;
  566                 if (sc->sc_rdesc->len > hgd->hgd_maxlen) {
  567                         size = hgd->hgd_maxlen;
  568                 } else {
  569                         size = sc->sc_rdesc->len;
  570                 }
  571                 hgd->hgd_actlen = size;
  572                 if (hgd->hgd_data == NULL)
  573                         return (0);             /* descriptor length only */
  574                 return (copyout(sc->sc_rdesc->data, hgd->hgd_data, size));
  575 
  576 
  577         case HIDRAW_SET_REPORT_DESC:
  578                 if (!(sc->sc_fflags & FWRITE))
  579                         return (EPERM);
  580 
  581                 /* check privileges */
  582                 error = priv_check(curthread, PRIV_DRIVER);
  583                 if (error)
  584                         return (error);
  585 
  586                 /* Stop interrupts and clear input report buffer */
  587                 mtx_lock(&sc->sc_mtx);
  588                 sc->sc_tail = sc->sc_head = 0;
  589                 error = hidraw_lock_queue(sc, true);
  590                 if (error == 0)
  591                         sc->sc_state.quiet = true;
  592                 mtx_unlock(&sc->sc_mtx);
  593                 if (error != 0)
  594                         return(error);
  595 
  596                 hgd = (struct hidraw_gen_descriptor *)addr;
  597                 buf = HIDRAW_LOCAL_ALLOC(local_buf, hgd->hgd_maxlen);
  598                 copyin(hgd->hgd_data, buf, hgd->hgd_maxlen);
  599                 /* Lock newbus around set_report_descr call */
  600                 mtx_lock(&Giant);
  601                 error = hid_set_report_descr(sc->sc_dev, buf, hgd->hgd_maxlen);
  602                 mtx_unlock(&Giant);
  603                 HIDRAW_LOCAL_FREE(local_buf, buf);
  604 
  605                 /* Realloc hidraw input queue */
  606                 if (error == 0)
  607                         sc->sc_q = realloc(sc->sc_q,
  608                             sc->sc_rdesc->rdsize * HIDRAW_BUFFER_SIZE,
  609                             M_DEVBUF, M_ZERO | M_WAITOK);
  610 
  611                 /* Start interrupts again */
  612                 mtx_lock(&sc->sc_mtx);
  613                 sc->sc_state.quiet = false;
  614                 hidraw_unlock_queue(sc);
  615                 mtx_unlock(&sc->sc_mtx);
  616                 return (error);
  617         case HIDRAW_SET_IMMED:
  618                 if (!(sc->sc_fflags & FREAD))
  619                         return (EPERM);
  620                 if (*(int *)addr) {
  621                         /* XXX should read into ibuf, but does it matter? */
  622                         size = sc->sc_rdesc->isize;
  623                         buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
  624                         error = hid_get_report(sc->sc_dev, buf, size, NULL,
  625                             HID_INPUT_REPORT, sc->sc_rdesc->iid);
  626                         HIDRAW_LOCAL_FREE(local_buf, buf);
  627                         if (error)
  628                                 return (EOPNOTSUPP);
  629 
  630                         mtx_lock(&sc->sc_mtx);
  631                         sc->sc_state.immed = true;
  632                         mtx_unlock(&sc->sc_mtx);
  633                 } else {
  634                         mtx_lock(&sc->sc_mtx);
  635                         sc->sc_state.immed = false;
  636                         mtx_unlock(&sc->sc_mtx);
  637                 }
  638                 return (0);
  639 
  640         case HIDRAW_GET_REPORT:
  641                 if (!(sc->sc_fflags & FREAD))
  642                         return (EPERM);
  643                 hgd = (struct hidraw_gen_descriptor *)addr;
  644                 switch (hgd->hgd_report_type) {
  645                 case HID_INPUT_REPORT:
  646                         size = sc->sc_rdesc->isize;
  647                         id = sc->sc_rdesc->iid;
  648                         break;
  649                 case HID_OUTPUT_REPORT:
  650                         size = sc->sc_rdesc->osize;
  651                         id = sc->sc_rdesc->oid;
  652                         break;
  653                 case HID_FEATURE_REPORT:
  654                         size = sc->sc_rdesc->fsize;
  655                         id = sc->sc_rdesc->fid;
  656                         break;
  657                 default:
  658                         return (EINVAL);
  659                 }
  660                 if (id != 0)
  661                         copyin(hgd->hgd_data, &id, 1);
  662                 size = MIN(hgd->hgd_maxlen, size);
  663                 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
  664                 error = hid_get_report(sc->sc_dev, buf, size, NULL,
  665                     hgd->hgd_report_type, id);
  666                 if (!error)
  667                         error = copyout(buf, hgd->hgd_data, size);
  668                 HIDRAW_LOCAL_FREE(local_buf, buf);
  669                 return (error);
  670 
  671         case HIDRAW_SET_REPORT:
  672                 if (!(sc->sc_fflags & FWRITE))
  673                         return (EPERM);
  674                 hgd = (struct hidraw_gen_descriptor *)addr;
  675                 switch (hgd->hgd_report_type) {
  676                 case HID_INPUT_REPORT:
  677                         size = sc->sc_rdesc->isize;
  678                         id = sc->sc_rdesc->iid;
  679                         break;
  680                 case HID_OUTPUT_REPORT:
  681                         size = sc->sc_rdesc->osize;
  682                         id = sc->sc_rdesc->oid;
  683                         break;
  684                 case HID_FEATURE_REPORT:
  685                         size = sc->sc_rdesc->fsize;
  686                         id = sc->sc_rdesc->fid;
  687                         break;
  688                 default:
  689                         return (EINVAL);
  690                 }
  691                 size = MIN(hgd->hgd_maxlen, size);
  692                 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
  693                 copyin(hgd->hgd_data, buf, size);
  694                 if (id != 0)
  695                         id = *(uint8_t *)buf;
  696                 error = hid_set_report(sc->sc_dev, buf, size,
  697                     hgd->hgd_report_type, id);
  698                 HIDRAW_LOCAL_FREE(local_buf, buf);
  699                 return (error);
  700 
  701         case HIDRAW_GET_REPORT_ID:
  702                 *(int *)addr = 0;       /* XXX: we only support reportid 0? */
  703                 return (0);
  704 
  705         case HIDIOCGRDESCSIZE:
  706                 *(int *)addr = sc->sc_hw->rdescsize;
  707                 return (0);
  708 
  709         case HIDIOCGRDESC:
  710                 hrd = *(struct hidraw_report_descriptor **)addr;
  711                 error = copyin(&hrd->size, &size, sizeof(uint32_t));
  712                 if (error)
  713                         return (error);
  714                 /*
  715                  * HID_MAX_DESCRIPTOR_SIZE-1 is a limit of report descriptor
  716                  * size in current Linux implementation.
  717                  */
  718                 if (size >= HID_MAX_DESCRIPTOR_SIZE)
  719                         return (EINVAL);
  720                 buf = HIDRAW_LOCAL_ALLOC(local_buf, size);
  721                 error = hid_get_rdesc(sc->sc_dev, buf, size);
  722                 if (error == 0) {
  723                         size = MIN(size, sc->sc_rdesc->len);
  724                         error = copyout(buf, hrd->value, size);
  725                 }
  726                 HIDRAW_LOCAL_FREE(local_buf, buf);
  727                 return (error);
  728 
  729         case HIDIOCGRAWINFO:
  730                 hdi = (struct hidraw_devinfo *)addr;
  731                 hdi->bustype = sc->sc_hw->idBus;
  732                 hdi->vendor = sc->sc_hw->idVendor;
  733                 hdi->product = sc->sc_hw->idProduct;
  734                 return (0);
  735         }
  736 
  737         /* variable-length ioctls handling */
  738         len = IOCPARM_LEN(cmd);
  739         switch (IOCBASECMD(cmd)) {
  740         case HIDIOCGRAWNAME(0):
  741                 strlcpy(addr, sc->sc_hw->name, len);
  742                 return (0);
  743 
  744         case HIDIOCGRAWPHYS(0):
  745                 strlcpy(addr, device_get_nameunit(sc->sc_dev), len);
  746                 return (0);
  747 
  748         case HIDIOCSFEATURE(0):
  749                 if (!(sc->sc_fflags & FWRITE))
  750                         return (EPERM);
  751                 if (len < 2)
  752                         return (EINVAL);
  753                 id = *(uint8_t *)addr;
  754                 if (id == 0) {
  755                         addr = (uint8_t *)addr + 1;
  756                         len--;
  757                 }
  758                 return (hid_set_report(sc->sc_dev, addr, len,
  759                     HID_FEATURE_REPORT, id));
  760 
  761         case HIDIOCGFEATURE(0):
  762                 if (!(sc->sc_fflags & FREAD))
  763                         return (EPERM);
  764                 if (len < 2)
  765                         return (EINVAL);
  766                 id = *(uint8_t *)addr;
  767                 if (id == 0) {
  768                         addr = (uint8_t *)addr + 1;
  769                         len--;
  770                 }
  771                 return (hid_get_report(sc->sc_dev, addr, len, NULL,
  772                     HID_FEATURE_REPORT, id));
  773 
  774         case HIDIOCGRAWUNIQ(0):
  775                 strlcpy(addr, sc->sc_hw->serial, len);
  776                 return (0);
  777         }
  778 
  779         return (EINVAL);
  780 }
  781 
  782 static int
  783 hidraw_poll(struct cdev *dev, int events, struct thread *td)
  784 {
  785         struct hidraw_softc *sc;
  786         int revents = 0;
  787 
  788         sc = dev->si_drv1;
  789         if (sc == NULL)
  790                 return (POLLHUP);
  791 
  792         if (events & (POLLOUT | POLLWRNORM) && (sc->sc_fflags & FWRITE))
  793                 revents |= events & (POLLOUT | POLLWRNORM);
  794         if (events & (POLLIN | POLLRDNORM) && (sc->sc_fflags & FREAD)) {
  795                 mtx_lock(&sc->sc_mtx);
  796                 if (sc->sc_head != sc->sc_tail)
  797                         revents |= events & (POLLIN | POLLRDNORM);
  798                 else {
  799                         sc->sc_state.sel = true;
  800                         selrecord(td, &sc->sc_rsel);
  801                 }
  802                 mtx_unlock(&sc->sc_mtx);
  803         }
  804 
  805         return (revents);
  806 }
  807 
  808 static int
  809 hidraw_kqfilter(struct cdev *dev, struct knote *kn)
  810 {
  811         struct hidraw_softc *sc;
  812 
  813         sc = dev->si_drv1;
  814         if (sc == NULL)
  815                 return (ENXIO);
  816 
  817         switch(kn->kn_filter) {
  818         case EVFILT_READ:
  819                 if (sc->sc_fflags & FREAD) {
  820                         kn->kn_fop = &hidraw_filterops_read;
  821                         break;
  822                 }
  823                 /* FALLTHROUGH */
  824         default:
  825                 return(EINVAL);
  826         }
  827         kn->kn_hook = sc;
  828 
  829         knlist_add(&sc->sc_rsel.si_note, kn, 0);
  830         return (0);
  831 }
  832 
  833 static int
  834 hidraw_kqread(struct knote *kn, long hint)
  835 {
  836         struct hidraw_softc *sc;
  837         int ret;
  838 
  839         sc = kn->kn_hook;
  840 
  841         mtx_assert(&sc->sc_mtx, MA_OWNED);
  842 
  843         if (sc->dev->si_drv1 == NULL) {
  844                 kn->kn_flags |= EV_EOF;
  845                 ret = 1;
  846         } else
  847                 ret = (sc->sc_head != sc->sc_tail) ? 1 : 0;
  848 
  849         return (ret);
  850 }
  851 
  852 static void
  853 hidraw_kqdetach(struct knote *kn)
  854 {
  855         struct hidraw_softc *sc;
  856 
  857         sc = kn->kn_hook;
  858         knlist_remove(&sc->sc_rsel.si_note, kn, 0);
  859 }
  860 
  861 static void
  862 hidraw_notify(struct hidraw_softc *sc)
  863 {
  864 
  865         mtx_assert(&sc->sc_mtx, MA_OWNED);
  866 
  867         if (sc->sc_state.aslp) {
  868                 sc->sc_state.aslp = false;
  869                 DPRINTFN(5, "waking %p\n", &sc->sc_q);
  870                 wakeup(&sc->sc_q);
  871         }
  872         if (sc->sc_state.sel) {
  873                 sc->sc_state.sel = false;
  874                 selwakeuppri(&sc->sc_rsel, PZERO);
  875         }
  876         if (sc->sc_async != NULL) {
  877                 DPRINTFN(3, "sending SIGIO %p\n", sc->sc_async);
  878                 PROC_LOCK(sc->sc_async);
  879                 kern_psignal(sc->sc_async, SIGIO);
  880                 PROC_UNLOCK(sc->sc_async);
  881         }
  882         KNOTE_LOCKED(&sc->sc_rsel.si_note, 0);
  883 }
  884 
  885 static device_method_t hidraw_methods[] = {
  886         /* Device interface */
  887         DEVMETHOD(device_identify,      hidraw_identify),
  888         DEVMETHOD(device_probe,         hidraw_probe),
  889         DEVMETHOD(device_attach,        hidraw_attach),
  890         DEVMETHOD(device_detach,        hidraw_detach),
  891 
  892         DEVMETHOD_END
  893 };
  894 
  895 static driver_t hidraw_driver = {
  896         "hidraw",
  897         hidraw_methods,
  898         sizeof(struct hidraw_softc)
  899 };
  900 
  901 #ifndef HIDRAW_MAKE_UHID_ALIAS
  902 devclass_t hidraw_devclass;
  903 #endif
  904 
  905 DRIVER_MODULE(hidraw, hidbus, hidraw_driver, hidraw_devclass, NULL, 0);
  906 MODULE_DEPEND(hidraw, hidbus, 1, 1, 1);
  907 MODULE_DEPEND(hidraw, hid, 1, 1, 1);
  908 MODULE_DEPEND(hidraw, usb, 1, 1, 1);
  909 MODULE_VERSION(hidraw, 1);

Cache object: a0e577f7c28c0bb3664b1c6ef2e59160


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