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

Cache object: 8dd2cad9e2c68be4e3080e0706d978a9


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