2 * $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $
3 * $FreeBSD: src/sys/dev/usb/hid.c,v 1.23 2003/08/24 17:55:54 obrien Exp $
4 * $DragonFly: src/sys/bus/usb/hid.c,v 1.13 2007/06/28 13:55:12 hasso Exp $
7 * Copyright (c) 1998 The NetBSD Foundation, Inc.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Lennart Augustsson (lennart@augustsson.net) at
12 * Carlstedt Research & Technology.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
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 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the NetBSD
25 * Foundation, Inc. and its contributors.
26 * 4. Neither the name of The NetBSD Foundation nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
47 #include <bus/usb/usb.h>
48 #include <bus/usb/usbhid.h>
50 #include <bus/usb/hid.h>
53 #define DPRINTF(x) if (usbdebug) kprintf x
54 #define DPRINTFN(n,x) if (usbdebug>(n)) kprintf x
61 static void hid_clear_local(struct hid_item
*);
69 int32_t usages
[MAXUSAGE
];
78 hid_clear_local(struct hid_item
*c
)
84 c
->designator_index
= 0;
85 c
->designator_minimum
= 0;
86 c
->designator_maximum
= 0;
88 c
->string_minimum
= 0;
89 c
->string_maximum
= 0;
94 hid_start_parse(void *d
, int len
, int kindset
)
98 s
= kmalloc(sizeof *s
, M_TEMP
, M_INTWAIT
|M_ZERO
);
100 s
->end
= (char *)d
+ len
;
101 s
->kindset
= kindset
;
106 hid_end_parse(struct hid_data
*s
)
109 while (s
->cur
.next
!= NULL
) {
110 struct hid_item
*hi
= s
->cur
.next
->next
;
111 kfree(s
->cur
.next
, M_TEMP
);
118 hid_get_item(struct hid_data
*s
, struct hid_item
*h
)
120 struct hid_item
*c
= &s
->cur
;
121 unsigned int bTag
, bType
, bSize
;
130 if (s
->multimax
!= 0) {
131 if (s
->multi
< s
->multimax
) {
132 c
->usage
= s
->usages
[min(s
->multi
, s
->nu
-1)];
135 c
->loc
.pos
+= c
->loc
.size
;
139 c
->loc
.count
= s
->multimax
;
158 bType
= 0xff; /* XXX what should it be */
162 bType
= (bSize
>> 2) & 3;
164 if (bSize
== 3) bSize
= 4;
174 dval
= (int8_t)*data
++;
178 dval
|= *data
++ << 8;
179 dval
= (int16_t)dval
;
183 dval
|= *data
++ << 8;
184 dval
|= *data
++ << 16;
185 dval
|= *data
++ << 24;
188 kprintf("BAD LENGTH %d\n", bSize
);
196 if (!(s
->kindset
& (1 << hid_input
)))
201 if (c
->flags
& HIO_VARIABLE
) {
202 s
->multimax
= c
->loc
.count
;
206 for (i
= c
->usage_minimum
;
207 i
<= c
->usage_maximum
;
209 s
->usages
[s
->nu
] = i
;
210 if (s
->nu
< MAXUSAGE
-1)
220 c
->loc
.size
* c
->loc
.count
;
226 if (!(s
->kindset
& (1 << hid_output
)))
228 c
->kind
= hid_output
;
231 case 10: /* Collection */
232 c
->kind
= hid_collection
;
233 c
->collection
= dval
;
239 case 11: /* Feature */
240 if (!(s
->kindset
& (1 << hid_feature
)))
242 c
->kind
= hid_feature
;
245 case 12: /* End collection */
246 c
->kind
= hid_endcollection
;
253 kprintf("Main bTag=%d\n", bTag
);
260 c
->_usage_page
= dval
<< 16;
263 c
->logical_minimum
= dval
;
266 c
->logical_maximum
= dval
;
269 c
->physical_maximum
= dval
;
272 c
->physical_maximum
= dval
;
275 c
->unit_exponent
= dval
;
290 hi
= kmalloc(sizeof *hi
, M_TEMP
, M_INTWAIT
);
302 kprintf("Global bTag=%d\n", bTag
);
310 dval
= c
->_usage_page
| (dval
&0xff);
312 dval
= c
->_usage_page
| (dval
&0xffff);
314 if (s
->nu
< MAXUSAGE
)
315 s
->usages
[s
->nu
++] = dval
;
321 dval
= c
->_usage_page
| (dval
&0xff);
323 dval
= c
->_usage_page
| (dval
&0xffff);
324 c
->usage_minimum
= dval
;
328 dval
= c
->_usage_page
| (dval
&0xff);
330 dval
= c
->_usage_page
| (dval
&0xffff);
331 c
->usage_maximum
= dval
;
334 c
->designator_index
= dval
;
337 c
->designator_minimum
= dval
;
340 c
->designator_maximum
= dval
;
343 c
->string_index
= dval
;
346 c
->string_minimum
= dval
;
349 c
->string_maximum
= dval
;
352 c
->set_delimiter
= dval
;
355 kprintf("Local bTag=%d\n", bTag
);
360 kprintf("default bType=%d\n", bType
);
367 hid_report_size(void *buf
, int len
, enum hid_kind k
, u_int8_t
*idp
)
371 int hi
, lo
, size
, id
;
375 for (d
= hid_start_parse(buf
, len
, 1<<k
); hid_get_item(d
, &h
); ) {
377 if (h
.report_ID
!= 0 && !id
)
379 if (h
.report_ID
== id
) {
382 hi
= h
.loc
.pos
+ h
.loc
.size
* h
.loc
.count
;
390 *idp
= id
; /* XXX wrong */
393 return ((size
+ 7) / 8);
397 hid_locate(void *desc
, int size
, u_int32_t u
, enum hid_kind k
,
398 struct hid_location
*loc
, u_int32_t
*flags
)
403 for (d
= hid_start_parse(desc
, size
, 1<<k
); hid_get_item(d
, &h
); ) {
404 if (h
.kind
== k
&& !(h
.flags
& HIO_CONST
) && h
.usage
== u
) {
419 hid_get_data(u_char
*buf
, struct hid_location
*loc
)
421 u_int hpos
= loc
->pos
;
422 u_int hsize
= loc
->size
;
426 DPRINTFN(10, ("hid_get_data: loc %d/%d\n", hpos
, hsize
));
433 for (i
= hpos
; i
< hpos
+hsize
; i
+= 8)
434 data
|= buf
[i
/ 8] << ((i
/ 8 - s
) * 8);
436 data
&= (1 << hsize
) - 1;
439 data
= ((int32_t)data
<< hsize
) >> hsize
;
440 DPRINTFN(10,("hid_get_data: loc %d/%d = %lu\n",
441 loc
->pos
, loc
->size
, (long)data
));
446 hid_is_collection(void *desc
, int size
, u_int32_t usage
)
452 hd
= hid_start_parse(desc
, size
, hid_input
);
456 err
= hid_get_item(hd
, &hi
) &&
457 hi
.kind
== hid_collection
&&