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/hidbus.c

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

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2019-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/bus.h>
   33 #include <sys/ck.h>
   34 #include <sys/epoch.h>
   35 #include <sys/kdb.h>
   36 #include <sys/kernel.h>
   37 #include <sys/libkern.h>
   38 #include <sys/lock.h>
   39 #include <sys/malloc.h>
   40 #include <sys/module.h>
   41 #include <sys/mutex.h>
   42 #include <sys/proc.h>
   43 #include <sys/sbuf.h>
   44 #include <sys/sx.h>
   45 #include <sys/systm.h>
   46 
   47 #define HID_DEBUG_VAR   hid_debug
   48 #include <dev/hid/hid.h>
   49 #include <dev/hid/hidbus.h>
   50 #include <dev/hid/hidquirk.h>
   51 
   52 #include "hid_if.h"
   53 
   54 #define INPUT_EPOCH     global_epoch_preempt
   55 #define HID_RSIZE_MAX   1024
   56 
   57 static hid_intr_t       hidbus_intr;
   58 
   59 static device_probe_t   hidbus_probe;
   60 static device_attach_t  hidbus_attach;
   61 static device_detach_t  hidbus_detach;
   62 
   63 struct hidbus_ivars {
   64         int32_t                         usage;
   65         uint8_t                         index;
   66         uint32_t                        flags;
   67         uintptr_t                       driver_info;    /* for internal use */
   68         struct mtx                      *mtx;           /* child intr mtx */
   69         hid_intr_t                      *intr_handler;  /* executed under mtx*/
   70         void                            *intr_ctx;
   71         unsigned int                    refcnt;         /* protected by mtx */
   72         struct epoch_context            epoch_ctx;
   73         CK_STAILQ_ENTRY(hidbus_ivars)   link;
   74 };
   75 
   76 struct hidbus_softc {
   77         device_t                        dev;
   78         struct sx                       sx;
   79         struct mtx                      mtx;
   80 
   81         bool                            nowrite;
   82 
   83         struct hid_rdesc_info           rdesc;
   84         bool                            overloaded;
   85         int                             nest;   /* Child attach nesting lvl */
   86         int                             nauto;  /* Number of autochildren */
   87 
   88         CK_STAILQ_HEAD(, hidbus_ivars)  tlcs;
   89 };
   90 
   91 static int
   92 hidbus_fill_rdesc_info(struct hid_rdesc_info *hri, const void *data,
   93     hid_size_t len)
   94 {
   95         int error = 0;
   96 
   97         hri->data = __DECONST(void *, data);
   98         hri->len = len;
   99 
  100         /*
  101          * If report descriptor is not available yet, set maximal
  102          * report sizes high enough to allow hidraw to work.
  103          */
  104         hri->isize = len == 0 ? HID_RSIZE_MAX :
  105             hid_report_size_max(data, len, hid_input, &hri->iid);
  106         hri->osize = len == 0 ? HID_RSIZE_MAX :
  107             hid_report_size_max(data, len, hid_output, &hri->oid);
  108         hri->fsize = len == 0 ? HID_RSIZE_MAX :
  109             hid_report_size_max(data, len, hid_feature, &hri->fid);
  110 
  111         if (hri->isize > HID_RSIZE_MAX) {
  112                 DPRINTF("input size is too large, %u bytes (truncating)\n",
  113                     hri->isize);
  114                 hri->isize = HID_RSIZE_MAX;
  115                 error = EOVERFLOW;
  116         }
  117         if (hri->osize > HID_RSIZE_MAX) {
  118                 DPRINTF("output size is too large, %u bytes (truncating)\n",
  119                     hri->osize);
  120                 hri->osize = HID_RSIZE_MAX;
  121                 error = EOVERFLOW;
  122         }
  123         if (hri->fsize > HID_RSIZE_MAX) {
  124                 DPRINTF("feature size is too large, %u bytes (truncating)\n",
  125                     hri->fsize);
  126                 hri->fsize = HID_RSIZE_MAX;
  127                 error = EOVERFLOW;
  128         }
  129 
  130         return (error);
  131 }
  132 
  133 int
  134 hidbus_locate(const void *desc, hid_size_t size, int32_t u, enum hid_kind k,
  135     uint8_t tlc_index, uint8_t index, struct hid_location *loc,
  136     uint32_t *flags, uint8_t *id, struct hid_absinfo *ai)
  137 {
  138         struct hid_data *d;
  139         struct hid_item h;
  140         int i;
  141 
  142         d = hid_start_parse(desc, size, 1 << k);
  143         HIDBUS_FOREACH_ITEM(d, &h, tlc_index) {
  144                 for (i = 0; i < h.nusages; i++) {
  145                         if (h.kind == k && h.usages[i] == u) {
  146                                 if (index--)
  147                                         break;
  148                                 if (loc != NULL)
  149                                         *loc = h.loc;
  150                                 if (flags != NULL)
  151                                         *flags = h.flags;
  152                                 if (id != NULL)
  153                                         *id = h.report_ID;
  154                                 if (ai != NULL && (h.flags&HIO_RELATIVE) == 0)
  155                                         *ai = (struct hid_absinfo) {
  156                                             .max = h.logical_maximum,
  157                                             .min = h.logical_minimum,
  158                                             .res = hid_item_resolution(&h),
  159                                         };
  160                                 hid_end_parse(d);
  161                                 return (1);
  162                         }
  163                 }
  164         }
  165         if (loc != NULL)
  166                 loc->size = 0;
  167         if (flags != NULL)
  168                 *flags = 0;
  169         if (id != NULL)
  170                 *id = 0;
  171         hid_end_parse(d);
  172         return (0);
  173 }
  174 
  175 bool
  176 hidbus_is_collection(const void *desc, hid_size_t size, int32_t usage,
  177     uint8_t tlc_index)
  178 {
  179         struct hid_data *d;
  180         struct hid_item h;
  181         bool ret = false;
  182 
  183         d = hid_start_parse(desc, size, 0);
  184         HIDBUS_FOREACH_ITEM(d, &h, tlc_index) {
  185                 if (h.kind == hid_collection && h.usage == usage) {
  186                         ret = true;
  187                         break;
  188                 }
  189         }
  190         hid_end_parse(d);
  191         return (ret);
  192 }
  193 
  194 static device_t
  195 hidbus_add_child(device_t dev, u_int order, const char *name, int unit)
  196 {
  197         struct hidbus_softc *sc = device_get_softc(dev);
  198         struct hidbus_ivars *tlc;
  199         device_t child;
  200 
  201         child = device_add_child_ordered(dev, order, name, unit);
  202         if (child == NULL)
  203                         return (child);
  204 
  205         tlc = malloc(sizeof(struct hidbus_ivars), M_DEVBUF, M_WAITOK | M_ZERO);
  206         tlc->mtx = &sc->mtx;
  207         device_set_ivars(child, tlc);
  208         sx_xlock(&sc->sx);
  209         CK_STAILQ_INSERT_TAIL(&sc->tlcs, tlc, link);
  210         sx_unlock(&sc->sx);
  211 
  212         return (child);
  213 }
  214 
  215 static int
  216 hidbus_enumerate_children(device_t dev, const void* data, hid_size_t len)
  217 {
  218         struct hidbus_softc *sc = device_get_softc(dev);
  219         struct hid_data *hd;
  220         struct hid_item hi;
  221         device_t child;
  222         uint8_t index = 0;
  223 
  224         if (data == NULL || len == 0)
  225                 return (ENXIO);
  226 
  227         /* Add a child for each top level collection */
  228         hd = hid_start_parse(data, len, 1 << hid_input);
  229         while (hid_get_item(hd, &hi)) {
  230                 if (hi.kind != hid_collection || hi.collevel != 1)
  231                         continue;
  232                 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
  233                 if (child == NULL) {
  234                         device_printf(dev, "Could not add HID device\n");
  235                         continue;
  236                 }
  237                 hidbus_set_index(child, index);
  238                 hidbus_set_usage(child, hi.usage);
  239                 hidbus_set_flags(child, HIDBUS_FLAG_AUTOCHILD);
  240                 index++;
  241                 DPRINTF("Add child TLC: 0x%04x:0x%04x\n",
  242                     HID_GET_USAGE_PAGE(hi.usage), HID_GET_USAGE(hi.usage));
  243         }
  244         hid_end_parse(hd);
  245 
  246         if (index == 0)
  247                 return (ENXIO);
  248 
  249         sc->nauto = index;
  250 
  251         return (0);
  252 }
  253 
  254 static int
  255 hidbus_attach_children(device_t dev)
  256 {
  257         struct hidbus_softc *sc = device_get_softc(dev);
  258         int error;
  259 
  260         HID_INTR_SETUP(device_get_parent(dev), hidbus_intr, sc, &sc->rdesc);
  261 
  262         error = hidbus_enumerate_children(dev, sc->rdesc.data, sc->rdesc.len);
  263         if (error != 0)
  264                 DPRINTF("failed to enumerate children: error %d\n", error);
  265 
  266         /*
  267          * hidbus_attach_children() can recurse through device_identify->
  268          * hid_set_report_descr() call sequence. Do not perform children
  269          * attach twice in that case.
  270          */
  271         sc->nest++;
  272         bus_generic_probe(dev);
  273         sc->nest--;
  274         if (sc->nest != 0)
  275                 return (0);
  276 
  277         if (hid_is_keyboard(sc->rdesc.data, sc->rdesc.len) != 0)
  278                 error = bus_generic_attach(dev);
  279         else
  280                 error = bus_delayed_attach_children(dev);
  281         if (error != 0)
  282                 device_printf(dev, "failed to attach child: error %d\n", error);
  283 
  284         return (error);
  285 }
  286 
  287 static int
  288 hidbus_detach_children(device_t dev)
  289 {
  290         device_t *children, bus;
  291         bool is_bus;
  292         int i, error;
  293 
  294         error = 0;
  295 
  296         is_bus = device_get_devclass(dev) == devclass_find("hidbus");
  297         bus = is_bus ? dev : device_get_parent(dev);
  298 
  299         KASSERT(device_get_devclass(bus) == devclass_find("hidbus"),
  300             ("Device is not hidbus or it's child"));
  301 
  302         if (is_bus) {
  303                 /* If hidbus is passed, delete all children. */
  304                 bus_generic_detach(bus);
  305                 device_delete_children(bus);
  306         } else {
  307                 /*
  308                  * If hidbus child is passed, delete all hidbus children
  309                  * except caller. Deleting the caller may result in deadlock.
  310                  */
  311                 error = device_get_children(bus, &children, &i);
  312                 if (error != 0)
  313                         return (error);
  314                 while (i-- > 0) {
  315                         if (children[i] == dev)
  316                                 continue;
  317                         DPRINTF("Delete child. index=%d (%s)\n",
  318                             hidbus_get_index(children[i]),
  319                             device_get_nameunit(children[i]));
  320                         error = device_delete_child(bus, children[i]);
  321                         if (error) {
  322                                 DPRINTF("Failed deleting %s\n",
  323                                     device_get_nameunit(children[i]));
  324                                 break;
  325                         }
  326                 }
  327                 free(children, M_TEMP);
  328         }
  329 
  330         HID_INTR_UNSETUP(device_get_parent(bus));
  331 
  332         return (error);
  333 }
  334 
  335 static int
  336 hidbus_probe(device_t dev)
  337 {
  338 
  339         device_set_desc(dev, "HID bus");
  340 
  341         /* Allow other subclasses to override this driver. */
  342         return (BUS_PROBE_GENERIC);
  343 }
  344 
  345 static int
  346 hidbus_attach(device_t dev)
  347 {
  348         struct hidbus_softc *sc = device_get_softc(dev);
  349         struct hid_device_info *devinfo = device_get_ivars(dev);
  350         void *d_ptr = NULL;
  351         hid_size_t d_len;
  352         int error;
  353 
  354         sc->dev = dev;
  355         CK_STAILQ_INIT(&sc->tlcs);
  356         mtx_init(&sc->mtx, "hidbus ivar lock", NULL, MTX_DEF);
  357         sx_init(&sc->sx, "hidbus ivar list lock");
  358 
  359         /*
  360          * Ignore error. It is possible for non-HID device e.g. XBox360 gamepad
  361          * to emulate HID through overloading of report descriptor.
  362          */
  363         d_len = devinfo->rdescsize;
  364         if (d_len != 0) {
  365                 d_ptr = malloc(d_len, M_DEVBUF, M_ZERO | M_WAITOK);
  366                 error = hid_get_rdesc(dev, d_ptr, d_len);
  367                 if (error != 0) {
  368                         free(d_ptr, M_DEVBUF);
  369                         d_len = 0;
  370                         d_ptr = NULL;
  371                 }
  372         }
  373 
  374         hidbus_fill_rdesc_info(&sc->rdesc, d_ptr, d_len);
  375 
  376         sc->nowrite = hid_test_quirk(devinfo, HQ_NOWRITE);
  377 
  378         error = hidbus_attach_children(dev);
  379         if (error != 0) {
  380                 hidbus_detach(dev);
  381                 return (ENXIO);
  382         }
  383 
  384         return (0);
  385 }
  386 
  387 static int
  388 hidbus_detach(device_t dev)
  389 {
  390         struct hidbus_softc *sc = device_get_softc(dev);
  391 
  392         hidbus_detach_children(dev);
  393         sx_destroy(&sc->sx);
  394         mtx_destroy(&sc->mtx);
  395         free(sc->rdesc.data, M_DEVBUF);
  396 
  397         return (0);
  398 }
  399 
  400 static void
  401 hidbus_child_detached(device_t bus, device_t child)
  402 {
  403         struct hidbus_softc *sc = device_get_softc(bus);
  404         struct hidbus_ivars *tlc = device_get_ivars(child);
  405 
  406         KASSERT(tlc->refcnt == 0, ("Child device is running"));
  407         tlc->mtx = &sc->mtx;
  408         tlc->intr_handler = NULL;
  409         tlc->flags &= ~HIDBUS_FLAG_CAN_POLL;
  410 }
  411 
  412 /*
  413  * Epoch callback indicating tlc is safe to destroy
  414  */
  415 static void
  416 hidbus_ivar_dtor(epoch_context_t ctx)
  417 {
  418         struct hidbus_ivars *tlc;
  419 
  420         tlc = __containerof(ctx, struct hidbus_ivars, epoch_ctx);
  421         free(tlc, M_DEVBUF);
  422 }
  423 
  424 static void
  425 hidbus_child_deleted(device_t bus, device_t child)
  426 {
  427         struct hidbus_softc *sc = device_get_softc(bus);
  428         struct hidbus_ivars *tlc = device_get_ivars(child);
  429 
  430         sx_xlock(&sc->sx);
  431         KASSERT(tlc->refcnt == 0, ("Child device is running"));
  432         CK_STAILQ_REMOVE(&sc->tlcs, tlc, hidbus_ivars, link);
  433         sx_unlock(&sc->sx);
  434         epoch_call(INPUT_EPOCH, hidbus_ivar_dtor, &tlc->epoch_ctx);
  435 }
  436 
  437 static int
  438 hidbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
  439 {
  440         struct hidbus_softc *sc = device_get_softc(bus);
  441         struct hidbus_ivars *tlc = device_get_ivars(child);
  442 
  443         switch (which) {
  444         case HIDBUS_IVAR_INDEX:
  445                 *result = tlc->index;
  446                 break;
  447         case HIDBUS_IVAR_USAGE:
  448                 *result = tlc->usage;
  449                 break;
  450         case HIDBUS_IVAR_FLAGS:
  451                 *result = tlc->flags;
  452                 break;
  453         case HIDBUS_IVAR_DRIVER_INFO:
  454                 *result = tlc->driver_info;
  455                 break;
  456         case HIDBUS_IVAR_LOCK:
  457                 *result = (uintptr_t)(tlc->mtx == &sc->mtx ? NULL : tlc->mtx);
  458                 break;
  459         default:
  460                 return (EINVAL);
  461         }
  462         return (0);
  463 }
  464 
  465 static int
  466 hidbus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
  467 {
  468         struct hidbus_softc *sc = device_get_softc(bus);
  469         struct hidbus_ivars *tlc = device_get_ivars(child);
  470 
  471         switch (which) {
  472         case HIDBUS_IVAR_INDEX:
  473                 tlc->index = value;
  474                 break;
  475         case HIDBUS_IVAR_USAGE:
  476                 tlc->usage = value;
  477                 break;
  478         case HIDBUS_IVAR_FLAGS:
  479                 tlc->flags = value;
  480                 if ((value & HIDBUS_FLAG_CAN_POLL) != 0)
  481                         HID_INTR_SETUP(
  482                             device_get_parent(bus), NULL, NULL, NULL);
  483                 break;
  484         case HIDBUS_IVAR_DRIVER_INFO:
  485                 tlc->driver_info = value;
  486                 break;
  487         case HIDBUS_IVAR_LOCK:
  488                 tlc->mtx = (struct mtx *)value == NULL ?
  489                     &sc->mtx : (struct mtx *)value;
  490                 break;
  491         default:
  492                 return (EINVAL);
  493         }
  494         return (0);
  495 }
  496 
  497 /* Location hint for devctl(8) */
  498 static int
  499 hidbus_child_location(device_t bus, device_t child, struct sbuf *sb)
  500 {
  501         struct hidbus_ivars *tlc = device_get_ivars(child);
  502 
  503         sbuf_printf(sb, "index=%hhu", tlc->index);
  504         return (0);
  505 }
  506 
  507 /* PnP information for devctl(8) */
  508 static int
  509 hidbus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
  510 {
  511         struct hidbus_ivars *tlc = device_get_ivars(child);
  512         struct hid_device_info *devinfo = device_get_ivars(bus);
  513 
  514         sbuf_printf(sb, "page=0x%04x usage=0x%04x bus=0x%02hx "
  515             "vendor=0x%04hx product=0x%04hx version=0x%04hx%s%s",
  516             HID_GET_USAGE_PAGE(tlc->usage), HID_GET_USAGE(tlc->usage),
  517             devinfo->idBus, devinfo->idVendor, devinfo->idProduct,
  518             devinfo->idVersion, devinfo->idPnP[0] == '\0' ? "" : " _HID=",
  519             devinfo->idPnP[0] == '\0' ? "" : devinfo->idPnP);
  520         return (0);
  521 }
  522 
  523 void
  524 hidbus_set_desc(device_t child, const char *suffix)
  525 {
  526         device_t bus = device_get_parent(child);
  527         struct hidbus_softc *sc = device_get_softc(bus);
  528         struct hid_device_info *devinfo = device_get_ivars(bus);
  529         struct hidbus_ivars *tlc = device_get_ivars(child);
  530         char buf[80];
  531 
  532         /* Do not add NULL suffix or if device name already contains it. */
  533         if (suffix != NULL && strcasestr(devinfo->name, suffix) == NULL &&
  534             (sc->nauto > 1 || (tlc->flags & HIDBUS_FLAG_AUTOCHILD) == 0)) {
  535                 snprintf(buf, sizeof(buf), "%s %s", devinfo->name, suffix);
  536                 device_set_desc_copy(child, buf);
  537         } else
  538                 device_set_desc(child, devinfo->name);
  539 }
  540 
  541 device_t
  542 hidbus_find_child(device_t bus, int32_t usage)
  543 {
  544         device_t *children, child;
  545         int ccount, i;
  546 
  547         bus_topo_assert();
  548 
  549         /* Get a list of all hidbus children */
  550         if (device_get_children(bus, &children, &ccount) != 0)
  551                 return (NULL);
  552 
  553         /* Scan through to find required TLC */
  554         for (i = 0, child = NULL; i < ccount; i++) {
  555                 if (hidbus_get_usage(children[i]) == usage) {
  556                         child = children[i];
  557                         break;
  558                 }
  559         }
  560         free(children, M_TEMP);
  561 
  562         return (child);
  563 }
  564 
  565 void
  566 hidbus_intr(void *context, void *buf, hid_size_t len)
  567 {
  568         struct hidbus_softc *sc = context;
  569         struct hidbus_ivars *tlc;
  570         struct epoch_tracker et;
  571 
  572         /*
  573          * Broadcast input report to all subscribers.
  574          * TODO: Add check for input report ID.
  575          *
  576          * Relock mutex on every TLC item as we can't hold any locks over whole
  577          * TLC list here due to LOR with open()/close() handlers.
  578          */
  579         if (!HID_IN_POLLING_MODE())
  580                 epoch_enter_preempt(INPUT_EPOCH, &et);
  581         CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
  582                 if (tlc->refcnt == 0 || tlc->intr_handler == NULL)
  583                         continue;
  584                 if (HID_IN_POLLING_MODE()) {
  585                         if ((tlc->flags & HIDBUS_FLAG_CAN_POLL) != 0)
  586                                 tlc->intr_handler(tlc->intr_ctx, buf, len);
  587                 } else {
  588                         mtx_lock(tlc->mtx);
  589                         tlc->intr_handler(tlc->intr_ctx, buf, len);
  590                         mtx_unlock(tlc->mtx);
  591                 }
  592         }
  593         if (!HID_IN_POLLING_MODE())
  594                 epoch_exit_preempt(INPUT_EPOCH, &et);
  595 }
  596 
  597 void
  598 hidbus_set_intr(device_t child, hid_intr_t *handler, void *context)
  599 {
  600         struct hidbus_ivars *tlc = device_get_ivars(child);
  601 
  602         tlc->intr_handler = handler;
  603         tlc->intr_ctx = context;
  604 }
  605 
  606 int
  607 hidbus_intr_start(device_t child)
  608 {
  609         device_t bus = device_get_parent(child);
  610         struct hidbus_softc *sc = device_get_softc(bus);
  611         struct hidbus_ivars *ivar = device_get_ivars(child);
  612         struct hidbus_ivars *tlc;
  613         bool refcnted = false;
  614         int error;
  615 
  616         if (sx_xlock_sig(&sc->sx) != 0)
  617                 return (EINTR);
  618         CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
  619                 refcnted |= (tlc->refcnt != 0);
  620                 if (tlc == ivar) {
  621                         mtx_lock(tlc->mtx);
  622                         ++tlc->refcnt;
  623                         mtx_unlock(tlc->mtx);
  624                 }
  625         }
  626         error = refcnted ? 0 : HID_INTR_START(device_get_parent(bus));
  627         sx_unlock(&sc->sx);
  628 
  629         return (error);
  630 }
  631 
  632 int
  633 hidbus_intr_stop(device_t child)
  634 {
  635         device_t bus = device_get_parent(child);
  636         struct hidbus_softc *sc = device_get_softc(bus);
  637         struct hidbus_ivars *ivar = device_get_ivars(child);
  638         struct hidbus_ivars *tlc;
  639         bool refcnted = false;
  640         int error;
  641 
  642         if (sx_xlock_sig(&sc->sx) != 0)
  643                 return (EINTR);
  644         CK_STAILQ_FOREACH(tlc, &sc->tlcs, link) {
  645                 if (tlc == ivar) {
  646                         mtx_lock(tlc->mtx);
  647                         MPASS(tlc->refcnt != 0);
  648                         --tlc->refcnt;
  649                         mtx_unlock(tlc->mtx);
  650                 }
  651                 refcnted |= (tlc->refcnt != 0);
  652         }
  653         error = refcnted ? 0 : HID_INTR_STOP(device_get_parent(bus));
  654         sx_unlock(&sc->sx);
  655 
  656         return (error);
  657 }
  658 
  659 void
  660 hidbus_intr_poll(device_t child)
  661 {
  662         device_t bus = device_get_parent(child);
  663 
  664         HID_INTR_POLL(device_get_parent(bus));
  665 }
  666 
  667 struct hid_rdesc_info *
  668 hidbus_get_rdesc_info(device_t child)
  669 {
  670         device_t bus = device_get_parent(child);
  671         struct hidbus_softc *sc = device_get_softc(bus);
  672 
  673         return (&sc->rdesc);
  674 }
  675 
  676 /*
  677  * HID interface.
  678  *
  679  * Hidbus as well as any hidbus child can be passed as first arg.
  680  */
  681 
  682 /* Read cached report descriptor */
  683 int
  684 hid_get_report_descr(device_t dev, void **data, hid_size_t *len)
  685 {
  686         device_t bus;
  687         struct hidbus_softc *sc;
  688 
  689         bus = device_get_devclass(dev) == devclass_find("hidbus") ?
  690             dev : device_get_parent(dev);
  691         sc = device_get_softc(bus);
  692 
  693         /*
  694          * Do not send request to a transport backend.
  695          * Use cached report descriptor instead of it.
  696          */
  697         if (sc->rdesc.data == NULL || sc->rdesc.len == 0)
  698                 return (ENXIO);
  699 
  700         if (data != NULL)
  701                 *data = sc->rdesc.data;
  702         if (len != NULL)
  703                 *len = sc->rdesc.len;
  704 
  705         return (0);
  706 }
  707 
  708 /*
  709  * Replace cached report descriptor with top level driver provided one.
  710  *
  711  * It deletes all hidbus children except caller and enumerates them again after
  712  * new descriptor has been registered. Currently it can not be called from
  713  * autoenumerated (by report's TLC) child device context as it results in child
  714  * duplication. To overcome this limitation hid_set_report_descr() should be
  715  * called from device_identify driver's handler with hidbus itself passed as
  716  * 'device_t dev' parameter.
  717  */
  718 int
  719 hid_set_report_descr(device_t dev, const void *data, hid_size_t len)
  720 {
  721         struct hid_rdesc_info rdesc;
  722         device_t bus;
  723         struct hidbus_softc *sc;
  724         bool is_bus;
  725         int error;
  726 
  727         bus_topo_assert();
  728 
  729         is_bus = device_get_devclass(dev) == devclass_find("hidbus");
  730         bus = is_bus ? dev : device_get_parent(dev);
  731         sc = device_get_softc(bus);
  732 
  733         /*
  734          * Do not overload already overloaded report descriptor in
  735          * device_identify handler. It causes infinite recursion loop.
  736          */
  737         if (is_bus && sc->overloaded)
  738                 return(0);
  739 
  740         DPRINTFN(5, "len=%d\n", len);
  741         DPRINTFN(5, "data = %*D\n", len, data, " ");
  742 
  743         error = hidbus_fill_rdesc_info(&rdesc, data, len);
  744         if (error != 0)
  745                 return (error);
  746 
  747         error = hidbus_detach_children(dev);
  748         if (error != 0)
  749                 return(error);
  750 
  751         /* Make private copy to handle a case of dynamicaly allocated data. */
  752         rdesc.data = malloc(len, M_DEVBUF, M_ZERO | M_WAITOK);
  753         bcopy(data, rdesc.data, len);
  754         sc->overloaded = true;
  755         free(sc->rdesc.data, M_DEVBUF);
  756         bcopy(&rdesc, &sc->rdesc, sizeof(struct hid_rdesc_info));
  757 
  758         error = hidbus_attach_children(bus);
  759 
  760         return (error);
  761 }
  762 
  763 static int
  764 hidbus_write(device_t dev, const void *data, hid_size_t len)
  765 {
  766         struct hidbus_softc *sc;
  767         uint8_t id;
  768 
  769         sc = device_get_softc(dev);
  770         /*
  771          * Output interrupt endpoint is often optional. If HID device
  772          * does not provide it, send reports via control pipe.
  773          */
  774         if (sc->nowrite) {
  775                 /* try to extract the ID byte */
  776                 id = (sc->rdesc.oid & (len > 0)) ? *(const uint8_t*)data : 0;
  777                 return (hid_set_report(dev, data, len, HID_OUTPUT_REPORT, id));
  778         }
  779 
  780         return (hid_write(dev, data, len));
  781 }
  782 
  783 /*------------------------------------------------------------------------*
  784  *      hidbus_lookup_id
  785  *
  786  * This functions takes an array of "struct hid_device_id" and tries
  787  * to match the entries with the information in "struct hid_device_info".
  788  *
  789  * Return values:
  790  * NULL: No match found.
  791  * Else: Pointer to matching entry.
  792  *------------------------------------------------------------------------*/
  793 const struct hid_device_id *
  794 hidbus_lookup_id(device_t dev, const struct hid_device_id *id, int nitems_id)
  795 {
  796         const struct hid_device_id *id_end;
  797         const struct hid_device_info *info;
  798         int32_t usage;
  799         bool is_child;
  800 
  801         if (id == NULL) {
  802                 goto done;
  803         }
  804 
  805         id_end = id + nitems_id;
  806         info = hid_get_device_info(dev);
  807         is_child = device_get_devclass(dev) != devclass_find("hidbus");
  808         if (is_child)
  809                 usage = hidbus_get_usage(dev);
  810 
  811         /*
  812          * Keep on matching array entries until we find a match or
  813          * until we reach the end of the matching array:
  814          */
  815         for (; id != id_end; id++) {
  816 
  817                 if (is_child && (id->match_flag_page) &&
  818                     (id->page != HID_GET_USAGE_PAGE(usage))) {
  819                         continue;
  820                 }
  821                 if (is_child && (id->match_flag_usage) &&
  822                     (id->usage != HID_GET_USAGE(usage))) {
  823                         continue;
  824                 }
  825                 if ((id->match_flag_bus) &&
  826                     (id->idBus != info->idBus)) {
  827                         continue;
  828                 }
  829                 if ((id->match_flag_vendor) &&
  830                     (id->idVendor != info->idVendor)) {
  831                         continue;
  832                 }
  833                 if ((id->match_flag_product) &&
  834                     (id->idProduct != info->idProduct)) {
  835                         continue;
  836                 }
  837                 if ((id->match_flag_ver_lo) &&
  838                     (id->idVersion_lo > info->idVersion)) {
  839                         continue;
  840                 }
  841                 if ((id->match_flag_ver_hi) &&
  842                     (id->idVersion_hi < info->idVersion)) {
  843                         continue;
  844                 }
  845                 if (id->match_flag_pnp &&
  846                     strncmp(id->idPnP, info->idPnP, HID_PNP_ID_SIZE) != 0) {
  847                         continue;
  848                 }
  849                 /* We found a match! */
  850                 return (id);
  851         }
  852 
  853 done:
  854         return (NULL);
  855 }
  856 
  857 /*------------------------------------------------------------------------*
  858  *      hidbus_lookup_driver_info - factored out code
  859  *
  860  * Return values:
  861  *    0: Success
  862  * Else: Failure
  863  *------------------------------------------------------------------------*/
  864 int
  865 hidbus_lookup_driver_info(device_t child, const struct hid_device_id *id,
  866     int nitems_id)
  867 {
  868 
  869         id = hidbus_lookup_id(child, id, nitems_id);
  870         if (id) {
  871                 /* copy driver info */
  872                 hidbus_set_driver_info(child, id->driver_info);
  873                 return (0);
  874         }
  875         return (ENXIO);
  876 }
  877 
  878 const struct hid_device_info *
  879 hid_get_device_info(device_t dev)
  880 {
  881         device_t bus;
  882 
  883         bus = device_get_devclass(dev) == devclass_find("hidbus") ?
  884             dev : device_get_parent(dev);
  885 
  886         return (device_get_ivars(bus));
  887 }
  888 
  889 static device_method_t hidbus_methods[] = {
  890         /* device interface */
  891         DEVMETHOD(device_probe,         hidbus_probe),
  892         DEVMETHOD(device_attach,        hidbus_attach),
  893         DEVMETHOD(device_detach,        hidbus_detach),
  894         DEVMETHOD(device_suspend,       bus_generic_suspend),
  895         DEVMETHOD(device_resume,        bus_generic_resume),
  896 
  897         /* bus interface */
  898         DEVMETHOD(bus_add_child,        hidbus_add_child),
  899         DEVMETHOD(bus_child_detached,   hidbus_child_detached),
  900         DEVMETHOD(bus_child_deleted,    hidbus_child_deleted),
  901         DEVMETHOD(bus_read_ivar,        hidbus_read_ivar),
  902         DEVMETHOD(bus_write_ivar,       hidbus_write_ivar),
  903         DEVMETHOD(bus_child_pnpinfo,    hidbus_child_pnpinfo),
  904         DEVMETHOD(bus_child_location,   hidbus_child_location),
  905 
  906         /* hid interface */
  907         DEVMETHOD(hid_get_rdesc,        hid_get_rdesc),
  908         DEVMETHOD(hid_read,             hid_read),
  909         DEVMETHOD(hid_write,            hidbus_write),
  910         DEVMETHOD(hid_get_report,       hid_get_report),
  911         DEVMETHOD(hid_set_report,       hid_set_report),
  912         DEVMETHOD(hid_set_idle,         hid_set_idle),
  913         DEVMETHOD(hid_set_protocol,     hid_set_protocol),
  914         DEVMETHOD(hid_ioctl,            hid_ioctl),
  915 
  916         DEVMETHOD_END
  917 };
  918 
  919 driver_t hidbus_driver = {
  920         "hidbus",
  921         hidbus_methods,
  922         sizeof(struct hidbus_softc),
  923 };
  924 
  925 MODULE_DEPEND(hidbus, hid, 1, 1, 1);
  926 MODULE_VERSION(hidbus, 1);
  927 DRIVER_MODULE(hidbus, iichid, hidbus_driver, 0, 0);
  928 DRIVER_MODULE(hidbus, usbhid, hidbus_driver, 0, 0);

Cache object: 483b5bca0199b469f86f2e4ee9595daa


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