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