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

Cache object: c6476f49b818b3f784f0e155f1b4eef3


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