1 /* $NetBSD: hid.c,v 1.27 2007/09/08 07:46:13 plunky Exp $ */
2 /* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (lennart@augustsson.net) at
10 * Carlstedt Research & Technology.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: hid.c,v 1.27 2007/09/08 07:46:13 plunky Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #if defined(__NetBSD__)
40 #include <sys/kernel.h>
42 #include <sys/malloc.h>
44 #include <dev/usb/usb.h>
45 #include <dev/usb/usbhid.h>
47 #include <dev/usb/hid.h>
50 #define DPRINTF(x) if (uhidevdebug) logprintf x
51 #define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x
52 extern int uhidevdebug
;
58 Static
void hid_clear_local(struct hid_item
*);
66 int32_t usages
[MAXUSAGE
];
75 hid_clear_local(struct hid_item
*c
)
78 DPRINTFN(5,("hid_clear_local\n"));
82 c
->designator_index
= 0;
83 c
->designator_minimum
= 0;
84 c
->designator_maximum
= 0;
86 c
->string_minimum
= 0;
87 c
->string_maximum
= 0;
92 hid_start_parse(const void *d
, int len
, enum hid_kind kind
)
96 s
= malloc(sizeof *s
, M_TEMP
, M_WAITOK
|M_ZERO
);
98 s
->end
= (const char *)d
+ len
;
104 hid_end_parse(struct hid_data
*s
)
107 while (s
->cur
.next
!= NULL
) {
108 struct hid_item
*hi
= s
->cur
.next
->next
;
109 free(s
->cur
.next
, M_TEMP
);
116 hid_get_item(struct hid_data
*s
, struct hid_item
*h
)
118 struct hid_item
*c
= &s
->cur
;
119 unsigned int bTag
, bType
, bSize
;
126 enum hid_kind retkind
;
129 DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n",
130 s
->multi
, s
->multimax
));
131 if (s
->multimax
!= 0) {
132 if (s
->multi
< s
->multimax
) {
133 c
->usage
= s
->usages
[min(s
->multi
, s
->nu
-1)];
136 c
->loc
.pos
+= c
->loc
.size
;
138 DPRINTFN(5,("return multi\n"));
141 c
->loc
.count
= s
->multimax
;
160 bType
= 0xff; /* XXX what should it be */
164 bType
= (bSize
>> 2) & 3;
166 if (bSize
== 3) bSize
= 4;
176 dval
= /*(int8_t)*/ *data
++;
180 dval
|= *data
++ << 8;
181 dval
= /*(int16_t)*/ dval
;
185 dval
|= *data
++ << 8;
186 dval
|= *data
++ << 16;
187 dval
|= *data
++ << 24;
190 printf("BAD LENGTH %d\n", bSize
);
194 DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d\n",
202 if (s
->kind
!= retkind
) {
210 if (c
->flags
& HIO_VARIABLE
) {
211 s
->multimax
= c
->loc
.count
;
215 for (i
= c
->usage_minimum
;
216 i
<= c
->usage_maximum
;
218 s
->usages
[s
->nu
] = i
;
219 if (s
->nu
< MAXUSAGE
-1)
226 c
->usage
= c
->_usage_page
; /* XXX */
230 c
->loc
.size
* c
->loc
.count
;
237 retkind
= hid_output
;
239 case 10: /* Collection */
240 c
->kind
= hid_collection
;
241 c
->collection
= dval
;
247 case 11: /* Feature */
248 retkind
= hid_feature
;
250 case 12: /* End collection */
251 c
->kind
= hid_endcollection
;
257 printf("Main bTag=%d\n", bTag
);
264 c
->_usage_page
= dval
<< 16;
267 c
->logical_minimum
= dval
;
270 c
->logical_maximum
= dval
;
273 c
->physical_maximum
= dval
;
276 c
->physical_maximum
= dval
;
279 c
->unit_exponent
= dval
;
295 hi
= malloc(sizeof *hi
, M_TEMP
, M_WAITOK
);
307 printf("Global bTag=%d\n", bTag
);
315 dval
= c
->_usage_page
| (dval
&0xff);
317 dval
= c
->_usage_page
| (dval
&0xffff);
319 if (s
->nu
< MAXUSAGE
)
320 s
->usages
[s
->nu
++] = dval
;
326 dval
= c
->_usage_page
| (dval
&0xff);
328 dval
= c
->_usage_page
| (dval
&0xffff);
329 c
->usage_minimum
= dval
;
333 dval
= c
->_usage_page
| (dval
&0xff);
335 dval
= c
->_usage_page
| (dval
&0xffff);
336 c
->usage_maximum
= dval
;
339 c
->designator_index
= dval
;
342 c
->designator_minimum
= dval
;
345 c
->designator_maximum
= dval
;
348 c
->string_index
= dval
;
351 c
->string_minimum
= dval
;
354 c
->string_maximum
= dval
;
357 c
->set_delimiter
= dval
;
360 printf("Local bTag=%d\n", bTag
);
365 printf("default bType=%d\n", bType
);
372 hid_report_size(const void *buf
, int len
, enum hid_kind k
, u_int8_t id
)
380 DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k
, id
));
381 for (d
= hid_start_parse(buf
, len
, k
); hid_get_item(d
, &h
); ) {
382 DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d "
383 "size=%d count=%d\n",
384 h
.kind
, h
.report_ID
, h
.loc
.pos
, h
.loc
.size
,
386 if (h
.report_ID
== id
&& h
.kind
== k
) {
391 printf("hid_report_size: lo != 0\n");
395 hi
= h
.loc
.pos
+ h
.loc
.size
* h
.loc
.count
;
396 DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo
, hi
));
400 return ((hi
- lo
+ 7) / 8);
404 hid_locate(const void *desc
, int size
, u_int32_t u
, u_int8_t id
, enum hid_kind k
,
405 struct hid_location
*loc
, u_int32_t
*flags
)
411 DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u
, k
, id
));
412 for (d
= hid_start_parse(desc
, size
, k
); hid_get_item(d
, &h
); ) {
413 DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
414 h
.usage
, h
.kind
, h
.report_ID
, h
.flags
));
415 if (h
.kind
== k
&& !(h
.flags
& HIO_CONST
) &&
416 h
.usage
== u
&& h
.report_ID
== id
) {
431 hid_get_data(u_char
*buf
, struct hid_location
*loc
)
433 u_int hpos
= loc
->pos
;
434 u_int hsize
= loc
->size
;
438 DPRINTFN(10, ("hid_get_data: loc %d/%d\n", hpos
, hsize
));
445 for (i
= hpos
; i
< hpos
+hsize
; i
+= 8)
446 data
|= buf
[i
/ 8] << ((i
/ 8 - s
) * 8);
448 data
&= (1 << hsize
) - 1;
451 data
= ((int32_t)data
<< hsize
) >> hsize
;
452 DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n",
453 loc
->pos
, loc
->size
, (long)data
));
458 * hid_is_collection(desc, size, id, usage)
460 * This function is broken in the following way.
462 * It is used to discover if the given 'id' is part of 'usage' collection
463 * in the descriptor in order to match report id against device type.
465 * The semantics of hid_start_parse() means though, that only a single
466 * kind of report is considered. The current HID code that uses this for
467 * matching is actually only looking for input reports, so this works
470 * This function could try all report kinds (input, output and feature)
471 * consecutively if necessary, but it may be better to integrate the
472 * libusbhid code which can consider multiple report kinds simultaneously
474 * Needs some thought.
477 hid_is_collection(const void *desc
, int size
, u_int8_t id
, u_int32_t usage
)
481 u_int32_t coll_usage
= ~0;
483 hd
= hid_start_parse(desc
, size
, hid_input
);
487 DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id
, usage
));
488 while (hid_get_item(hd
, &hi
)) {
489 DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x"
491 hi
.kind
, hi
.report_ID
, hi
.usage
, coll_usage
));
493 if (hi
.kind
== hid_collection
&&
494 hi
.collection
== HCOLL_APPLICATION
)
495 coll_usage
= hi
.usage
;
497 if (hi
.kind
== hid_endcollection
)
500 if (hi
.kind
== hid_input
&&
501 coll_usage
== usage
&&
502 hi
.report_ID
== id
) {
503 DPRINTFN(2,("hid_is_collection: found\n"));
508 DPRINTFN(2,("hid_is_collection: not found\n"));