LCOV - code coverage report
Current view: top level - dev/hid - hid.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 301 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: hid.c,v 1.2 2016/01/20 01:11:50 jcs 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           0 : hid_clear_local(struct hid_item *c)
      79             : {
      80           0 :         c->loc.count = 0;
      81           0 :         c->loc.size = 0;
      82           0 :         c->usage = 0;
      83           0 :         c->usage_minimum = 0;
      84           0 :         c->usage_maximum = 0;
      85           0 :         c->designator_index = 0;
      86           0 :         c->designator_minimum = 0;
      87           0 :         c->designator_maximum = 0;
      88           0 :         c->string_index = 0;
      89           0 :         c->string_minimum = 0;
      90           0 :         c->string_maximum = 0;
      91           0 :         c->set_delimiter = 0;
      92           0 : }
      93             : 
      94             : static void
      95           0 : hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t nextid)
      96             : {
      97             :         uint8_t i;
      98             : 
      99           0 :         if (c->report_ID == nextid)
     100           0 :                 return;
     101             : 
     102             :         /* save current position for current rID */
     103           0 :         if (c->report_ID == 0) {
     104             :                 i = 0;
     105           0 :         } else {
     106           0 :                 for (i = 1; i != MAXID; i++) {
     107           0 :                         if (s->last_pos[i].rid == c->report_ID)
     108             :                                 break;
     109           0 :                         if (s->last_pos[i].rid == 0)
     110             :                                 break;
     111             :                 }
     112             :         }
     113           0 :         if (i != MAXID) {
     114           0 :                 s->last_pos[i].rid = c->report_ID;
     115           0 :                 s->last_pos[i].pos = c->loc.pos;
     116           0 :         }
     117             : 
     118             :         /* store next report ID */
     119           0 :         c->report_ID = nextid;
     120             : 
     121             :         /* lookup last position for next rID */
     122           0 :         if (nextid == 0) {
     123             :                 i = 0;
     124           0 :         } else {
     125           0 :                 for (i = 1; i != MAXID; i++) {
     126           0 :                         if (s->last_pos[i].rid == nextid)
     127             :                                 break;
     128           0 :                         if (s->last_pos[i].rid == 0)
     129             :                                 break;
     130             :                 }
     131             :         }
     132           0 :         if (i != MAXID) {
     133           0 :                 s->last_pos[i].rid = nextid;
     134           0 :                 c->loc.pos = s->last_pos[i].pos;
     135           0 :         } else {
     136             :                 DPRINTF("Out of RID entries, position is set to zero!\n");
     137           0 :                 c->loc.pos = 0;
     138             :         }
     139           0 : }
     140             : 
     141             : struct hid_data *
     142           0 : hid_start_parse(const void *d, int len, enum hid_kind kind)
     143             : {
     144             :         struct hid_data *s;
     145             : 
     146           0 :         s = malloc(sizeof(*s), M_TEMP, M_WAITOK | M_ZERO);
     147             : 
     148           0 :         s->start = s->p = d;
     149           0 :         s->end = ((const uint8_t *)d) + len;
     150           0 :         s->kind = kind;
     151           0 :         return (s);
     152             : }
     153             : 
     154             : void
     155           0 : hid_end_parse(struct hid_data *s)
     156             : {
     157           0 :         if (s == NULL)
     158             :                 return;
     159             : 
     160           0 :         free(s, M_TEMP, 0);
     161           0 : }
     162             : 
     163             : static uint8_t
     164           0 : hid_get_byte(struct hid_data *s, const uint16_t wSize)
     165             : {
     166             :         const uint8_t *ptr;
     167             :         uint8_t retval;
     168             : 
     169           0 :         ptr = s->p;
     170             : 
     171             :         /* check if end is reached */
     172           0 :         if (ptr == s->end)
     173           0 :                 return (0);
     174             : 
     175             :         /* read out a byte */
     176           0 :         retval = *ptr;
     177             : 
     178             :         /* check if data pointer can be advanced by "wSize" bytes */
     179           0 :         if ((s->end - ptr) < wSize)
     180           0 :                 ptr = s->end;
     181             :         else
     182           0 :                 ptr += wSize;
     183             : 
     184             :         /* update pointer */
     185           0 :         s->p = ptr;
     186             : 
     187           0 :         return (retval);
     188           0 : }
     189             : 
     190             : int
     191           0 : 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           0 :         if (s == NULL)
     200           0 :                 return (0);
     201             : 
     202           0 :         c = &s->cur[s->pushlevel];
     203             : 
     204             :  top:
     205             :         /* check if there is an array of items */
     206             :         DPRINTF("%s: icount=%d ncount=%d\n", __func__,
     207             :             s->icount, s->ncount);
     208           0 :         if (s->icount < s->ncount) {
     209             :                 /* get current usage */
     210           0 :                 if (s->iusage < s->nusage) {
     211           0 :                         dval = s->usages_min[s->iusage] + s->ousage;
     212           0 :                         c->usage = dval;
     213           0 :                         s->usage_last = dval;
     214           0 :                         if (dval == s->usages_max[s->iusage]) {
     215           0 :                                 s->iusage ++;
     216           0 :                                 s->ousage = 0;
     217           0 :                         } else {
     218           0 :                                 s->ousage ++;
     219             :                         }
     220             :                 } else {
     221             :                         DPRINTF("Using last usage\n");
     222           0 :                         dval = s->usage_last;
     223             :                 }
     224           0 :                 s->icount ++;
     225             :                 /*
     226             :                  * Only copy HID item, increment position and return
     227             :                  * if correct kind!
     228             :                  */
     229           0 :                 if (s->kind == c->kind) {
     230           0 :                         *h = *c;
     231             :                         DPRINTF("%u,%u,%u\n", h->loc.pos,
     232             :                             h->loc.size, h->loc.count);
     233           0 :                         c->loc.pos += c->loc.size * c->loc.count;
     234           0 :                         return (1);
     235             :                 }
     236             :         }
     237             : 
     238             :         /* reset state variables */
     239           0 :         s->icount = 0;
     240           0 :         s->ncount = 0;
     241           0 :         s->iusage = 0;
     242           0 :         s->nusage = 0;
     243           0 :         s->susage = 0;
     244           0 :         s->ousage = 0;
     245           0 :         hid_clear_local(c);
     246             : 
     247             :         /* get next item */
     248           0 :         while (s->p != s->end) {
     249             : 
     250           0 :                 bSize = hid_get_byte(s, 1);
     251           0 :                 if (bSize == 0xfe) {
     252             :                         /* long item */
     253           0 :                         bSize = hid_get_byte(s, 1);
     254           0 :                         bSize |= hid_get_byte(s, 1) << 8;
     255           0 :                         bTag = hid_get_byte(s, 1);
     256             :                         bType = 0xff;   /* XXX what should it be */
     257           0 :                 } else {
     258             :                         /* short item */
     259           0 :                         bTag = bSize >> 4;
     260           0 :                         bType = (bSize >> 2) & 3;
     261           0 :                         bSize &= 3;
     262           0 :                         if (bSize == 3)
     263             :                                 bSize = 4;
     264             :                 }
     265           0 :                 switch (bSize) {
     266             :                 case 0:
     267             :                         dval = 0;
     268             :                         mask = 0;
     269           0 :                         break;
     270             :                 case 1:
     271           0 :                         dval = hid_get_byte(s, 1);
     272             :                         mask = 0xFF;
     273           0 :                         break;
     274             :                 case 2:
     275           0 :                         dval = hid_get_byte(s, 1);
     276           0 :                         dval |= hid_get_byte(s, 1) << 8;
     277             :                         mask = 0xFFFF;
     278           0 :                         break;
     279             :                 case 4:
     280           0 :                         dval = hid_get_byte(s, 1);
     281           0 :                         dval |= hid_get_byte(s, 1) << 8;
     282           0 :                         dval |= hid_get_byte(s, 1) << 16;
     283           0 :                         dval |= hid_get_byte(s, 1) << 24;
     284             :                         mask = 0xFFFFFFFF;
     285           0 :                         break;
     286             :                 default:
     287           0 :                         dval = hid_get_byte(s, bSize);
     288             :                         DPRINTF("bad length %u (data=0x%02x)\n",
     289             :                             bSize, dval);
     290           0 :                         continue;
     291             :                 }
     292             : 
     293             :                 DPRINTF("%s: bType=%d bTag=%d dval=%d\n", __func__,
     294             :                     bType, bTag, dval);
     295           0 :                 switch (bType) {
     296             :                 case 0:         /* Main */
     297           0 :                         switch (bTag) {
     298             :                         case 8: /* Input */
     299           0 :                                 c->kind = hid_input;
     300           0 :                                 c->flags = dval;
     301             :                 ret:
     302           0 :                                 c->loc.count = s->loc_count;
     303           0 :                                 c->loc.size = s->loc_size;
     304             : 
     305           0 :                                 if (c->flags & HIO_VARIABLE) {
     306             :                                         /* range check usage count */
     307           0 :                                         if (c->loc.count > 255) {
     308             :                                                 DPRINTF("Number of "
     309             :                                                     "items truncated to 255\n");
     310           0 :                                                 s->ncount = 255;
     311           0 :                                         } else
     312           0 :                                                 s->ncount = c->loc.count;
     313             : 
     314             :                                         /*
     315             :                                          * The "top" loop will return
     316             :                                          * one and one item:
     317             :                                          */
     318           0 :                                         c->loc.count = 1;
     319           0 :                                 } else {
     320           0 :                                         s->ncount = 1;
     321             :                                 }
     322           0 :                                 goto top;
     323             : 
     324             :                         case 9: /* Output */
     325           0 :                                 c->kind = hid_output;
     326           0 :                                 c->flags = dval;
     327           0 :                                 goto ret;
     328             :                         case 10:        /* Collection */
     329           0 :                                 c->kind = hid_collection;
     330           0 :                                 c->collection = dval;
     331           0 :                                 c->collevel++;
     332           0 :                                 c->usage = s->usage_last;
     333           0 :                                 *h = *c;
     334           0 :                                 return (1);
     335             :                         case 11:        /* Feature */
     336           0 :                                 c->kind = hid_feature;
     337           0 :                                 c->flags = dval;
     338           0 :                                 goto ret;
     339             :                         case 12:        /* End collection */
     340           0 :                                 c->kind = hid_endcollection;
     341           0 :                                 if (c->collevel == 0) {
     342             :                                         DPRINTF("invalid end collection\n");
     343           0 :                                         return (0);
     344             :                                 }
     345           0 :                                 c->collevel--;
     346           0 :                                 *h = *c;
     347           0 :                                 return (1);
     348             :                         default:
     349             :                                 DPRINTF("Main bTag=%d\n", bTag);
     350             :                                 break;
     351             :                         }
     352             :                         break;
     353             :                 case 1:         /* Global */
     354           0 :                         switch (bTag) {
     355             :                         case 0:
     356           0 :                                 c->_usage_page = dval << 16;
     357           0 :                                 break;
     358             :                         case 1:
     359           0 :                                 c->logical_minimum = dval;
     360           0 :                                 break;
     361             :                         case 2:
     362           0 :                                 c->logical_maximum = dval;
     363           0 :                                 break;
     364             :                         case 3:
     365           0 :                                 c->physical_minimum = dval;
     366           0 :                                 break;
     367             :                         case 4:
     368           0 :                                 c->physical_maximum = dval;
     369           0 :                                 break;
     370             :                         case 5:
     371           0 :                                 c->unit_exponent = dval;
     372           0 :                                 break;
     373             :                         case 6:
     374           0 :                                 c->unit = dval;
     375           0 :                                 break;
     376             :                         case 7:
     377             :                                 /* mask because value is unsigned */
     378           0 :                                 s->loc_size = dval & mask;
     379           0 :                                 break;
     380             :                         case 8:
     381           0 :                                 hid_switch_rid(s, c, dval & mask);
     382           0 :                                 break;
     383             :                         case 9:
     384             :                                 /* mask because value is unsigned */
     385           0 :                                 s->loc_count = dval & mask;
     386           0 :                                 break;
     387             :                         case 10:        /* Push */
     388           0 :                                 s->pushlevel ++;
     389           0 :                                 if (s->pushlevel < MAXPUSH) {
     390           0 :                                         s->cur[s->pushlevel] = *c;
     391             :                                         /* store size and count */
     392           0 :                                         c->loc.size = s->loc_size;
     393           0 :                                         c->loc.count = s->loc_count;
     394             :                                         /* update current item pointer */
     395           0 :                                         c = &s->cur[s->pushlevel];
     396           0 :                                 } else {
     397             :                                         DPRINTF("Cannot push "
     398             :                                             "item @ %d\n", s->pushlevel);
     399             :                                 }
     400             :                                 break;
     401             :                         case 11:        /* Pop */
     402           0 :                                 s->pushlevel --;
     403           0 :                                 if (s->pushlevel < MAXPUSH) {
     404             :                                         /* preserve position */
     405           0 :                                         oldpos = c->loc.pos;
     406           0 :                                         c = &s->cur[s->pushlevel];
     407             :                                         /* restore size and count */
     408           0 :                                         s->loc_size = c->loc.size;
     409           0 :                                         s->loc_count = c->loc.count;
     410             :                                         /* set default item location */
     411           0 :                                         c->loc.pos = oldpos;
     412           0 :                                         c->loc.size = 0;
     413           0 :                                         c->loc.count = 0;
     414           0 :                                 } else {
     415             :                                         DPRINTF("Cannot pop "
     416             :                                             "item @ %d\n", s->pushlevel);
     417             :                                 }
     418             :                                 break;
     419             :                         default:
     420             :                                 DPRINTF("Global bTag=%d\n", bTag);
     421             :                                 break;
     422             :                         }
     423             :                         break;
     424             :                 case 2:         /* Local */
     425           0 :                         switch (bTag) {
     426             :                         case 0:
     427           0 :                                 if (bSize != 4)
     428           0 :                                         dval = (dval & mask) | c->_usage_page;
     429             : 
     430             :                                 /* set last usage, in case of a collection */
     431           0 :                                 s->usage_last = dval;
     432             : 
     433           0 :                                 if (s->nusage < MAXUSAGE) {
     434           0 :                                         s->usages_min[s->nusage] = dval;
     435           0 :                                         s->usages_max[s->nusage] = dval;
     436           0 :                                         s->nusage ++;
     437           0 :                                 } else {
     438             :                                         DPRINTF("max usage reached\n");
     439             :                                 }
     440             : 
     441             :                                 /* clear any pending usage sets */
     442           0 :                                 s->susage = 0;
     443           0 :                                 break;
     444             :                         case 1:
     445           0 :                                 s->susage |= 1;
     446             : 
     447           0 :                                 if (bSize != 4)
     448           0 :                                         dval = (dval & mask) | c->_usage_page;
     449           0 :                                 c->usage_minimum = dval;
     450             : 
     451           0 :                                 goto check_set;
     452             :                         case 2:
     453           0 :                                 s->susage |= 2;
     454             : 
     455           0 :                                 if (bSize != 4)
     456           0 :                                         dval = (dval & mask) | c->_usage_page;
     457           0 :                                 c->usage_maximum = dval;
     458             : 
     459             :                         check_set:
     460           0 :                                 if (s->susage != 3)
     461             :                                         break;
     462             : 
     463             :                                 /* sanity check */
     464           0 :                                 if ((s->nusage < MAXUSAGE) &&
     465           0 :                                     (c->usage_minimum <= c->usage_maximum)) {
     466             :                                         /* add usage range */
     467           0 :                                         s->usages_min[s->nusage] = 
     468             :                                             c->usage_minimum;
     469           0 :                                         s->usages_max[s->nusage] = 
     470           0 :                                             c->usage_maximum;
     471           0 :                                         s->nusage ++;
     472           0 :                                 } else {
     473             :                                         DPRINTF("Usage set dropped\n");
     474             :                                 }
     475           0 :                                 s->susage = 0;
     476           0 :                                 break;
     477             :                         case 3:
     478           0 :                                 c->designator_index = dval;
     479           0 :                                 break;
     480             :                         case 4:
     481           0 :                                 c->designator_minimum = dval;
     482           0 :                                 break;
     483             :                         case 5:
     484           0 :                                 c->designator_maximum = dval;
     485           0 :                                 break;
     486             :                         case 7:
     487           0 :                                 c->string_index = dval;
     488           0 :                                 break;
     489             :                         case 8:
     490           0 :                                 c->string_minimum = dval;
     491           0 :                                 break;
     492             :                         case 9:
     493           0 :                                 c->string_maximum = dval;
     494           0 :                                 break;
     495             :                         case 10:
     496           0 :                                 c->set_delimiter = dval;
     497           0 :                                 break;
     498             :                         default:
     499             :                                 DPRINTF("Local bTag=%d\n", bTag);
     500             :                                 break;
     501             :                         }
     502             :                         break;
     503             :                 default:
     504             :                         DPRINTF("default bType=%d\n", bType);
     505             :                         break;
     506             :                 }
     507             :         }
     508           0 :         return (0);
     509           0 : }
     510             : 
     511             : int
     512           0 : hid_report_size(const void *buf, int len, enum hid_kind k, u_int8_t id)
     513             : {
     514             :         struct hid_data *d;
     515           0 :         struct hid_item h;
     516             :         int lo, hi;
     517             : 
     518           0 :         h.report_ID = 0;
     519             :         lo = hi = -1;
     520             :         DPRINTF("hid_report_size: kind=%d id=%d\n", k, id);
     521           0 :         for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
     522             :                 DPRINTF("hid_report_size: item kind=%d id=%d pos=%d "
     523             :                           "size=%d count=%d\n",
     524             :                           h.kind, h.report_ID, h.loc.pos, h.loc.size,
     525             :                           h.loc.count);
     526           0 :                 if (h.report_ID == id && h.kind == k) {
     527           0 :                         if (lo < 0) {
     528           0 :                                 lo = h.loc.pos;
     529             : #ifdef DIAGNOSTIC
     530           0 :                                 if (lo != 0) {
     531           0 :                                         printf("hid_report_size: lo != 0\n");
     532           0 :                                 }
     533             : #endif
     534             :                         }
     535           0 :                         hi = h.loc.pos + h.loc.size * h.loc.count;
     536             :                         DPRINTF("hid_report_size: lo=%d hi=%d\n", lo, hi);
     537             : 
     538           0 :                 }
     539             :         }
     540           0 :         hid_end_parse(d);
     541           0 :         return ((hi - lo + 7) / 8);
     542           0 : }
     543             : 
     544             : int
     545           0 : hid_locate(const void *desc, int size, int32_t u, uint8_t id, enum hid_kind k,
     546             :     struct hid_location *loc, uint32_t *flags)
     547             : {
     548             :         struct hid_data *d;
     549           0 :         struct hid_item h;
     550             : 
     551           0 :         h.report_ID = 0;
     552             :         DPRINTF("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id);
     553           0 :         for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
     554             :                 DPRINTF("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
     555             :                             h.usage, h.kind, h.report_ID, h.flags);
     556           0 :                 if (h.kind == k && !(h.flags & HIO_CONST) &&
     557           0 :                     h.usage == u && h.report_ID == id) {
     558           0 :                         if (loc != NULL)
     559           0 :                                 *loc = h.loc;
     560           0 :                         if (flags != NULL)
     561           0 :                                 *flags = h.flags;
     562           0 :                         hid_end_parse(d);
     563           0 :                         return (1);
     564             :                 }
     565             :         }
     566           0 :         hid_end_parse(d);
     567           0 :         if (loc != NULL)
     568           0 :                 loc->size = 0;
     569           0 :         if (flags != NULL)
     570           0 :                 *flags = 0;
     571           0 :         return (0);
     572           0 : }
     573             : 
     574             : uint32_t
     575           0 : hid_get_data_sub(const uint8_t *buf, int len, struct hid_location *loc,
     576             :     int is_signed)
     577             : {
     578           0 :         uint32_t hpos = loc->pos;
     579           0 :         uint32_t hsize = loc->size;
     580             :         uint32_t data;
     581             :         uint32_t rpos;
     582             :         uint8_t n;
     583             : 
     584             :         DPRINTF("hid_get_data_sub: loc %d/%d\n", hpos, hsize);
     585             : 
     586             :         /* Range check and limit */
     587           0 :         if (hsize == 0)
     588           0 :                 return (0);
     589           0 :         if (hsize > 32)
     590           0 :                 hsize = 32;
     591             : 
     592             :         /* Get data in a safe way */
     593             :         data = 0;
     594           0 :         rpos = (hpos / 8);
     595           0 :         n = (hsize + 7) / 8;
     596           0 :         rpos += n;
     597           0 :         while (n--) {
     598           0 :                 rpos--;
     599           0 :                 if (rpos < len)
     600           0 :                         data |= buf[rpos] << (8 * n);
     601             :         }
     602             : 
     603             :         /* Correctly shift down data */
     604           0 :         data = (data >> (hpos % 8));
     605           0 :         n = 32 - hsize;
     606             : 
     607             :         /* Mask and sign extend in one */
     608           0 :         if (is_signed != 0)
     609           0 :                 data = (int32_t)((int32_t)data << n) >> n;
     610             :         else
     611           0 :                 data = (uint32_t)((uint32_t)data << n) >> n;
     612             : 
     613             :         DPRINTF("hid_get_data_sub: loc %d/%d = %lu\n",
     614             :             loc->pos, loc->size, (long)data);
     615           0 :         return (data);
     616           0 : }
     617             : 
     618             : int32_t
     619           0 : hid_get_data(const uint8_t *buf, int len, struct hid_location *loc)
     620             : {
     621           0 :         return (hid_get_data_sub(buf, len, loc, 1));
     622             : }
     623             : 
     624             : uint32_t
     625           0 : hid_get_udata(const uint8_t *buf, int len, struct hid_location *loc)
     626             : {
     627           0 :         return (hid_get_data_sub(buf, len, loc, 0));
     628             : }
     629             : 
     630             : int
     631           0 : hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage)
     632             : {
     633             :         struct hid_data *hd;
     634           0 :         struct hid_item hi;
     635             :         uint32_t coll_usage = ~0;
     636             : 
     637           0 :         hd = hid_start_parse(desc, size, hid_none);
     638             : 
     639             :         DPRINTF("%s: id=%d usage=0x%x\n", __func__, id, usage);
     640           0 :         while (hid_get_item(hd, &hi)) {
     641             :                 DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__,
     642             :                             hi.kind, hi.report_ID, hi.usage, coll_usage);
     643           0 :                 if (hi.kind == hid_collection &&
     644           0 :                     hi.collection == HCOLL_APPLICATION)
     645           0 :                         coll_usage = hi.usage;
     646           0 :                 if (hi.kind == hid_endcollection &&
     647           0 :                     coll_usage == usage && hi.report_ID == id) {
     648             :                         DPRINTF("%s: found\n", __func__);
     649           0 :                         hid_end_parse(hd);
     650           0 :                         return (1);
     651             :                 }
     652             :         }
     653             :         DPRINTF("%s: not found\n", __func__);
     654           0 :         hid_end_parse(hd);
     655           0 :         return (0);
     656           0 : }

Generated by: LCOV version 1.13