1 /* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */
4 * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $FreeBSD: head/lib/libusbhid/parse.c 240762 2012-09-20 18:56:27Z mav $
36 #include <bus/u4b/usb.h>
37 #include <bus/u4b/usbhid.h>
49 uint32_t pos
[ITEMTYPES
];
56 struct hid_item cur
[MAXPUSH
];
57 struct hid_pos_data last_pos
[MAXID
];
58 uint32_t pos
[ITEMTYPES
];
59 int32_t usages_min
[MAXUSAGE
];
60 int32_t usages_max
[MAXUSAGE
];
61 int32_t usage_last
; /* last seen usage */
62 uint32_t loc_size
; /* last seen size */
63 uint32_t loc_count
; /* last seen count */
64 uint8_t kindset
; /* we have 5 kinds so 8 bits are enough */
65 uint8_t pushlevel
; /* current pushlevel */
66 uint8_t ncount
; /* end usage item count */
67 uint8_t icount
; /* current usage item count */
68 uint8_t nusage
; /* end "usages_min/max" index */
69 uint8_t iusage
; /* current "usages_min/max" index */
70 uint8_t ousage
; /* current "usages_min/max" offset */
71 uint8_t susage
; /* usage set flags */
72 int32_t reportid
; /* requested report ID */
75 /*------------------------------------------------------------------------*
77 *------------------------------------------------------------------------*/
79 hid_clear_local(hid_item_t
*c
)
85 c
->designator_index
= 0;
86 c
->designator_minimum
= 0;
87 c
->designator_maximum
= 0;
89 c
->string_minimum
= 0;
90 c
->string_maximum
= 0;
95 hid_switch_rid(struct hid_data
*s
, struct hid_item
*c
, int32_t next_rID
)
99 /* check for same report ID - optimise */
101 if (c
->report_ID
== next_rID
)
104 /* save current position for current rID */
106 if (c
->report_ID
== 0) {
109 for (i
= 1; i
!= MAXID
; i
++) {
110 if (s
->last_pos
[i
].rid
== c
->report_ID
)
112 if (s
->last_pos
[i
].rid
== 0)
117 s
->last_pos
[i
].rid
= c
->report_ID
;
118 for (j
= 0; j
< ITEMTYPES
; j
++)
119 s
->last_pos
[i
].pos
[j
] = s
->pos
[j
];
122 /* store next report ID */
124 c
->report_ID
= next_rID
;
126 /* lookup last position for next rID */
131 for (i
= 1; i
!= MAXID
; i
++) {
132 if (s
->last_pos
[i
].rid
== next_rID
)
134 if (s
->last_pos
[i
].rid
== 0)
139 s
->last_pos
[i
].rid
= next_rID
;
140 for (j
= 0; j
< ITEMTYPES
; j
++)
141 s
->pos
[j
] = s
->last_pos
[i
].pos
[j
];
143 for (j
= 0; j
< ITEMTYPES
; j
++)
144 s
->pos
[j
] = 0; /* Out of RID entries. */
148 /*------------------------------------------------------------------------*
150 *------------------------------------------------------------------------*/
152 hid_start_parse(report_desc_t d
, int kindset
, int id
)
156 s
= malloc(sizeof *s
);
157 memset(s
, 0, sizeof *s
);
158 s
->start
= s
->p
= d
->data
;
159 s
->end
= d
->data
+ d
->size
;
160 s
->kindset
= kindset
;
165 /*------------------------------------------------------------------------*
167 *------------------------------------------------------------------------*/
169 hid_end_parse(hid_data_t s
)
178 /*------------------------------------------------------------------------*
179 * get byte from HID descriptor
180 *------------------------------------------------------------------------*/
182 hid_get_byte(struct hid_data
*s
, const uint16_t wSize
)
189 /* check if end is reached */
193 /* read out a byte */
196 /* check if data pointer can be advanced by "wSize" bytes */
197 if ((s
->end
- ptr
) < wSize
)
208 /*------------------------------------------------------------------------*
210 *------------------------------------------------------------------------*/
212 hid_get_item_raw(hid_data_t s
, hid_item_t
*h
)
215 unsigned int bTag
, bType
, bSize
;
222 c
= &s
->cur
[s
->pushlevel
];
225 /* check if there is an array of items */
226 if (s
->icount
< s
->ncount
) {
227 /* get current usage */
228 if (s
->iusage
< s
->nusage
) {
229 dval
= s
->usages_min
[s
->iusage
] + s
->ousage
;
231 s
->usage_last
= dval
;
232 if (dval
== s
->usages_max
[s
->iusage
]) {
239 /* Using last usage */
240 dval
= s
->usage_last
;
244 * Only copy HID item, increment position and return
245 * if correct kindset!
247 if (s
->kindset
& (1 << c
->kind
)) {
249 h
->pos
= s
->pos
[c
->kind
];
250 s
->pos
[c
->kind
] += c
->report_size
* c
->report_count
;
255 /* reset state variables */
265 while (s
->p
!= s
->end
) {
267 bSize
= hid_get_byte(s
, 1);
270 bSize
= hid_get_byte(s
, 1);
271 bSize
|= hid_get_byte(s
, 1) << 8;
272 bTag
= hid_get_byte(s
, 1);
273 bType
= 0xff; /* XXX what should it be */
277 bType
= (bSize
>> 2) & 3;
289 dval
= (int8_t)hid_get_byte(s
, 1);
293 dval
= hid_get_byte(s
, 1);
294 dval
|= hid_get_byte(s
, 1) << 8;
295 dval
= (int16_t)dval
;
299 dval
= hid_get_byte(s
, 1);
300 dval
|= hid_get_byte(s
, 1) << 8;
301 dval
|= hid_get_byte(s
, 1) << 16;
302 dval
|= hid_get_byte(s
, 1) << 24;
306 dval
= hid_get_byte(s
, bSize
);
317 c
->report_count
= s
->loc_count
;
318 c
->report_size
= s
->loc_size
;
320 if (c
->flags
& HIO_VARIABLE
) {
321 /* range check usage count */
322 if (c
->report_count
> 255) {
325 s
->ncount
= c
->report_count
;
328 * The "top" loop will return
332 c
->usage_minimum
= 0;
333 c
->usage_maximum
= 0;
340 c
->kind
= hid_output
;
343 case 10: /* Collection */
344 c
->kind
= hid_collection
;
345 c
->collection
= dval
;
347 c
->usage
= s
->usage_last
;
350 case 11: /* Feature */
351 c
->kind
= hid_feature
;
354 case 12: /* End collection */
355 c
->kind
= hid_endcollection
;
356 if (c
->collevel
== 0) {
357 /* Invalid end collection. */
371 c
->_usage_page
= dval
<< 16;
374 c
->logical_minimum
= dval
;
377 c
->logical_maximum
= dval
;
380 c
->physical_minimum
= dval
;
383 c
->physical_maximum
= dval
;
386 c
->unit_exponent
= dval
;
392 /* mask because value is unsigned */
393 s
->loc_size
= dval
& mask
;
396 hid_switch_rid(s
, c
, dval
& mask
);
399 /* mask because value is unsigned */
400 s
->loc_count
= dval
& mask
;
404 if (s
->pushlevel
< MAXPUSH
) {
405 s
->cur
[s
->pushlevel
] = *c
;
406 /* store size and count */
407 c
->report_size
= s
->loc_size
;
408 c
->report_count
= s
->loc_count
;
409 /* update current item pointer */
410 c
= &s
->cur
[s
->pushlevel
];
415 if (s
->pushlevel
< MAXPUSH
) {
416 c
= &s
->cur
[s
->pushlevel
];
417 /* restore size and count */
418 s
->loc_size
= c
->report_size
;
419 s
->loc_count
= c
->report_count
;
432 dval
= (dval
& mask
) | c
->_usage_page
;
434 /* set last usage, in case of a collection */
435 s
->usage_last
= dval
;
437 if (s
->nusage
< MAXUSAGE
) {
438 s
->usages_min
[s
->nusage
] = dval
;
439 s
->usages_max
[s
->nusage
] = dval
;
444 /* clear any pending usage sets */
451 dval
= (dval
& mask
) | c
->_usage_page
;
452 c
->usage_minimum
= dval
;
459 dval
= (dval
& mask
) | c
->_usage_page
;
460 c
->usage_maximum
= dval
;
467 if ((s
->nusage
< MAXUSAGE
) &&
468 (c
->usage_minimum
<= c
->usage_maximum
)) {
469 /* add usage range */
470 s
->usages_min
[s
->nusage
] =
472 s
->usages_max
[s
->nusage
] =
481 c
->designator_index
= dval
;
484 c
->designator_minimum
= dval
;
487 c
->designator_maximum
= dval
;
490 c
->string_index
= dval
;
493 c
->string_minimum
= dval
;
496 c
->string_maximum
= dval
;
499 c
->set_delimiter
= dval
;
513 hid_get_item(hid_data_t s
, hid_item_t
*h
)
518 r
= hid_get_item_raw(s
, h
);
519 if (r
<= 0 || s
->reportid
== -1 || h
->report_ID
== s
->reportid
)
526 hid_report_size(report_desc_t r
, enum hid_kind k
, int id
)
538 memset(&h
, 0, sizeof h
);
539 for (d
= hid_start_parse(r
, 1 << k
, id
); hid_get_item(d
, &h
); ) {
541 /* compute minimum */
544 /* compute end position */
545 temp
= h
.pos
+ (h
.report_size
* h
.report_count
);
546 /* compute maximum */
549 if (h
.report_ID
!= 0)
555 /* safety check - can happen in case of currupt descriptors */
561 /* return length in bytes rounded up */
562 return ((temp
+ 7) / 8 + report_id
);
566 hid_locate(report_desc_t desc
, unsigned int u
, enum hid_kind k
,
567 hid_item_t
*h
, int id
)
571 for (d
= hid_start_parse(desc
, 1 << k
, id
); hid_get_item(d
, h
); ) {
572 if (h
->kind
== k
&& !(h
->flags
& HIO_CONST
) && h
->usage
== u
) {