Home | History | Annotate | Line # | Download | only in hid
hid.c revision 1.1.2.2
      1  1.1.2.2  pgoyette /*	$NetBSD: hid.c,v 1.1.2.2 2018/11/26 01:52:31 pgoyette Exp $	*/
      2      1.1    bouyer /*	$FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
      3      1.1    bouyer 
      4      1.1    bouyer /*
      5      1.1    bouyer  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      6      1.1    bouyer  * All rights reserved.
      7      1.1    bouyer  *
      8      1.1    bouyer  * This code is derived from software contributed to The NetBSD Foundation
      9      1.1    bouyer  * by Lennart Augustsson (lennart (at) augustsson.net) at
     10      1.1    bouyer  * Carlstedt Research & Technology.
     11      1.1    bouyer  *
     12      1.1    bouyer  * Redistribution and use in source and binary forms, with or without
     13      1.1    bouyer  * modification, are permitted provided that the following conditions
     14      1.1    bouyer  * are met:
     15      1.1    bouyer  * 1. Redistributions of source code must retain the above copyright
     16      1.1    bouyer  *    notice, this list of conditions and the following disclaimer.
     17      1.1    bouyer  * 2. Redistributions in binary form must reproduce the above copyright
     18      1.1    bouyer  *    notice, this list of conditions and the following disclaimer in the
     19      1.1    bouyer  *    documentation and/or other materials provided with the distribution.
     20      1.1    bouyer  *
     21      1.1    bouyer  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22      1.1    bouyer  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23      1.1    bouyer  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24      1.1    bouyer  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25      1.1    bouyer  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26      1.1    bouyer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27      1.1    bouyer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28      1.1    bouyer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29      1.1    bouyer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30      1.1    bouyer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31      1.1    bouyer  * POSSIBILITY OF SUCH DAMAGE.
     32      1.1    bouyer  */
     33      1.1    bouyer 
     34      1.1    bouyer #include <sys/cdefs.h>
     35  1.1.2.2  pgoyette __KERNEL_RCSID(0, "$NetBSD: hid.c,v 1.1.2.2 2018/11/26 01:52:31 pgoyette Exp $");
     36      1.1    bouyer 
     37      1.1    bouyer #ifdef _KERNEL_OPT
     38      1.1    bouyer #include "opt_usb.h"
     39      1.1    bouyer #endif
     40      1.1    bouyer 
     41      1.1    bouyer #include <sys/param.h>
     42      1.1    bouyer #include <sys/systm.h>
     43      1.1    bouyer #include <sys/kernel.h>
     44      1.1    bouyer #include <sys/kmem.h>
     45      1.1    bouyer 
     46      1.1    bouyer #include <dev/usb/usb.h>
     47      1.1    bouyer #include <dev/usb/usbhid.h>
     48      1.1    bouyer 
     49      1.1    bouyer #include <dev/hid/hid.h>
     50      1.1    bouyer 
     51      1.1    bouyer #ifdef UHIDEV_DEBUG
     52      1.1    bouyer #define DPRINTF(x)	if (uhidevdebug) printf x
     53      1.1    bouyer #define DPRINTFN(n,x)	if (uhidevdebug>(n)) printf x
     54      1.1    bouyer extern int uhidevdebug;
     55      1.1    bouyer #else
     56      1.1    bouyer #define DPRINTF(x)
     57      1.1    bouyer #define DPRINTFN(n,x)
     58      1.1    bouyer #endif
     59      1.1    bouyer 
     60      1.1    bouyer Static void hid_clear_local(struct hid_item *);
     61      1.1    bouyer 
     62      1.1    bouyer #define MAXUSAGE 256
     63      1.1    bouyer struct hid_data {
     64      1.1    bouyer 	const u_char *start;
     65      1.1    bouyer 	const u_char *end;
     66      1.1    bouyer 	const u_char *p;
     67      1.1    bouyer 	struct hid_item cur;
     68      1.1    bouyer 	int32_t usages[MAXUSAGE];
     69      1.1    bouyer 	int nu;
     70      1.1    bouyer 	int minset;
     71      1.1    bouyer 	int multi;
     72      1.1    bouyer 	int multimax;
     73      1.1    bouyer 	enum hid_kind kind;
     74      1.1    bouyer };
     75      1.1    bouyer 
     76      1.1    bouyer Static void
     77      1.1    bouyer hid_clear_local(struct hid_item *c)
     78      1.1    bouyer {
     79      1.1    bouyer 
     80      1.1    bouyer 	DPRINTFN(5,("hid_clear_local\n"));
     81      1.1    bouyer 	c->usage = 0;
     82      1.1    bouyer 	c->usage_minimum = 0;
     83      1.1    bouyer 	c->usage_maximum = 0;
     84      1.1    bouyer 	c->designator_index = 0;
     85      1.1    bouyer 	c->designator_minimum = 0;
     86      1.1    bouyer 	c->designator_maximum = 0;
     87      1.1    bouyer 	c->string_index = 0;
     88      1.1    bouyer 	c->string_minimum = 0;
     89      1.1    bouyer 	c->string_maximum = 0;
     90      1.1    bouyer 	c->set_delimiter = 0;
     91      1.1    bouyer }
     92      1.1    bouyer 
     93      1.1    bouyer struct hid_data *
     94      1.1    bouyer hid_start_parse(const void *d, int len, enum hid_kind kind)
     95      1.1    bouyer {
     96      1.1    bouyer 	struct hid_data *s;
     97      1.1    bouyer 
     98      1.1    bouyer 	s = kmem_zalloc(sizeof(*s), KM_SLEEP);
     99      1.1    bouyer 	s->start = s->p = d;
    100      1.1    bouyer 	s->end = (const char *)d + len;
    101      1.1    bouyer 	s->kind = kind;
    102      1.1    bouyer 	return s;
    103      1.1    bouyer }
    104      1.1    bouyer 
    105      1.1    bouyer void
    106      1.1    bouyer hid_end_parse(struct hid_data *s)
    107      1.1    bouyer {
    108      1.1    bouyer 
    109      1.1    bouyer 	while (s->cur.next != NULL) {
    110      1.1    bouyer 		struct hid_item *hi = s->cur.next->next;
    111      1.1    bouyer 		kmem_free(s->cur.next, sizeof(*s->cur.next));
    112      1.1    bouyer 		s->cur.next = hi;
    113      1.1    bouyer 	}
    114      1.1    bouyer 	kmem_free(s, sizeof(*s));
    115      1.1    bouyer }
    116      1.1    bouyer 
    117      1.1    bouyer int
    118      1.1    bouyer hid_get_item(struct hid_data *s, struct hid_item *h)
    119      1.1    bouyer {
    120      1.1    bouyer 	struct hid_item *c = &s->cur;
    121      1.1    bouyer 	unsigned int bTag, bType, bSize;
    122      1.1    bouyer 	uint32_t oldpos;
    123      1.1    bouyer 	const u_char *data;
    124      1.1    bouyer 	int32_t dval;
    125  1.1.2.2  pgoyette 	uint32_t uval;
    126      1.1    bouyer 	const u_char *p;
    127      1.1    bouyer 	struct hid_item *hi;
    128      1.1    bouyer 	int i;
    129      1.1    bouyer 	enum hid_kind retkind;
    130      1.1    bouyer 
    131      1.1    bouyer  top:
    132      1.1    bouyer 	DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n",
    133      1.1    bouyer 		    s->multi, s->multimax));
    134      1.1    bouyer 	if (s->multimax != 0) {
    135      1.1    bouyer 		if (s->multi < s->multimax) {
    136  1.1.2.1  pgoyette 			c->usage = s->usages[uimin(s->multi, s->nu-1)];
    137      1.1    bouyer 			s->multi++;
    138      1.1    bouyer 			*h = *c;
    139      1.1    bouyer 			c->loc.pos += c->loc.size;
    140      1.1    bouyer 			h->next = NULL;
    141      1.1    bouyer 			DPRINTFN(5,("return multi\n"));
    142      1.1    bouyer 			return 1;
    143      1.1    bouyer 		} else {
    144      1.1    bouyer 			c->loc.count = s->multimax;
    145      1.1    bouyer 			s->multimax = 0;
    146      1.1    bouyer 			s->nu = 0;
    147      1.1    bouyer 			hid_clear_local(c);
    148      1.1    bouyer 		}
    149      1.1    bouyer 	}
    150      1.1    bouyer 	for (;;) {
    151      1.1    bouyer 		p = s->p;
    152      1.1    bouyer 		if (p >= s->end)
    153      1.1    bouyer 			return 0;
    154      1.1    bouyer 
    155      1.1    bouyer 		bSize = *p++;
    156      1.1    bouyer 		if (bSize == 0xfe) {
    157      1.1    bouyer 			/* long item */
    158      1.1    bouyer 			bSize = *p++;
    159      1.1    bouyer 			bSize |= *p++ << 8;
    160      1.1    bouyer 			bTag = *p++;
    161      1.1    bouyer 			data = p;
    162      1.1    bouyer 			p += bSize;
    163      1.1    bouyer 			bType = 0xff; /* XXX what should it be */
    164      1.1    bouyer 		} else {
    165      1.1    bouyer 			/* short item */
    166      1.1    bouyer 			bTag = bSize >> 4;
    167      1.1    bouyer 			bType = (bSize >> 2) & 3;
    168      1.1    bouyer 			bSize &= 3;
    169      1.1    bouyer 			if (bSize == 3) bSize = 4;
    170      1.1    bouyer 			data = p;
    171      1.1    bouyer 			p += bSize;
    172      1.1    bouyer 		}
    173      1.1    bouyer 		s->p = p;
    174      1.1    bouyer 		switch(bSize) {
    175      1.1    bouyer 		case 0:
    176      1.1    bouyer 			dval = 0;
    177  1.1.2.2  pgoyette 			uval = dval;
    178      1.1    bouyer 			break;
    179      1.1    bouyer 		case 1:
    180  1.1.2.2  pgoyette 			dval = *data++;
    181  1.1.2.2  pgoyette 			uval = dval;
    182  1.1.2.2  pgoyette 			dval = (int8_t)dval;
    183      1.1    bouyer 			break;
    184      1.1    bouyer 		case 2:
    185      1.1    bouyer 			dval = *data++;
    186      1.1    bouyer 			dval |= *data++ << 8;
    187  1.1.2.2  pgoyette 			uval = dval;
    188      1.1    bouyer 			dval = (int16_t)dval;
    189      1.1    bouyer 			break;
    190      1.1    bouyer 		case 4:
    191      1.1    bouyer 			dval = *data++;
    192      1.1    bouyer 			dval |= *data++ << 8;
    193      1.1    bouyer 			dval |= *data++ << 16;
    194      1.1    bouyer 			dval |= *data++ << 24;
    195  1.1.2.2  pgoyette 			uval = dval;
    196      1.1    bouyer 			dval = (int32_t)dval;
    197      1.1    bouyer 			break;
    198      1.1    bouyer 		default:
    199      1.1    bouyer 			aprint_normal("BAD LENGTH %d\n", bSize);
    200      1.1    bouyer 			continue;
    201      1.1    bouyer 		}
    202      1.1    bouyer 
    203  1.1.2.2  pgoyette 		DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d uval=%u\n",
    204  1.1.2.2  pgoyette 			 bType, bTag, dval, uval));
    205      1.1    bouyer 		switch (bType) {
    206      1.1    bouyer 		case 0:			/* Main */
    207      1.1    bouyer 			switch (bTag) {
    208      1.1    bouyer 			case 8:		/* Input */
    209      1.1    bouyer 				retkind = hid_input;
    210      1.1    bouyer 			ret:
    211      1.1    bouyer 				if (s->kind != retkind) {
    212      1.1    bouyer 					s->minset = 0;
    213      1.1    bouyer 					s->nu = 0;
    214      1.1    bouyer 					hid_clear_local(c);
    215      1.1    bouyer 					continue;
    216      1.1    bouyer 				}
    217      1.1    bouyer 				c->kind = retkind;
    218  1.1.2.2  pgoyette 				c->flags = uval;
    219      1.1    bouyer 				if (c->flags & HIO_VARIABLE) {
    220      1.1    bouyer 					s->multimax = c->loc.count;
    221      1.1    bouyer 					s->multi = 0;
    222      1.1    bouyer 					c->loc.count = 1;
    223      1.1    bouyer 					if (s->minset) {
    224      1.1    bouyer 						for (i = c->usage_minimum;
    225      1.1    bouyer 						     i <= c->usage_maximum;
    226      1.1    bouyer 						     i++) {
    227      1.1    bouyer 							s->usages[s->nu] = i;
    228      1.1    bouyer 							if (s->nu < MAXUSAGE-1)
    229      1.1    bouyer 								s->nu++;
    230      1.1    bouyer 						}
    231      1.1    bouyer 						s->minset = 0;
    232      1.1    bouyer 					}
    233      1.1    bouyer 					goto top;
    234      1.1    bouyer 				} else {
    235      1.1    bouyer 					if (s->minset)
    236      1.1    bouyer 						c->usage = c->usage_minimum;
    237      1.1    bouyer 					*h = *c;
    238      1.1    bouyer 					h->next = NULL;
    239      1.1    bouyer 					c->loc.pos +=
    240      1.1    bouyer 					    c->loc.size * c->loc.count;
    241      1.1    bouyer 					s->minset = 0;
    242      1.1    bouyer 					s->nu = 0;
    243      1.1    bouyer 					hid_clear_local(c);
    244      1.1    bouyer 					return 1;
    245      1.1    bouyer 				}
    246      1.1    bouyer 			case 9:		/* Output */
    247      1.1    bouyer 				retkind = hid_output;
    248      1.1    bouyer 				goto ret;
    249      1.1    bouyer 			case 10:	/* Collection */
    250      1.1    bouyer 				c->kind = hid_collection;
    251  1.1.2.2  pgoyette 				c->collection = uval;
    252      1.1    bouyer 				c->collevel++;
    253      1.1    bouyer 				*h = *c;
    254      1.1    bouyer 				hid_clear_local(c);
    255      1.1    bouyer 				s->nu = 0;
    256      1.1    bouyer 				return 1;
    257      1.1    bouyer 			case 11:	/* Feature */
    258      1.1    bouyer 				retkind = hid_feature;
    259      1.1    bouyer 				goto ret;
    260      1.1    bouyer 			case 12:	/* End collection */
    261      1.1    bouyer 				c->kind = hid_endcollection;
    262      1.1    bouyer 				c->collevel--;
    263      1.1    bouyer 				*h = *c;
    264      1.1    bouyer 				s->nu = 0;
    265      1.1    bouyer 				return 1;
    266      1.1    bouyer 			default:
    267      1.1    bouyer 				aprint_normal("Main bTag=%d\n", bTag);
    268      1.1    bouyer 				break;
    269      1.1    bouyer 			}
    270      1.1    bouyer 			break;
    271      1.1    bouyer 		case 1:		/* Global */
    272      1.1    bouyer 			switch (bTag) {
    273      1.1    bouyer 			case 0:
    274  1.1.2.2  pgoyette 				c->_usage_page = uval << 16;
    275      1.1    bouyer 				break;
    276      1.1    bouyer 			case 1:
    277      1.1    bouyer 				c->logical_minimum = dval;
    278      1.1    bouyer 				break;
    279      1.1    bouyer 			case 2:
    280      1.1    bouyer 				c->logical_maximum = dval;
    281      1.1    bouyer 				break;
    282      1.1    bouyer 			case 3:
    283      1.1    bouyer 				c->physical_minimum = dval;
    284      1.1    bouyer 				break;
    285      1.1    bouyer 			case 4:
    286      1.1    bouyer 				c->physical_maximum = dval;
    287      1.1    bouyer 				break;
    288      1.1    bouyer 			case 5:
    289  1.1.2.2  pgoyette 				c->unit_exponent = uval;
    290      1.1    bouyer 				break;
    291      1.1    bouyer 			case 6:
    292  1.1.2.2  pgoyette 				c->unit = uval;
    293      1.1    bouyer 				break;
    294      1.1    bouyer 			case 7:
    295  1.1.2.2  pgoyette 				c->loc.size = uval;
    296      1.1    bouyer 				break;
    297      1.1    bouyer 			case 8:
    298  1.1.2.2  pgoyette 				c->report_ID = uval;
    299      1.1    bouyer 				c->loc.pos = 0;
    300      1.1    bouyer 				break;
    301      1.1    bouyer 			case 9:
    302  1.1.2.2  pgoyette 				c->loc.count = uval;
    303      1.1    bouyer 				break;
    304      1.1    bouyer 			case 10: /* Push */
    305      1.1    bouyer 				hi = kmem_alloc(sizeof(*hi), KM_SLEEP);
    306      1.1    bouyer 				*hi = *c;
    307      1.1    bouyer 				c->next = hi;
    308      1.1    bouyer 				break;
    309      1.1    bouyer 			case 11: /* Pop */
    310      1.1    bouyer 				hi = c->next;
    311      1.1    bouyer 				if (hi == NULL)
    312      1.1    bouyer 					break;
    313      1.1    bouyer 				oldpos = c->loc.pos;
    314      1.1    bouyer 				*c = *hi;
    315      1.1    bouyer 				c->loc.pos = oldpos;
    316      1.1    bouyer 				kmem_free(hi, sizeof(*hi));
    317      1.1    bouyer 				break;
    318      1.1    bouyer 			default:
    319      1.1    bouyer 				aprint_normal("Global bTag=%d\n", bTag);
    320      1.1    bouyer 				break;
    321      1.1    bouyer 			}
    322      1.1    bouyer 			break;
    323      1.1    bouyer 		case 2:		/* Local */
    324      1.1    bouyer 			switch (bTag) {
    325      1.1    bouyer 			case 0:
    326  1.1.2.2  pgoyette 				if (bSize < 4)
    327  1.1.2.2  pgoyette 					uval = c->_usage_page | uval;
    328  1.1.2.2  pgoyette 				c->usage = uval;
    329      1.1    bouyer 				if (s->nu < MAXUSAGE)
    330  1.1.2.2  pgoyette 					s->usages[s->nu++] = uval;
    331      1.1    bouyer 				/* else XXX */
    332      1.1    bouyer 				break;
    333      1.1    bouyer 			case 1:
    334      1.1    bouyer 				s->minset = 1;
    335  1.1.2.2  pgoyette 				if (bSize < 4)
    336  1.1.2.2  pgoyette 					uval = c->_usage_page | uval;
    337  1.1.2.2  pgoyette 				c->usage_minimum = uval;
    338      1.1    bouyer 				break;
    339      1.1    bouyer 			case 2:
    340  1.1.2.2  pgoyette 				if (bSize < 4)
    341  1.1.2.2  pgoyette 					uval = c->_usage_page | uval;
    342  1.1.2.2  pgoyette 				c->usage_maximum = uval;
    343      1.1    bouyer 				break;
    344      1.1    bouyer 			case 3:
    345  1.1.2.2  pgoyette 				c->designator_index = uval;
    346      1.1    bouyer 				break;
    347      1.1    bouyer 			case 4:
    348  1.1.2.2  pgoyette 				c->designator_minimum = uval;
    349      1.1    bouyer 				break;
    350      1.1    bouyer 			case 5:
    351  1.1.2.2  pgoyette 				c->designator_maximum = uval;
    352      1.1    bouyer 				break;
    353      1.1    bouyer 			case 7:
    354  1.1.2.2  pgoyette 				c->string_index = uval;
    355      1.1    bouyer 				break;
    356      1.1    bouyer 			case 8:
    357  1.1.2.2  pgoyette 				c->string_minimum = uval;
    358      1.1    bouyer 				break;
    359      1.1    bouyer 			case 9:
    360  1.1.2.2  pgoyette 				c->string_maximum = uval;
    361      1.1    bouyer 				break;
    362      1.1    bouyer 			case 10:
    363  1.1.2.2  pgoyette 				c->set_delimiter = uval;
    364      1.1    bouyer 				break;
    365      1.1    bouyer 			default:
    366      1.1    bouyer 				aprint_normal("Local bTag=%d\n", bTag);
    367      1.1    bouyer 				break;
    368      1.1    bouyer 			}
    369      1.1    bouyer 			break;
    370      1.1    bouyer 		default:
    371      1.1    bouyer 			aprint_normal("default bType=%d\n", bType);
    372      1.1    bouyer 			break;
    373      1.1    bouyer 		}
    374      1.1    bouyer 	}
    375      1.1    bouyer }
    376      1.1    bouyer 
    377      1.1    bouyer int
    378      1.1    bouyer hid_report_size(const void *buf, int len, enum hid_kind k, uint8_t id)
    379      1.1    bouyer {
    380      1.1    bouyer 	struct hid_data *d;
    381      1.1    bouyer 	struct hid_item h;
    382      1.1    bouyer 	int lo, hi;
    383      1.1    bouyer 
    384      1.1    bouyer 	h.report_ID = 0;
    385      1.1    bouyer 	lo = hi = -1;
    386      1.1    bouyer 	DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id));
    387      1.1    bouyer 	for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
    388      1.1    bouyer 		DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d "
    389      1.1    bouyer 			    "size=%d count=%d\n",
    390      1.1    bouyer 			    h.kind, h.report_ID, h.loc.pos, h.loc.size,
    391      1.1    bouyer 			    h.loc.count));
    392      1.1    bouyer 		if (h.report_ID == id && h.kind == k) {
    393      1.1    bouyer 			if (lo < 0) {
    394      1.1    bouyer 				lo = h.loc.pos;
    395      1.1    bouyer #ifdef DIAGNOSTIC
    396      1.1    bouyer 				if (lo != 0) {
    397      1.1    bouyer 					aprint_normal("hid_report_size:"
    398      1.1    bouyer 					   " lo != 0\n");
    399      1.1    bouyer 				}
    400      1.1    bouyer #endif
    401      1.1    bouyer 			}
    402      1.1    bouyer 			hi = h.loc.pos + h.loc.size * h.loc.count;
    403      1.1    bouyer 			DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi));
    404      1.1    bouyer 		}
    405      1.1    bouyer 	}
    406      1.1    bouyer 	hid_end_parse(d);
    407      1.1    bouyer 	return (hi - lo + 7) / 8;
    408      1.1    bouyer }
    409      1.1    bouyer 
    410      1.1    bouyer int
    411      1.1    bouyer hid_locate(const void *desc, int size, uint32_t u, uint8_t id, enum hid_kind k,
    412      1.1    bouyer 	   struct hid_location *loc, uint32_t *flags)
    413      1.1    bouyer {
    414      1.1    bouyer 	struct hid_data *d;
    415      1.1    bouyer 	struct hid_item h;
    416      1.1    bouyer 
    417      1.1    bouyer 	h.report_ID = 0;
    418      1.1    bouyer 	DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id));
    419      1.1    bouyer 	for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
    420      1.1    bouyer 		DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
    421      1.1    bouyer 			    h.usage, h.kind, h.report_ID, h.flags));
    422      1.1    bouyer 		if (h.kind == k && !(h.flags & HIO_CONST) &&
    423      1.1    bouyer 		    h.usage == u && h.report_ID == id) {
    424      1.1    bouyer 			if (loc != NULL)
    425      1.1    bouyer 				*loc = h.loc;
    426      1.1    bouyer 			if (flags != NULL)
    427      1.1    bouyer 				*flags = h.flags;
    428      1.1    bouyer 			hid_end_parse(d);
    429      1.1    bouyer 			return 1;
    430      1.1    bouyer 		}
    431      1.1    bouyer 	}
    432      1.1    bouyer 	hid_end_parse(d);
    433      1.1    bouyer 	if (loc != NULL)
    434      1.1    bouyer 		loc->size = 0;
    435      1.1    bouyer 	return 0;
    436      1.1    bouyer }
    437      1.1    bouyer 
    438      1.1    bouyer long
    439      1.1    bouyer hid_get_data(const u_char *buf, const struct hid_location *loc)
    440      1.1    bouyer {
    441      1.1    bouyer 	u_int hsize = loc->size;
    442      1.1    bouyer 	u_long data;
    443      1.1    bouyer 
    444      1.1    bouyer 	if (hsize == 0)
    445      1.1    bouyer 		return 0;
    446      1.1    bouyer 
    447      1.1    bouyer 	data = hid_get_udata(buf, loc);
    448      1.1    bouyer 	if (data < (1UL << (hsize - 1)) || hsize == sizeof(data) * NBBY)
    449      1.1    bouyer 		return data;
    450      1.1    bouyer 	return data - (1UL << hsize);
    451      1.1    bouyer }
    452      1.1    bouyer 
    453      1.1    bouyer u_long
    454      1.1    bouyer hid_get_udata(const u_char *buf, const struct hid_location *loc)
    455      1.1    bouyer {
    456      1.1    bouyer 	u_int hpos = loc->pos;
    457      1.1    bouyer 	u_int hsize = loc->size;
    458      1.1    bouyer 	u_int i, num, off;
    459      1.1    bouyer 	u_long data;
    460      1.1    bouyer 
    461      1.1    bouyer 	if (hsize == 0)
    462      1.1    bouyer 		return 0;
    463      1.1    bouyer 
    464      1.1    bouyer 	data = 0;
    465      1.1    bouyer 	off = hpos / 8;
    466      1.1    bouyer 	num = (hpos + hsize + 7) / 8 - off;
    467      1.1    bouyer 
    468      1.1    bouyer 	for (i = 0; i < num; i++)
    469      1.1    bouyer 		data |= (unsigned long)buf[off + i] << (i * 8);
    470      1.1    bouyer 
    471      1.1    bouyer 	data >>= hpos % 8;
    472      1.1    bouyer 	if (hsize < sizeof(data) * NBBY)
    473      1.1    bouyer 		data &= (1UL << hsize) - 1;
    474      1.1    bouyer 
    475      1.1    bouyer 	DPRINTFN(10,("hid_get_udata: loc %d/%d = %lu\n", hpos, hsize, data));
    476      1.1    bouyer 	return data;
    477      1.1    bouyer }
    478      1.1    bouyer 
    479      1.1    bouyer /*
    480      1.1    bouyer  * hid_is_collection(desc, size, id, usage)
    481      1.1    bouyer  *
    482      1.1    bouyer  * This function is broken in the following way.
    483      1.1    bouyer  *
    484      1.1    bouyer  * It is used to discover if the given 'id' is part of 'usage' collection
    485      1.1    bouyer  * in the descriptor in order to match report id against device type.
    486      1.1    bouyer  *
    487      1.1    bouyer  * The semantics of hid_start_parse() means though, that only a single
    488      1.1    bouyer  * kind of report is considered. The current HID code that uses this for
    489      1.1    bouyer  * matching is actually only looking for input reports, so this works
    490      1.1    bouyer  * for now.
    491      1.1    bouyer  *
    492      1.1    bouyer  * This function could try all report kinds (input, output and feature)
    493      1.1    bouyer  * consecutively if necessary, but it may be better to integrate the
    494      1.1    bouyer  * libusbhid code which can consider multiple report kinds simultaneously
    495      1.1    bouyer  *
    496      1.1    bouyer  * Needs some thought.
    497      1.1    bouyer  */
    498      1.1    bouyer int
    499      1.1    bouyer hid_is_collection(const void *desc, int size, uint8_t id, uint32_t usage)
    500      1.1    bouyer {
    501      1.1    bouyer 	struct hid_data *hd;
    502      1.1    bouyer 	struct hid_item hi;
    503      1.1    bouyer 	uint32_t coll_usage = ~0;
    504      1.1    bouyer 
    505      1.1    bouyer 	hd = hid_start_parse(desc, size, hid_input);
    506      1.1    bouyer 	if (hd == NULL)
    507      1.1    bouyer 		return 0;
    508      1.1    bouyer 
    509      1.1    bouyer 	DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage));
    510      1.1    bouyer 	while (hid_get_item(hd, &hi)) {
    511      1.1    bouyer 		DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x"
    512      1.1    bouyer 			    "(0x%x)\n",
    513      1.1    bouyer 			    hi.kind, hi.report_ID, hi.usage, coll_usage));
    514      1.1    bouyer 
    515      1.1    bouyer 		if (hi.kind == hid_collection &&
    516      1.1    bouyer 		    hi.collection == HCOLL_APPLICATION)
    517      1.1    bouyer 			coll_usage = hi.usage;
    518      1.1    bouyer 
    519      1.1    bouyer 		if (hi.kind == hid_endcollection)
    520      1.1    bouyer 			coll_usage = ~0;
    521      1.1    bouyer 
    522      1.1    bouyer 		if (hi.kind == hid_input &&
    523      1.1    bouyer 		    coll_usage == usage &&
    524      1.1    bouyer 		    hi.report_ID == id) {
    525      1.1    bouyer 			DPRINTFN(2,("hid_is_collection: found\n"));
    526      1.1    bouyer 			hid_end_parse(hd);
    527      1.1    bouyer 			return 1;
    528      1.1    bouyer 		}
    529      1.1    bouyer 	}
    530      1.1    bouyer 	DPRINTFN(2,("hid_is_collection: not found\n"));
    531      1.1    bouyer 	hid_end_parse(hd);
    532      1.1    bouyer 	return 0;
    533      1.1    bouyer }
    534