[BACK]Return to hid.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

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