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/hid.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 /*      $OpenBSD: hid.c,v 1.5 2022/05/20 05:03:45 anton Exp $ */
    2 /*      $NetBSD: hid.c,v 1.23 2002/07/11 21:14:25 augustss Exp $        */
    3 /*      $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
    4 
    5 /*
    6  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    7  * All rights reserved.
    8  *
    9  * This code is derived from software contributed to The NetBSD Foundation
   10  * by Lennart Augustsson (lennart@augustsson.net) at
   11  * Carlstedt Research & Technology.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/malloc.h>
   38 
   39 #include <dev/hid/hid.h>
   40 
   41 #ifdef USBHID_DEBUG
   42 #define DPRINTF(x...)    do { printf(x); } while (0)
   43 #else
   44 #define DPRINTF(x...)
   45 #endif
   46 
   47 #define MAXUSAGE 64
   48 #define MAXPUSH 4
   49 #define MAXID 16
   50 
   51 struct hid_pos_data {
   52         int32_t rid;
   53         uint32_t pos;
   54 };
   55 
   56 struct hid_data {
   57         const uint8_t *start;
   58         const uint8_t *end;
   59         const uint8_t *p;
   60         struct hid_item cur[MAXPUSH];
   61         struct hid_pos_data last_pos[MAXID];
   62         int32_t usages_min[MAXUSAGE];
   63         int32_t usages_max[MAXUSAGE];
   64         int32_t usage_last;     /* last seen usage */
   65         uint32_t loc_size;      /* last seen size */
   66         uint32_t loc_count;     /* last seen count */
   67         enum hid_kind kind;
   68         uint8_t pushlevel;      /* current pushlevel */
   69         uint8_t ncount;         /* end usage item count */
   70         uint8_t icount;         /* current usage item count */
   71         uint8_t nusage;         /* end "usages_min/max" index */
   72         uint8_t iusage;         /* current "usages_min/max" index */
   73         uint8_t ousage;         /* current "usages_min/max" offset */
   74         uint8_t susage;         /* usage set flags */
   75 };
   76 
   77 static void
   78 hid_clear_local(struct hid_item *c)
   79 {
   80         c->loc.count = 0;
   81         c->loc.size = 0;
   82         c->usage = 0;
   83         c->usage_minimum = 0;
   84         c->usage_maximum = 0;
   85         c->designator_index = 0;
   86         c->designator_minimum = 0;
   87         c->designator_maximum = 0;
   88         c->string_index = 0;
   89         c->string_minimum = 0;
   90         c->string_maximum = 0;
   91         c->set_delimiter = 0;
   92 }
   93 
   94 static void
   95 hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t nextid)
   96 {
   97         uint8_t i;
   98 
   99         if (c->report_ID == nextid)
  100                 return;
  101 
  102         /* save current position for current rID */
  103         if (c->report_ID == 0) {
  104                 i = 0;
  105         } else {
  106                 for (i = 1; i != MAXID; i++) {
  107                         if (s->last_pos[i].rid == c->report_ID)
  108                                 break;
  109                         if (s->last_pos[i].rid == 0)
  110                                 break;
  111                 }
  112         }
  113         if (i != MAXID) {
  114                 s->last_pos[i].rid = c->report_ID;
  115                 s->last_pos[i].pos = c->loc.pos;
  116         }
  117 
  118         /* store next report ID */
  119         c->report_ID = nextid;
  120 
  121         /* lookup last position for next rID */
  122         if (nextid == 0) {
  123                 i = 0;
  124         } else {
  125                 for (i = 1; i != MAXID; i++) {
  126                         if (s->last_pos[i].rid == nextid)
  127                                 break;
  128                         if (s->last_pos[i].rid == 0)
  129                                 break;
  130                 }
  131         }
  132         if (i != MAXID) {
  133                 s->last_pos[i].rid = nextid;
  134                 c->loc.pos = s->last_pos[i].pos;
  135         } else {
  136                 DPRINTF("Out of RID entries, position is set to zero!\n");
  137                 c->loc.pos = 0;
  138         }
  139 }
  140 
  141 struct hid_data *
  142 hid_start_parse(const void *d, int len, enum hid_kind kind)
  143 {
  144         struct hid_data *s;
  145 
  146         s = malloc(sizeof(*s), M_TEMP, M_WAITOK | M_ZERO);
  147 
  148         s->start = s->p = d;
  149         s->end = ((const uint8_t *)d) + len;
  150         s->kind = kind;
  151         return (s);
  152 }
  153 
  154 void
  155 hid_end_parse(struct hid_data *s)
  156 {
  157         if (s == NULL)
  158                 return;
  159 
  160         free(s, M_TEMP, 0);
  161 }
  162 
  163 static uint8_t
  164 hid_get_byte(struct hid_data *s, const uint16_t wSize)
  165 {
  166         const uint8_t *ptr;
  167         uint8_t retval;
  168 
  169         ptr = s->p;
  170 
  171         /* check if end is reached */
  172         if (ptr == s->end)
  173                 return (0);
  174 
  175         /* read out a byte */
  176         retval = *ptr;
  177 
  178         /* check if data pointer can be advanced by "wSize" bytes */
  179         if ((s->end - ptr) < wSize)
  180                 ptr = s->end;
  181         else
  182                 ptr += wSize;
  183 
  184         /* update pointer */
  185         s->p = ptr;
  186 
  187         return (retval);
  188 }
  189 
  190 int
  191 hid_get_item(struct hid_data *s, struct hid_item *h)
  192 {
  193         struct hid_item *c;
  194         unsigned int bTag, bType, bSize;
  195         uint32_t oldpos;
  196         int32_t mask;
  197         int32_t dval;
  198 
  199         if (s == NULL)
  200                 return (0);
  201 
  202         if (s->pushlevel >= MAXPUSH)
  203                 return (0);
  204 
  205         c = &s->cur[s->pushlevel];
  206 
  207  top:
  208         /* check if there is an array of items */
  209         DPRINTF("%s: icount=%d ncount=%d\n", __func__,
  210             s->icount, s->ncount);
  211         if (s->icount < s->ncount) {
  212                 /* get current usage */
  213                 if (s->iusage < s->nusage) {
  214                         dval = s->usages_min[s->iusage] + s->ousage;
  215                         c->usage = dval;
  216                         s->usage_last = dval;
  217                         if (dval == s->usages_max[s->iusage]) {
  218                                 s->iusage ++;
  219                                 s->ousage = 0;
  220                         } else {
  221                                 s->ousage ++;
  222                         }
  223                 } else {
  224                         DPRINTF("Using last usage\n");
  225                         dval = s->usage_last;
  226                 }
  227                 s->icount ++;
  228                 /*
  229                  * Only copy HID item, increment position and return
  230                  * if correct kind!
  231                  */
  232                 if (s->kind == hid_all || s->kind == c->kind) {
  233                         *h = *c;
  234                         DPRINTF("%u,%u,%u\n", h->loc.pos,
  235                             h->loc.size, h->loc.count);
  236                         c->loc.pos += c->loc.size * c->loc.count;
  237                         return (1);
  238                 }
  239         }
  240 
  241         /* reset state variables */
  242         s->icount = 0;
  243         s->ncount = 0;
  244         s->iusage = 0;
  245         s->nusage = 0;
  246         s->susage = 0;
  247         s->ousage = 0;
  248         hid_clear_local(c);
  249 
  250         /* get next item */
  251         while (s->p != s->end) {
  252 
  253                 bSize = hid_get_byte(s, 1);
  254                 if (bSize == 0xfe) {
  255                         /* long item */
  256                         bSize = hid_get_byte(s, 1);
  257                         bSize |= hid_get_byte(s, 1) << 8;
  258                         bTag = hid_get_byte(s, 1);
  259                         bType = 0xff;   /* XXX what should it be */
  260                 } else {
  261                         /* short item */
  262                         bTag = bSize >> 4;
  263                         bType = (bSize >> 2) & 3;
  264                         bSize &= 3;
  265                         if (bSize == 3)
  266                                 bSize = 4;
  267                 }
  268                 switch (bSize) {
  269                 case 0:
  270                         dval = 0;
  271                         mask = 0;
  272                         break;
  273                 case 1:
  274                         dval = hid_get_byte(s, 1);
  275                         mask = 0xFF;
  276                         break;
  277                 case 2:
  278                         dval = hid_get_byte(s, 1);
  279                         dval |= hid_get_byte(s, 1) << 8;
  280                         mask = 0xFFFF;
  281                         break;
  282                 case 4:
  283                         dval = hid_get_byte(s, 1);
  284                         dval |= hid_get_byte(s, 1) << 8;
  285                         dval |= hid_get_byte(s, 1) << 16;
  286                         dval |= hid_get_byte(s, 1) << 24;
  287                         mask = 0xFFFFFFFF;
  288                         break;
  289                 default:
  290                         dval = hid_get_byte(s, bSize);
  291                         DPRINTF("bad length %u (data=0x%02x)\n",
  292                             bSize, dval);
  293                         continue;
  294                 }
  295 
  296                 DPRINTF("%s: bType=%d bTag=%d dval=%d\n", __func__,
  297                     bType, bTag, dval);
  298                 switch (bType) {
  299                 case 0:         /* Main */
  300                         switch (bTag) {
  301                         case 8: /* Input */
  302                                 c->kind = hid_input;
  303                                 c->flags = dval;
  304                 ret:
  305                                 c->loc.count = s->loc_count;
  306                                 c->loc.size = s->loc_size;
  307 
  308                                 if (c->flags & HIO_VARIABLE) {
  309                                         /* range check usage count */
  310                                         if (c->loc.count > 255) {
  311                                                 DPRINTF("Number of "
  312                                                     "items truncated to 255\n");
  313                                                 s->ncount = 255;
  314                                         } else
  315                                                 s->ncount = c->loc.count;
  316 
  317                                         /*
  318                                          * The "top" loop will return
  319                                          * one and one item:
  320                                          */
  321                                         c->loc.count = 1;
  322                                 } else {
  323                                         s->ncount = 1;
  324                                 }
  325                                 goto top;
  326 
  327                         case 9: /* Output */
  328                                 c->kind = hid_output;
  329                                 c->flags = dval;
  330                                 goto ret;
  331                         case 10:        /* Collection */
  332                                 c->kind = hid_collection;
  333                                 c->collection = dval;
  334                                 c->collevel++;
  335                                 c->usage = s->usage_last;
  336                                 *h = *c;
  337                                 return (1);
  338                         case 11:        /* Feature */
  339                                 c->kind = hid_feature;
  340                                 c->flags = dval;
  341                                 goto ret;
  342                         case 12:        /* End collection */
  343                                 c->kind = hid_endcollection;
  344                                 if (c->collevel == 0) {
  345                                         DPRINTF("invalid end collection\n");
  346                                         return (0);
  347                                 }
  348                                 c->collevel--;
  349                                 *h = *c;
  350                                 return (1);
  351                         default:
  352                                 DPRINTF("Main bTag=%d\n", bTag);
  353                                 break;
  354                         }
  355                         break;
  356                 case 1:         /* Global */
  357                         switch (bTag) {
  358                         case 0:
  359                                 c->_usage_page = dval << 16;
  360                                 break;
  361                         case 1:
  362                                 c->logical_minimum = dval;
  363                                 break;
  364                         case 2:
  365                                 c->logical_maximum = dval;
  366                                 break;
  367                         case 3:
  368                                 c->physical_minimum = dval;
  369                                 break;
  370                         case 4:
  371                                 c->physical_maximum = dval;
  372                                 break;
  373                         case 5:
  374                                 c->unit_exponent = dval;
  375                                 break;
  376                         case 6:
  377                                 c->unit = dval;
  378                                 break;
  379                         case 7:
  380                                 /* mask because value is unsigned */
  381                                 s->loc_size = dval & mask;
  382                                 break;
  383                         case 8:
  384                                 hid_switch_rid(s, c, dval & mask);
  385                                 break;
  386                         case 9:
  387                                 /* mask because value is unsigned */
  388                                 s->loc_count = dval & mask;
  389                                 break;
  390                         case 10:        /* Push */
  391                                 if (s->pushlevel < MAXPUSH - 1) {
  392                                         s->pushlevel++;
  393                                         s->cur[s->pushlevel] = *c;
  394                                         /* store size and count */
  395                                         c->loc.size = s->loc_size;
  396                                         c->loc.count = s->loc_count;
  397                                         /* update current item pointer */
  398                                         c = &s->cur[s->pushlevel];
  399                                 } else {
  400                                         DPRINTF("Cannot push "
  401                                             "item @ %d\n", s->pushlevel);
  402                                 }
  403                                 break;
  404                         case 11:        /* Pop */
  405                                 if (s->pushlevel > 0) {
  406                                         s->pushlevel--;
  407                                         /* preserve position */
  408                                         oldpos = c->loc.pos;
  409                                         c = &s->cur[s->pushlevel];
  410                                         /* restore size and count */
  411                                         s->loc_size = c->loc.size;
  412                                         s->loc_count = c->loc.count;
  413                                         /* set default item location */
  414                                         c->loc.pos = oldpos;
  415                                         c->loc.size = 0;
  416                                         c->loc.count = 0;
  417                                 } else {
  418                                         DPRINTF("Cannot pop "
  419                                             "item @ %d\n", s->pushlevel);
  420                                 }
  421                                 break;
  422                         default:
  423                                 DPRINTF("Global bTag=%d\n", bTag);
  424                                 break;
  425                         }
  426                         break;
  427                 case 2:         /* Local */
  428                         switch (bTag) {
  429                         case 0:
  430                                 if (bSize != 4)
  431                                         dval = (dval & mask) | c->_usage_page;
  432 
  433                                 /* set last usage, in case of a collection */
  434                                 s->usage_last = dval;
  435 
  436                                 if (s->nusage < MAXUSAGE) {
  437                                         s->usages_min[s->nusage] = dval;
  438                                         s->usages_max[s->nusage] = dval;
  439                                         s->nusage ++;
  440                                 } else {
  441                                         DPRINTF("max usage reached\n");
  442                                 }
  443 
  444                                 /* clear any pending usage sets */
  445                                 s->susage = 0;
  446                                 break;
  447                         case 1:
  448                                 s->susage |= 1;
  449 
  450                                 if (bSize != 4)
  451                                         dval = (dval & mask) | c->_usage_page;
  452                                 c->usage_minimum = dval;
  453 
  454                                 goto check_set;
  455                         case 2:
  456                                 s->susage |= 2;
  457 
  458                                 if (bSize != 4)
  459                                         dval = (dval & mask) | c->_usage_page;
  460                                 c->usage_maximum = dval;
  461 
  462                         check_set:
  463                                 if (s->susage != 3)
  464                                         break;
  465 
  466                                 /* sanity check */
  467                                 if ((s->nusage < MAXUSAGE) &&
  468                                     (c->usage_minimum <= c->usage_maximum)) {
  469                                         /* add usage range */
  470                                         s->usages_min[s->nusage] = 
  471                                             c->usage_minimum;
  472                                         s->usages_max[s->nusage] = 
  473                                             c->usage_maximum;
  474                                         s->nusage ++;
  475                                 } else {
  476                                         DPRINTF("Usage set dropped\n");
  477                                 }
  478                                 s->susage = 0;
  479                                 break;
  480                         case 3:
  481                                 c->designator_index = dval;
  482                                 break;
  483                         case 4:
  484                                 c->designator_minimum = dval;
  485                                 break;
  486                         case 5:
  487                                 c->designator_maximum = dval;
  488                                 break;
  489                         case 7:
  490                                 c->string_index = dval;
  491                                 break;
  492                         case 8:
  493                                 c->string_minimum = dval;
  494                                 break;
  495                         case 9:
  496                                 c->string_maximum = dval;
  497                                 break;
  498                         case 10:
  499                                 c->set_delimiter = dval;
  500                                 break;
  501                         default:
  502                                 DPRINTF("Local bTag=%d\n", bTag);
  503                                 break;
  504                         }
  505                         break;
  506                 default:
  507                         DPRINTF("default bType=%d\n", bType);
  508                         break;
  509                 }
  510         }
  511         return (0);
  512 }
  513 
  514 int
  515 hid_report_size(const void *buf, int len, enum hid_kind k, u_int8_t id)
  516 {
  517         struct hid_data *d;
  518         struct hid_item h;
  519         int lo, hi;
  520 
  521         h.report_ID = 0;
  522         lo = hi = -1;
  523         DPRINTF("hid_report_size: kind=%d id=%d\n", k, id);
  524         for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
  525                 DPRINTF("hid_report_size: item kind=%d id=%d pos=%d "
  526                           "size=%d count=%d\n",
  527                           h.kind, h.report_ID, h.loc.pos, h.loc.size,
  528                           h.loc.count);
  529                 if (h.report_ID == id && h.kind == k) {
  530                         if (lo < 0) {
  531                                 lo = h.loc.pos;
  532 #ifdef DIAGNOSTIC
  533                                 if (lo != 0) {
  534                                         printf("hid_report_size: lo != 0\n");
  535                                 }
  536 #endif
  537                         }
  538                         hi = h.loc.pos + h.loc.size * h.loc.count;
  539                         DPRINTF("hid_report_size: lo=%d hi=%d\n", lo, hi);
  540 
  541                 }
  542         }
  543         hid_end_parse(d);
  544         return ((hi - lo + 7) / 8);
  545 }
  546 
  547 int
  548 hid_locate(const void *desc, int size, int32_t u, uint8_t id, enum hid_kind k,
  549     struct hid_location *loc, uint32_t *flags)
  550 {
  551         struct hid_data *d;
  552         struct hid_item h;
  553 
  554         h.report_ID = 0;
  555         DPRINTF("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id);
  556         for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
  557                 DPRINTF("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
  558                             h.usage, h.kind, h.report_ID, h.flags);
  559                 if (h.kind == k && !(h.flags & HIO_CONST) &&
  560                     h.usage == u && h.report_ID == id) {
  561                         if (loc != NULL)
  562                                 *loc = h.loc;
  563                         if (flags != NULL)
  564                                 *flags = h.flags;
  565                         hid_end_parse(d);
  566                         return (1);
  567                 }
  568         }
  569         hid_end_parse(d);
  570         if (loc != NULL)
  571                 loc->size = 0;
  572         if (flags != NULL)
  573                 *flags = 0;
  574         return (0);
  575 }
  576 
  577 uint32_t
  578 hid_get_data_sub(const uint8_t *buf, int len, struct hid_location *loc,
  579     int is_signed)
  580 {
  581         uint32_t hpos = loc->pos;
  582         uint32_t hsize = loc->size;
  583         uint32_t data;
  584         uint32_t rpos;
  585         uint8_t n;
  586 
  587         DPRINTF("hid_get_data_sub: loc %d/%d\n", hpos, hsize);
  588 
  589         /* Range check and limit */
  590         if (hsize == 0)
  591                 return (0);
  592         if (hsize > 32)
  593                 hsize = 32;
  594 
  595         /* Get data in a safe way */
  596         data = 0;
  597         rpos = (hpos / 8);
  598         n = (hsize + 7) / 8;
  599         rpos += n;
  600         while (n--) {
  601                 rpos--;
  602                 if (rpos < len)
  603                         data |= buf[rpos] << (8 * n);
  604         }
  605 
  606         /* Correctly shift down data */
  607         data = (data >> (hpos % 8));
  608         n = 32 - hsize;
  609 
  610         /* Mask and sign extend in one */
  611         if (is_signed != 0)
  612                 data = (int32_t)((int32_t)data << n) >> n;
  613         else
  614                 data = (uint32_t)((uint32_t)data << n) >> n;
  615 
  616         DPRINTF("hid_get_data_sub: loc %d/%d = %lu\n",
  617             loc->pos, loc->size, (long)data);
  618         return (data);
  619 }
  620 
  621 int32_t
  622 hid_get_data(const uint8_t *buf, int len, struct hid_location *loc)
  623 {
  624         return (hid_get_data_sub(buf, len, loc, 1));
  625 }
  626 
  627 uint32_t
  628 hid_get_udata(const uint8_t *buf, int len, struct hid_location *loc)
  629 {
  630         return (hid_get_data_sub(buf, len, loc, 0));
  631 }
  632 
  633 int
  634 hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage)
  635 {
  636         struct hid_data *hd;
  637         struct hid_item hi;
  638         uint32_t coll_usage = ~0;
  639 
  640         hd = hid_start_parse(desc, size, hid_all);
  641 
  642         DPRINTF("%s: id=%d usage=0x%x\n", __func__, id, usage);
  643         while (hid_get_item(hd, &hi)) {
  644                 DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__,
  645                             hi.kind, hi.report_ID, hi.usage, coll_usage);
  646                 if (hi.kind == hid_collection &&
  647                     hi.collection == HCOLL_APPLICATION)
  648                         coll_usage = hi.usage;
  649                 if (hi.kind == hid_endcollection &&
  650                     coll_usage == usage && hi.report_ID == id) {
  651                         DPRINTF("%s: found\n", __func__);
  652                         hid_end_parse(hd);
  653                         return (1);
  654                 }
  655         }
  656         DPRINTF("%s: not found\n", __func__);
  657         hid_end_parse(hd);
  658         return (0);
  659 }

Cache object: dc94f143347df80f1231368a9ce2cbd9


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