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/usb/usb_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 /*      $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $   */
    2 
    3 
    4 #include <sys/cdefs.h>
    5 __FBSDID("$FreeBSD: releng/8.3/sys/dev/usb/usb_hid.c 224178 2011-07-18 08:38:08Z hselasky $");
    6 /*-
    7  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    8  * All rights reserved.
    9  *
   10  * This code is derived from software contributed to The NetBSD Foundation
   11  * by Lennart Augustsson (lennart@augustsson.net) at
   12  * Carlstedt Research & Technology.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33  * POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/stdint.h>
   37 #include <sys/stddef.h>
   38 #include <sys/param.h>
   39 #include <sys/queue.h>
   40 #include <sys/types.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/bus.h>
   44 #include <sys/module.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/condvar.h>
   48 #include <sys/sysctl.h>
   49 #include <sys/sx.h>
   50 #include <sys/unistd.h>
   51 #include <sys/callout.h>
   52 #include <sys/malloc.h>
   53 #include <sys/priv.h>
   54 
   55 #include <dev/usb/usb.h>
   56 #include <dev/usb/usbdi.h>
   57 #include <dev/usb/usbdi_util.h>
   58 #include <dev/usb/usbhid.h>
   59 
   60 #define USB_DEBUG_VAR usb_debug
   61 
   62 #include <dev/usb/usb_core.h>
   63 #include <dev/usb/usb_debug.h>
   64 #include <dev/usb/usb_process.h>
   65 #include <dev/usb/usb_device.h>
   66 #include <dev/usb/usb_request.h>
   67 
   68 static void hid_clear_local(struct hid_item *);
   69 static uint8_t hid_get_byte(struct hid_data *s, const uint16_t wSize);
   70 
   71 #define MAXUSAGE 64
   72 #define MAXPUSH 4
   73 #define MAXID 16
   74 
   75 struct hid_pos_data {
   76         int32_t rid;
   77         uint32_t pos;
   78 };
   79 
   80 struct hid_data {
   81         const uint8_t *start;
   82         const uint8_t *end;
   83         const uint8_t *p;
   84         struct hid_item cur[MAXPUSH];
   85         struct hid_pos_data last_pos[MAXID];
   86         int32_t usages_min[MAXUSAGE];
   87         int32_t usages_max[MAXUSAGE];
   88         int32_t usage_last;     /* last seen usage */
   89         uint32_t loc_size;      /* last seen size */
   90         uint32_t loc_count;     /* last seen count */
   91         uint8_t kindset;        /* we have 5 kinds so 8 bits are enough */
   92         uint8_t pushlevel;      /* current pushlevel */
   93         uint8_t ncount;         /* end usage item count */
   94         uint8_t icount;         /* current usage item count */
   95         uint8_t nusage;         /* end "usages_min/max" index */
   96         uint8_t iusage;         /* current "usages_min/max" index */
   97         uint8_t ousage;         /* current "usages_min/max" offset */
   98         uint8_t susage;         /* usage set flags */
   99 };
  100 
  101 /*------------------------------------------------------------------------*
  102  *      hid_clear_local
  103  *------------------------------------------------------------------------*/
  104 static void
  105 hid_clear_local(struct hid_item *c)
  106 {
  107 
  108         c->loc.count = 0;
  109         c->loc.size = 0;
  110         c->usage = 0;
  111         c->usage_minimum = 0;
  112         c->usage_maximum = 0;
  113         c->designator_index = 0;
  114         c->designator_minimum = 0;
  115         c->designator_maximum = 0;
  116         c->string_index = 0;
  117         c->string_minimum = 0;
  118         c->string_maximum = 0;
  119         c->set_delimiter = 0;
  120 }
  121 
  122 static void
  123 hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
  124 {
  125         uint8_t i;
  126 
  127         /* check for same report ID - optimise */
  128 
  129         if (c->report_ID == next_rID)
  130                 return;
  131 
  132         /* save current position for current rID */
  133 
  134         if (c->report_ID == 0) {
  135                 i = 0;
  136         } else {
  137                 for (i = 1; i != MAXID; i++) {
  138                         if (s->last_pos[i].rid == c->report_ID)
  139                                 break;
  140                         if (s->last_pos[i].rid == 0)
  141                                 break;
  142                 }
  143         }
  144         if (i != MAXID) {
  145                 s->last_pos[i].rid = c->report_ID;
  146                 s->last_pos[i].pos = c->loc.pos;
  147         }
  148 
  149         /* store next report ID */
  150 
  151         c->report_ID = next_rID;
  152 
  153         /* lookup last position for next rID */
  154 
  155         if (next_rID == 0) {
  156                 i = 0;
  157         } else {
  158                 for (i = 1; i != MAXID; i++) {
  159                         if (s->last_pos[i].rid == next_rID)
  160                                 break;
  161                         if (s->last_pos[i].rid == 0)
  162                                 break;
  163                 }
  164         }
  165         if (i != MAXID) {
  166                 s->last_pos[i].rid = next_rID;
  167                 c->loc.pos = s->last_pos[i].pos;
  168         } else {
  169                 DPRINTF("Out of RID entries, position is set to zero!\n");
  170                 c->loc.pos = 0;
  171         }
  172 }
  173 
  174 /*------------------------------------------------------------------------*
  175  *      hid_start_parse
  176  *------------------------------------------------------------------------*/
  177 struct hid_data *
  178 hid_start_parse(const void *d, usb_size_t len, int kindset)
  179 {
  180         struct hid_data *s;
  181 
  182         if ((kindset-1) & kindset) {
  183                 DPRINTFN(0, "Only one bit can be "
  184                     "set in the kindset\n");
  185                 return (NULL);
  186         }
  187 
  188         s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO);
  189         s->start = s->p = d;
  190         s->end = ((const uint8_t *)d) + len;
  191         s->kindset = kindset;
  192         return (s);
  193 }
  194 
  195 /*------------------------------------------------------------------------*
  196  *      hid_end_parse
  197  *------------------------------------------------------------------------*/
  198 void
  199 hid_end_parse(struct hid_data *s)
  200 {
  201         if (s == NULL)
  202                 return;
  203 
  204         free(s, M_TEMP);
  205 }
  206 
  207 /*------------------------------------------------------------------------*
  208  *      get byte from HID descriptor
  209  *------------------------------------------------------------------------*/
  210 static uint8_t
  211 hid_get_byte(struct hid_data *s, const uint16_t wSize)
  212 {
  213         const uint8_t *ptr;
  214         uint8_t retval;
  215 
  216         ptr = s->p;
  217 
  218         /* check if end is reached */
  219         if (ptr == s->end)
  220                 return (0);
  221 
  222         /* read out a byte */
  223         retval = *ptr;
  224 
  225         /* check if data pointer can be advanced by "wSize" bytes */
  226         if ((s->end - ptr) < wSize)
  227                 ptr = s->end;
  228         else
  229                 ptr += wSize;
  230 
  231         /* update pointer */
  232         s->p = ptr;
  233 
  234         return (retval);
  235 }
  236 
  237 /*------------------------------------------------------------------------*
  238  *      hid_get_item
  239  *------------------------------------------------------------------------*/
  240 int
  241 hid_get_item(struct hid_data *s, struct hid_item *h)
  242 {
  243         struct hid_item *c;
  244         unsigned int bTag, bType, bSize;
  245         uint32_t oldpos;
  246         int32_t mask;
  247         int32_t dval;
  248 
  249         if (s == NULL)
  250                 return (0);
  251 
  252         c = &s->cur[s->pushlevel];
  253 
  254  top:
  255         /* check if there is an array of items */
  256         if (s->icount < s->ncount) {
  257                 /* get current usage */
  258                 if (s->iusage < s->nusage) {
  259                         dval = s->usages_min[s->iusage] + s->ousage;
  260                         c->usage = dval;
  261                         s->usage_last = dval;
  262                         if (dval == s->usages_max[s->iusage]) {
  263                                 s->iusage ++;
  264                                 s->ousage = 0;
  265                         } else {
  266                                 s->ousage ++;
  267                         }
  268                 } else {
  269                         DPRINTFN(1, "Using last usage\n");
  270                         dval = s->usage_last;
  271                 }
  272                 s->icount ++;
  273                 /* 
  274                  * Only copy HID item, increment position and return
  275                  * if correct kindset!
  276                  */
  277                 if (s->kindset & (1 << c->kind)) {
  278                         *h = *c;
  279                         DPRINTFN(1, "%u,%u,%u\n", h->loc.pos,
  280                             h->loc.size, h->loc.count);
  281                         c->loc.pos += c->loc.size * c->loc.count;
  282                         return (1);
  283                 }
  284         }
  285 
  286         /* reset state variables */
  287         s->icount = 0;
  288         s->ncount = 0;
  289         s->iusage = 0;
  290         s->nusage = 0;
  291         s->susage = 0;
  292         s->ousage = 0;
  293         hid_clear_local(c);
  294 
  295         /* get next item */
  296         while (s->p != s->end) {
  297 
  298                 bSize = hid_get_byte(s, 1);
  299                 if (bSize == 0xfe) {
  300                         /* long item */
  301                         bSize = hid_get_byte(s, 1);
  302                         bSize |= hid_get_byte(s, 1) << 8;
  303                         bTag = hid_get_byte(s, 1);
  304                         bType = 0xff;   /* XXX what should it be */
  305                 } else {
  306                         /* short item */
  307                         bTag = bSize >> 4;
  308                         bType = (bSize >> 2) & 3;
  309                         bSize &= 3;
  310                         if (bSize == 3)
  311                                 bSize = 4;
  312                 }
  313                 switch (bSize) {
  314                 case 0:
  315                         dval = 0;
  316                         mask = 0;
  317                         break;
  318                 case 1:
  319                         dval = (int8_t)hid_get_byte(s, 1);
  320                         mask = 0xFF;
  321                         break;
  322                 case 2:
  323                         dval = hid_get_byte(s, 1);
  324                         dval |= hid_get_byte(s, 1) << 8;
  325                         dval = (int16_t)dval;
  326                         mask = 0xFFFF;
  327                         break;
  328                 case 4:
  329                         dval = hid_get_byte(s, 1);
  330                         dval |= hid_get_byte(s, 1) << 8;
  331                         dval |= hid_get_byte(s, 1) << 16;
  332                         dval |= hid_get_byte(s, 1) << 24;
  333                         mask = 0xFFFFFFFF;
  334                         break;
  335                 default:
  336                         dval = hid_get_byte(s, bSize);
  337                         DPRINTFN(0, "bad length %u (data=0x%02x)\n",
  338                             bSize, dval);
  339                         continue;
  340                 }
  341 
  342                 switch (bType) {
  343                 case 0:         /* Main */
  344                         switch (bTag) {
  345                         case 8: /* Input */
  346                                 c->kind = hid_input;
  347                                 c->flags = dval;
  348                 ret:
  349                                 c->loc.count = s->loc_count;
  350                                 c->loc.size = s->loc_size;
  351 
  352                                 if (c->flags & HIO_VARIABLE) {
  353                                         /* range check usage count */
  354                                         if (c->loc.count > 255) {
  355                                                 DPRINTFN(0, "Number of "
  356                                                     "items truncated to 255\n");
  357                                                 s->ncount = 255;
  358                                         } else
  359                                                 s->ncount = c->loc.count;
  360 
  361                                         /* 
  362                                          * The "top" loop will return
  363                                          * one and one item:
  364                                          */
  365                                         c->loc.count = 1;
  366                                 } else {
  367                                         s->ncount = 1;
  368                                 }
  369                                 goto top;
  370 
  371                         case 9: /* Output */
  372                                 c->kind = hid_output;
  373                                 c->flags = dval;
  374                                 goto ret;
  375                         case 10:        /* Collection */
  376                                 c->kind = hid_collection;
  377                                 c->collection = dval;
  378                                 c->collevel++;
  379                                 c->usage = s->usage_last;
  380                                 *h = *c;
  381                                 return (1);
  382                         case 11:        /* Feature */
  383                                 c->kind = hid_feature;
  384                                 c->flags = dval;
  385                                 goto ret;
  386                         case 12:        /* End collection */
  387                                 c->kind = hid_endcollection;
  388                                 if (c->collevel == 0) {
  389                                         DPRINTFN(0, "invalid end collection\n");
  390                                         return (0);
  391                                 }
  392                                 c->collevel--;
  393                                 *h = *c;
  394                                 return (1);
  395                         default:
  396                                 DPRINTFN(0, "Main bTag=%d\n", bTag);
  397                                 break;
  398                         }
  399                         break;
  400                 case 1:         /* Global */
  401                         switch (bTag) {
  402                         case 0:
  403                                 c->_usage_page = dval << 16;
  404                                 break;
  405                         case 1:
  406                                 c->logical_minimum = dval;
  407                                 break;
  408                         case 2:
  409                                 c->logical_maximum = dval;
  410                                 break;
  411                         case 3:
  412                                 c->physical_minimum = dval;
  413                                 break;
  414                         case 4:
  415                                 c->physical_maximum = dval;
  416                                 break;
  417                         case 5:
  418                                 c->unit_exponent = dval;
  419                                 break;
  420                         case 6:
  421                                 c->unit = dval;
  422                                 break;
  423                         case 7:
  424                                 /* mask because value is unsigned */
  425                                 s->loc_size = dval & mask;
  426                                 break;
  427                         case 8:
  428                                 hid_switch_rid(s, c, dval);
  429                                 break;
  430                         case 9:
  431                                 /* mask because value is unsigned */
  432                                 s->loc_count = dval & mask;
  433                                 break;
  434                         case 10:        /* Push */
  435                                 s->pushlevel ++;
  436                                 if (s->pushlevel < MAXPUSH) {
  437                                         s->cur[s->pushlevel] = *c;
  438                                         /* store size and count */
  439                                         c->loc.size = s->loc_size;
  440                                         c->loc.count = s->loc_count;
  441                                         /* update current item pointer */
  442                                         c = &s->cur[s->pushlevel];
  443                                 } else {
  444                                         DPRINTFN(0, "Cannot push "
  445                                             "item @ %d\n", s->pushlevel);
  446                                 }
  447                                 break;
  448                         case 11:        /* Pop */
  449                                 s->pushlevel --;
  450                                 if (s->pushlevel < MAXPUSH) {
  451                                         /* preserve position */
  452                                         oldpos = c->loc.pos;
  453                                         c = &s->cur[s->pushlevel];
  454                                         /* restore size and count */
  455                                         s->loc_size = c->loc.size;
  456                                         s->loc_count = c->loc.count;
  457                                         /* set default item location */
  458                                         c->loc.pos = oldpos;
  459                                         c->loc.size = 0;
  460                                         c->loc.count = 0;
  461                                 } else {
  462                                         DPRINTFN(0, "Cannot pop "
  463                                             "item @ %d\n", s->pushlevel);
  464                                 }
  465                                 break;
  466                         default:
  467                                 DPRINTFN(0, "Global bTag=%d\n", bTag);
  468                                 break;
  469                         }
  470                         break;
  471                 case 2:         /* Local */
  472                         switch (bTag) {
  473                         case 0:
  474                                 if (bSize != 4)
  475                                         dval = (dval & mask) | c->_usage_page;
  476 
  477                                 /* set last usage, in case of a collection */
  478                                 s->usage_last = dval;
  479 
  480                                 if (s->nusage < MAXUSAGE) {
  481                                         s->usages_min[s->nusage] = dval;
  482                                         s->usages_max[s->nusage] = dval;
  483                                         s->nusage ++;
  484                                 } else {
  485                                         DPRINTFN(0, "max usage reached\n");
  486                                 }
  487 
  488                                 /* clear any pending usage sets */
  489                                 s->susage = 0;
  490                                 break;
  491                         case 1:
  492                                 s->susage |= 1;
  493 
  494                                 if (bSize != 4)
  495                                         dval = (dval & mask) | c->_usage_page;
  496                                 c->usage_minimum = dval;
  497 
  498                                 goto check_set;
  499                         case 2:
  500                                 s->susage |= 2;
  501 
  502                                 if (bSize != 4)
  503                                         dval = (dval & mask) | c->_usage_page;
  504                                 c->usage_maximum = dval;
  505 
  506                         check_set:
  507                                 if (s->susage != 3)
  508                                         break;
  509 
  510                                 /* sanity check */
  511                                 if ((s->nusage < MAXUSAGE) &&
  512                                     (c->usage_minimum <= c->usage_maximum)) {
  513                                         /* add usage range */
  514                                         s->usages_min[s->nusage] = 
  515                                             c->usage_minimum;
  516                                         s->usages_max[s->nusage] = 
  517                                             c->usage_maximum;
  518                                         s->nusage ++;
  519                                 } else {
  520                                         DPRINTFN(0, "Usage set dropped\n");
  521                                 }
  522                                 s->susage = 0;
  523                                 break;
  524                         case 3:
  525                                 c->designator_index = dval;
  526                                 break;
  527                         case 4:
  528                                 c->designator_minimum = dval;
  529                                 break;
  530                         case 5:
  531                                 c->designator_maximum = dval;
  532                                 break;
  533                         case 7:
  534                                 c->string_index = dval;
  535                                 break;
  536                         case 8:
  537                                 c->string_minimum = dval;
  538                                 break;
  539                         case 9:
  540                                 c->string_maximum = dval;
  541                                 break;
  542                         case 10:
  543                                 c->set_delimiter = dval;
  544                                 break;
  545                         default:
  546                                 DPRINTFN(0, "Local bTag=%d\n", bTag);
  547                                 break;
  548                         }
  549                         break;
  550                 default:
  551                         DPRINTFN(0, "default bType=%d\n", bType);
  552                         break;
  553                 }
  554         }
  555         return (0);
  556 }
  557 
  558 /*------------------------------------------------------------------------*
  559  *      hid_report_size
  560  *------------------------------------------------------------------------*/
  561 int
  562 hid_report_size(const void *buf, usb_size_t len, enum hid_kind k, uint8_t *id)
  563 {
  564         struct hid_data *d;
  565         struct hid_item h;
  566         uint32_t temp;
  567         uint32_t hpos;
  568         uint32_t lpos;
  569         uint8_t any_id;
  570 
  571         any_id = 0;
  572         hpos = 0;
  573         lpos = 0xFFFFFFFF;
  574 
  575         for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
  576                 if (h.kind == k) {
  577                         /* check for ID-byte presense */
  578                         if ((h.report_ID != 0) && !any_id) {
  579                                 if (id != NULL)
  580                                         *id = h.report_ID;
  581                                 any_id = 1;
  582                         }
  583                         /* compute minimum */
  584                         if (lpos > h.loc.pos)
  585                                 lpos = h.loc.pos;
  586                         /* compute end position */
  587                         temp = h.loc.pos + (h.loc.size * h.loc.count);
  588                         /* compute maximum */
  589                         if (hpos < temp)
  590                                 hpos = temp;
  591                 }
  592         }
  593         hid_end_parse(d);
  594 
  595         /* safety check - can happen in case of currupt descriptors */
  596         if (lpos > hpos)
  597                 temp = 0;
  598         else
  599                 temp = hpos - lpos;
  600 
  601         /* check for ID byte */
  602         if (any_id)
  603                 temp += 8;
  604         else if (id != NULL)
  605                 *id = 0;
  606 
  607         /* return length in bytes rounded up */
  608         return ((temp + 7) / 8);
  609 }
  610 
  611 /*------------------------------------------------------------------------*
  612  *      hid_locate
  613  *------------------------------------------------------------------------*/
  614 int
  615 hid_locate(const void *desc, usb_size_t size, uint32_t u, enum hid_kind k,
  616     uint8_t index, struct hid_location *loc, uint32_t *flags, uint8_t *id)
  617 {
  618         struct hid_data *d;
  619         struct hid_item h;
  620 
  621         for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) {
  622                 if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) {
  623                         if (index--)
  624                                 continue;
  625                         if (loc != NULL)
  626                                 *loc = h.loc;
  627                         if (flags != NULL)
  628                                 *flags = h.flags;
  629                         if (id != NULL)
  630                                 *id = h.report_ID;
  631                         hid_end_parse(d);
  632                         return (1);
  633                 }
  634         }
  635         if (loc != NULL)
  636                 loc->size = 0;
  637         if (flags != NULL)
  638                 *flags = 0;
  639         if (id != NULL)
  640                 *id = 0;
  641         hid_end_parse(d);
  642         return (0);
  643 }
  644 
  645 /*------------------------------------------------------------------------*
  646  *      hid_get_data
  647  *------------------------------------------------------------------------*/
  648 static uint32_t
  649 hid_get_data_sub(const uint8_t *buf, usb_size_t len, struct hid_location *loc,
  650     int is_signed)
  651 {
  652         uint32_t hpos = loc->pos;
  653         uint32_t hsize = loc->size;
  654         uint32_t data;
  655         uint32_t rpos;
  656         uint8_t n;
  657 
  658         DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize);
  659 
  660         /* Range check and limit */
  661         if (hsize == 0)
  662                 return (0);
  663         if (hsize > 32)
  664                 hsize = 32;
  665 
  666         /* Get data in a safe way */    
  667         data = 0;
  668         rpos = (hpos / 8);
  669         n = (hsize + 7) / 8;
  670         rpos += n;
  671         while (n--) {
  672                 rpos--;
  673                 if (rpos < len)
  674                         data |= buf[rpos] << (8 * n);
  675         }
  676 
  677         /* Correctly shift down data */
  678         data = (data >> (hpos % 8));
  679         n = 32 - hsize;
  680 
  681         /* Mask and sign extend in one */
  682         if (is_signed != 0)
  683                 data = (int32_t)((int32_t)data << n) >> n;
  684         else
  685                 data = (uint32_t)((uint32_t)data << n) >> n;
  686 
  687         DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n",
  688             loc->pos, loc->size, (long)data);
  689         return (data);
  690 }
  691 
  692 int32_t
  693 hid_get_data(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
  694 {
  695         return (hid_get_data_sub(buf, len, loc, 1));
  696 }
  697 
  698 uint32_t
  699 hid_get_data_unsigned(const uint8_t *buf, usb_size_t len, struct hid_location *loc)
  700 {
  701         return (hid_get_data_sub(buf, len, loc, 0));
  702 }
  703 
  704 /*------------------------------------------------------------------------*
  705  *      hid_put_data
  706  *------------------------------------------------------------------------*/
  707 void
  708 hid_put_data_unsigned(uint8_t *buf, usb_size_t len,
  709     struct hid_location *loc, unsigned int value)
  710 {
  711         uint32_t hpos = loc->pos;
  712         uint32_t hsize = loc->size;
  713         uint64_t data;
  714         uint64_t mask;
  715         uint32_t rpos;
  716         uint8_t n;
  717 
  718         DPRINTFN(11, "hid_put_data: loc %d/%d = %u\n", hpos, hsize, value);
  719 
  720         /* Range check and limit */
  721         if (hsize == 0)
  722                 return;
  723         if (hsize > 32)
  724                 hsize = 32;
  725 
  726         /* Put data in a safe way */    
  727         rpos = (hpos / 8);
  728         n = (hsize + 7) / 8;
  729         data = ((uint64_t)value) << (hpos % 8);
  730         mask = ((1ULL << hsize) - 1ULL) << (hpos % 8);
  731         rpos += n;
  732         while (n--) {
  733                 rpos--;
  734                 if (rpos < len) {
  735                         buf[rpos] &= ~(mask >> (8 * n));
  736                         buf[rpos] |= (data >> (8 * n));
  737                 }
  738         }
  739 }
  740 
  741 /*------------------------------------------------------------------------*
  742  *      hid_is_collection
  743  *------------------------------------------------------------------------*/
  744 int
  745 hid_is_collection(const void *desc, usb_size_t size, uint32_t usage)
  746 {
  747         struct hid_data *hd;
  748         struct hid_item hi;
  749         int err;
  750 
  751         hd = hid_start_parse(desc, size, hid_input);
  752         if (hd == NULL)
  753                 return (0);
  754 
  755         while ((err = hid_get_item(hd, &hi))) {
  756                  if (hi.kind == hid_collection &&
  757                      hi.usage == usage)
  758                         break;
  759         }
  760         hid_end_parse(hd);
  761         return (err);
  762 }
  763 
  764 /*------------------------------------------------------------------------*
  765  *      hid_get_descriptor_from_usb
  766  *
  767  * This function will search for a HID descriptor between two USB
  768  * interface descriptors.
  769  *
  770  * Return values:
  771  * NULL: No more HID descriptors.
  772  * Else: Pointer to HID descriptor.
  773  *------------------------------------------------------------------------*/
  774 struct usb_hid_descriptor *
  775 hid_get_descriptor_from_usb(struct usb_config_descriptor *cd,
  776     struct usb_interface_descriptor *id)
  777 {
  778         struct usb_descriptor *desc = (void *)id;
  779 
  780         if (desc == NULL) {
  781                 return (NULL);
  782         }
  783         while ((desc = usb_desc_foreach(cd, desc))) {
  784                 if ((desc->bDescriptorType == UDESC_HID) &&
  785                     (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) {
  786                         return (void *)desc;
  787                 }
  788                 if (desc->bDescriptorType == UDESC_INTERFACE) {
  789                         break;
  790                 }
  791         }
  792         return (NULL);
  793 }
  794 
  795 /*------------------------------------------------------------------------*
  796  *      usbd_req_get_hid_desc
  797  *
  798  * This function will read out an USB report descriptor from the USB
  799  * device.
  800  *
  801  * Return values:
  802  * NULL: Failure.
  803  * Else: Success. The pointer should eventually be passed to free().
  804  *------------------------------------------------------------------------*/
  805 usb_error_t
  806 usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
  807     void **descp, uint16_t *sizep,
  808     struct malloc_type *mem, uint8_t iface_index)
  809 {
  810         struct usb_interface *iface = usbd_get_iface(udev, iface_index);
  811         struct usb_hid_descriptor *hid;
  812         usb_error_t err;
  813 
  814         if ((iface == NULL) || (iface->idesc == NULL)) {
  815                 return (USB_ERR_INVAL);
  816         }
  817         hid = hid_get_descriptor_from_usb
  818             (usbd_get_config_descriptor(udev), iface->idesc);
  819 
  820         if (hid == NULL) {
  821                 return (USB_ERR_IOERROR);
  822         }
  823         *sizep = UGETW(hid->descrs[0].wDescriptorLength);
  824         if (*sizep == 0) {
  825                 return (USB_ERR_IOERROR);
  826         }
  827         if (mtx)
  828                 mtx_unlock(mtx);
  829 
  830         *descp = malloc(*sizep, mem, M_ZERO | M_WAITOK);
  831 
  832         if (mtx)
  833                 mtx_lock(mtx);
  834 
  835         if (*descp == NULL) {
  836                 return (USB_ERR_NOMEM);
  837         }
  838         err = usbd_req_get_report_descriptor
  839             (udev, mtx, *descp, *sizep, iface_index);
  840 
  841         if (err) {
  842                 free(*descp, mem);
  843                 *descp = NULL;
  844                 return (err);
  845         }
  846         return (USB_ERR_NORMAL_COMPLETION);
  847 }

Cache object: 1de14e547fc02adbad6567ccb0de32a9


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