Annotation of sys/dev/usb/hid.c, Revision 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