[BACK]Return to usbhid.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / usbhidctl

Annotation of src/usr.bin/usbhidctl/usbhid.c, Revision 1.3

1.3     ! nate        1: /*     $OpenBSD: usbhid.c,v 1.2 2001/12/30 07:10:42 pvalchev Exp $     */
1.1       pvalchev    2: /*      $NetBSD: usbhid.c,v 1.17 2001/03/28 03:17:42 simonb Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by David Sainty <David.Sainty@dtsp.co.nz>
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: #include <sys/types.h>
                     41:
                     42: #include <dev/usb/usb.h>
                     43: #include <dev/usb/usbhid.h>
                     44:
                     45: #include <ctype.h>
                     46: #include <err.h>
                     47: #include <errno.h>
                     48: #include <fcntl.h>
                     49: #include <limits.h>
                     50: #include <stdio.h>
                     51: #include <stdlib.h>
                     52: #include <string.h>
                     53: #include <unistd.h>
1.2       pvalchev   54: #include <usbhid.h>
1.1       pvalchev   55:
                     56: /* Parser tokens */
                     57: #define DELIM_USAGE '.'
                     58: #define DELIM_PAGE ':'
                     59: #define DELIM_SET '='
                     60:
                     61: /* Zero if not in a verbose mode.  Greater levels of verbosity are
                     62:    indicated by values larger than one. */
                     63: static unsigned int verbose;
                     64:
                     65: struct Susbvar {
                     66:        /* Variable name, not NUL terminated */
                     67:        char const *variable;
                     68:        size_t varlen;
                     69:
                     70:        char const *value; /* Value to set variable to */
                     71:
                     72: #define MATCH_ALL              (1 << 0)
                     73: #define MATCH_COLLECTIONS      (1 << 1)
                     74: #define MATCH_NODATA           (1 << 2)
                     75: #define MATCH_CONSTANTS                (1 << 3)
                     76: #define MATCH_WASMATCHED       (1 << 4)
                     77: #define MATCH_SHOWPAGENAME     (1 << 5)
                     78: #define MATCH_SHOWNUMERIC      (1 << 6)
                     79: #define MATCH_WRITABLE         (1 << 7)
                     80:        unsigned int mflags;
                     81:
                     82:        /* Workspace for hidmatch() */
                     83:        ssize_t matchindex;
                     84:
                     85:        int (*opfunc)(struct hid_item *item, struct Susbvar *var,
                     86:                      u_int32_t const *collist, size_t collen, u_char *buf);
                     87: };
                     88:
                     89: struct Sreport {
                     90:        struct usb_ctl_report *buffer;
                     91:
                     92:        enum {srs_uninit, srs_clean, srs_dirty} status;
                     93:        int report_id;
                     94:        size_t size;
                     95: };
                     96:
                     97: static struct {
                     98:        int uhid_report;
                     99:        hid_kind_t hid_kind;
                    100:        char const *name;
                    101: } const reptoparam[] = {
                    102: #define REPORT_INPUT 0
                    103:        { UHID_INPUT_REPORT, hid_input, "input" },
                    104: #define REPORT_OUTPUT 1
                    105:        { UHID_OUTPUT_REPORT, hid_output, "output" },
                    106: #define REPORT_FEATURE 2
                    107:        { UHID_FEATURE_REPORT, hid_feature, "feature" }
                    108: #define REPORT_MAXVAL 2
                    109: };
                    110:
                    111: static struct Susbvar*
                    112: hidmatch(u_int32_t const *collist, size_t collen, struct hid_item *item,
                    113:         struct Susbvar *varlist, size_t vlsize)
                    114: {
                    115:        size_t vlind, colind, vlactive;
                    116:        int iscollection;
                    117:
                    118:        /*
                    119:         * Keep track of how many variables are still "active".  When
                    120:         * the active count reaches zero, don't bother to continue
                    121:         * looking for matches.
                    122:         */
                    123:        vlactive = vlsize;
                    124:
                    125:        iscollection = item->kind == hid_collection ||
                    126:                item->kind == hid_endcollection;
                    127:
                    128:        for (vlind = 0; vlind < vlsize; vlind++) {
                    129:                struct Susbvar *var;
                    130:
                    131:                var = &varlist[vlind];
                    132:
                    133:                var->matchindex = 0;
                    134:
                    135:                if (!(var->mflags & MATCH_COLLECTIONS) && iscollection) {
                    136:                        /* Don't match collections for this variable */
                    137:                        var->matchindex = -1;
                    138:                        vlactive--;
                    139:                } else if (!iscollection && !(var->mflags & MATCH_CONSTANTS) &&
                    140:                           (item->flags & HIO_CONST)) {
                    141:                        /*
                    142:                         * Don't match constants for this variable,
                    143:                         * but ignore the constant bit on collections.
                    144:                         */
                    145:                        var->matchindex = -1;
                    146:                        vlactive--;
                    147:                } else if ((var->mflags & MATCH_WRITABLE) &&
                    148:                           ((item->kind != hid_output &&
                    149:                             item->kind != hid_feature) ||
                    150:                            (item->flags & HIO_CONST))) {
                    151:                        /*
                    152:                         * If we are only matching writable items, if
                    153:                         * this is not an output or feature kind, or
                    154:                         * it is a constant, reject it.
                    155:                         */
                    156:                        var->matchindex = -1;
                    157:                        vlactive--;
                    158:                } else if (var->mflags & MATCH_ALL) {
                    159:                        /* Match immediately */
                    160:                        return &varlist[vlind];
                    161:                }
                    162:        }
                    163:
                    164:        for (colind = 0; vlactive > 0 && colind <= collen; colind++) {
                    165:                char const *usage_name, *page_name;
                    166:                size_t usage_len, page_len;
                    167:                int final;
                    168:                u_int32_t usage_id;
                    169:
                    170:                final = (colind == collen);
                    171:
                    172:                if (final)
                    173:                        usage_id = item->usage;
                    174:                else
                    175:                        usage_id = collist[colind];
                    176:
                    177:                usage_name = hid_usage_in_page(usage_id);
                    178:                usage_len = strlen(usage_name);
                    179:
                    180:                page_name = NULL;
                    181:
                    182:                for (vlind = 0; vlind < vlsize; vlind++) {
                    183:                        ssize_t matchindex, pagesplit;
                    184:                        size_t varlen, strind;
                    185:                        char const *varname;
                    186:                        struct Susbvar *var;
                    187:
                    188:                        var = &varlist[vlind];
                    189:
                    190:                        matchindex = var->matchindex;
                    191:                        varname = var->variable;
                    192:                        varlen = var->varlen;
                    193:
                    194:                        if (matchindex < 0)
                    195:                                /* Mismatch at a previous level */
                    196:                                continue;
                    197:
                    198:                        pagesplit = -1;
                    199:                        for (strind = matchindex; strind < varlen; strind++) {
                    200:                                if (varname[strind] == DELIM_USAGE)
                    201:                                        break;
                    202:                                if (varname[strind] == DELIM_PAGE)
                    203:                                        pagesplit = strind;
                    204:                        }
                    205:
                    206:                        if (final && strind != varlen) {
                    207:                                /*
                    208:                                 * Variable name is too long (hit
                    209:                                 * delimiter instead of
                    210:                                 * end-of-variable)
                    211:                                 */
                    212:                                var->matchindex = -1;
                    213:                                vlactive--;
                    214:                                continue;
                    215:                        }
                    216:
                    217:                        if (pagesplit >= 0) {
                    218:                                if (page_name == NULL) {
                    219:                                        page_name = hid_usage_page(HID_PAGE(usage_id));
                    220:                                        page_len = strlen(page_name);
                    221:                                }
                    222:                                if (page_len !=
                    223:                                    (size_t)(pagesplit - matchindex) ||
                    224:                                    memcmp(page_name, &varname[matchindex],
                    225:                                           page_len) != 0) {
                    226:                                        /* Mismatch, page name wrong */
                    227:                                        var->matchindex = -1;
                    228:                                        vlactive--;
                    229:                                        continue;
                    230:                                }
                    231:
                    232:                                /* Page matches, discard page name */
                    233:                                matchindex = pagesplit + 1;
                    234:                        }
                    235:
                    236:                        if (usage_len != strind - matchindex ||
                    237:                            memcmp(usage_name, &varname[matchindex],
                    238:                                   usage_len) != 0) {
                    239:                                /* Mismatch, usage name wrong */
                    240:                                var->matchindex = -1;
                    241:                                vlactive--;
                    242:                                continue;
                    243:                        }
                    244:
                    245:                        if (final)
                    246:                                /* Match */
                    247:                                return var;
                    248:
                    249:                        /*
                    250:                         * Partial match: Move index past this usage
                    251:                         * string + delimiter
                    252:                         */
                    253:                        var->matchindex = matchindex + usage_len + 1;
                    254:                }
                    255:        }
                    256:
                    257:        return NULL;
                    258: }
                    259:
                    260: static void
                    261: allocreport(struct Sreport *report, report_desc_t rd, int repindex)
                    262: {
                    263:        int reptsize;
                    264:
                    265:        reptsize = hid_report_size(rd, reptoparam[repindex].hid_kind,
                    266:                                   &report->report_id);
                    267:        if (reptsize < 0)
                    268:                errx(1, "Negative report size");
                    269:        report->size = reptsize;
                    270:
                    271:        if (report->size > 0) {
                    272:                /*
                    273:                 * Allocate a buffer with enough space for the
                    274:                 * report in the variable-sized data field.
                    275:                 */
                    276:                report->buffer = malloc(sizeof(*report->buffer) -
1.3     ! nate      277:                                        sizeof(report->buffer->ucr_data) +
1.1       pvalchev  278:                                        report->size);
                    279:                if (report->buffer == NULL)
                    280:                        err(1, NULL);
                    281:        } else
                    282:                report->buffer = NULL;
                    283:
                    284:        report->status = srs_clean;
                    285: }
                    286:
                    287: static void
                    288: freereport(struct Sreport *report)
                    289: {
                    290:        if (report->buffer != NULL)
                    291:                free(report->buffer);
                    292:        report->status = srs_uninit;
                    293: }
                    294:
                    295: static void
                    296: getreport(struct Sreport *report, int hidfd, report_desc_t rd, int repindex)
                    297: {
                    298:        if (report->status == srs_uninit) {
                    299:                allocreport(report, rd, repindex);
                    300:                if (report->size == 0)
                    301:                        return;
                    302:
1.3     ! nate      303:                report->buffer->ucr_report = reptoparam[repindex].uhid_report;
1.1       pvalchev  304:                if (ioctl(hidfd, USB_GET_REPORT, report->buffer) < 0)
                    305:                        err(1, "USB_GET_REPORT");
                    306:        }
                    307: }
                    308:
                    309: static void
                    310: setreport(struct Sreport *report, int hidfd, int repindex)
                    311: {
                    312:        if (report->status == srs_dirty) {
1.3     ! nate      313:                report->buffer->ucr_report = reptoparam[repindex].uhid_report;
1.1       pvalchev  314:
                    315:                if (ioctl(hidfd, USB_SET_REPORT, report->buffer) < 0)
                    316:                        err(1, "USB_SET_REPORT(%s)",
                    317:                            reptoparam[repindex].name);
                    318:
                    319:                report->status = srs_clean;
                    320:        }
                    321: }
                    322:
                    323: /* ARGSUSED1 */
                    324: static int
                    325: varop_value(struct hid_item *item, struct Susbvar *var,
                    326:            u_int32_t const *collist, size_t collen, u_char *buf)
                    327: {
                    328:        printf("%d\n", hid_get_data(buf, item));
                    329:        return 0;
                    330: }
                    331:
                    332: /* ARGSUSED1 */
                    333: static int
                    334: varop_display(struct hid_item *item, struct Susbvar *var,
                    335:              u_int32_t const *collist, size_t collen, u_char *buf)
                    336: {
                    337:        size_t colitem;
                    338:
                    339:        for (colitem = 0; colitem < collen; colitem++) {
                    340:                if (var->mflags & MATCH_SHOWPAGENAME)
                    341:                        printf("%s:",
                    342:                               hid_usage_page(HID_PAGE(collist[colitem])));
                    343:                printf("%s.", hid_usage_in_page(collist[colitem]));
                    344:        }
                    345:
                    346:        if (var->mflags & MATCH_SHOWPAGENAME)
                    347:                printf("%s:", hid_usage_page(HID_PAGE(item->usage)));
                    348:        printf("%s=%d%s\n", hid_usage_in_page(item->usage),
                    349:               hid_get_data(buf, item),
                    350:               (item->flags & HIO_CONST) ? " (const)" : "");
                    351:        return 0;
                    352: }
                    353:
                    354: /* ARGSUSED1 */
                    355: static int
                    356: varop_modify(struct hid_item *item, struct Susbvar *var,
                    357:             u_int32_t const *collist, size_t collen, u_char *buf)
                    358: {
                    359:        u_int dataval;
                    360:
                    361:        dataval = (u_int)strtol(var->value, NULL, 10);
                    362:
                    363:        hid_set_data(buf, item, dataval);
                    364:
                    365:        if (verbose >= 1)
                    366:                /*
                    367:                 * Allow displaying of set value in verbose mode.
                    368:                 * This isn't particularly useful though, so don't
                    369:                 * bother documenting it.
                    370:                 */
                    371:                varop_display(item, var, collist, collen, buf);
                    372:
                    373:        return 1;
                    374: }
                    375:
                    376: static void
                    377: reportitem(char const *label, struct hid_item const *item, unsigned int mflags)
                    378: {
                    379:        printf("%s size=%d count=%d page=%s usage=%s%s", label,
                    380:               item->report_size, item->report_count,
                    381:               hid_usage_page(HID_PAGE(item->usage)),
                    382:               hid_usage_in_page(item->usage),
                    383:               item->flags & HIO_CONST ? " Const" : "");
                    384:        if (mflags & MATCH_SHOWNUMERIC)
                    385:                printf(" (%u/0x%x)",
                    386:                       HID_PAGE(item->usage), HID_USAGE(item->usage));
                    387:        printf(", logical range %d..%d",
                    388:               item->logical_minimum, item->logical_maximum);
                    389:        if (item->physical_minimum != item->physical_maximum)
                    390:                printf(", physical range %d..%d",
                    391:                       item->physical_minimum, item->physical_maximum);
                    392:        if (item->unit)
                    393:                printf(", unit=0x%02x exp=%d", item->unit,
                    394:                       item->unit_exponent);
                    395:        printf("\n");
                    396: }
                    397:
                    398: /* ARGSUSED1 */
                    399: static int
                    400: varop_report(struct hid_item *item, struct Susbvar *var,
                    401:             u_int32_t const *collist, size_t collen, u_char *buf)
                    402: {
                    403:        switch (item->kind) {
                    404:        case hid_collection:
                    405:                printf("Collection page=%s usage=%s\n",
                    406:                       hid_usage_page(HID_PAGE(item->usage)),
                    407:                       hid_usage_in_page(item->usage));
                    408:                break;
                    409:        case hid_endcollection:
                    410:                printf("End collection\n");
                    411:                break;
                    412:        case hid_input:
                    413:                reportitem("Input  ", item, var->mflags);
                    414:                break;
                    415:        case hid_output:
                    416:                reportitem("Output ", item, var->mflags);
                    417:                break;
                    418:        case hid_feature:
                    419:                reportitem("Feature", item, var->mflags);
                    420:                break;
                    421:        }
                    422:
                    423:        return 0;
                    424: }
                    425:
                    426: static void
                    427: devloop(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize)
                    428: {
                    429:        struct hid_data *hdata;
                    430:        struct hid_item hitem;
                    431:        u_int32_t colls[128];
                    432:        struct Sreport inreport;
                    433:        size_t dlen;
                    434:        u_char *dbuf;
                    435:        size_t collind;
                    436:
                    437:        allocreport(&inreport, rd, REPORT_INPUT);
                    438:
                    439:        if (inreport.size <= 0)
                    440:                errx(1, "Input report descriptor invalid length");
                    441:
                    442:        dlen = inreport.size;
1.3     ! nate      443:        dbuf = inreport.buffer->ucr_data;
1.1       pvalchev  444:
                    445:        for (;;) {
                    446:                ssize_t readlen;
                    447:
                    448:                readlen = read(hidfd, dbuf, dlen);
                    449:                if (readlen < 0 || dlen != (size_t)readlen)
                    450:                        err(1, "bad read %ld != %ld",
                    451:                            (long)readlen, (long)dlen);
                    452:
                    453:                collind = 0;
                    454:                hdata = hid_start_parse(rd, 1 << hid_input);
                    455:                if (hdata == NULL)
                    456:                        errx(1, "Failed to start parser");
                    457:
                    458:                while (hid_get_item(hdata, &hitem)) {
                    459:                        struct Susbvar *matchvar;
                    460:
                    461:                        switch (hitem.kind) {
                    462:                        case hid_collection:
                    463:                                if (collind >= (sizeof(colls) / sizeof(*colls)))
                    464:                                        errx(1, "Excessive nested collections");
                    465:                                colls[collind++] = hitem.usage;
                    466:                                break;
                    467:                        case hid_endcollection:
                    468:                                if (collind == 0)
                    469:                                        errx(1, "Excessive collection ends");
                    470:                                collind--;
                    471:                                break;
                    472:                        case hid_input:
                    473:                                break;
                    474:                        case hid_output:
                    475:                        case hid_feature:
                    476:                                errx(1, "Unexpected non-input item returned");
                    477:                        }
                    478:
                    479:                        matchvar = hidmatch(colls, collind, &hitem,
                    480:                                            varlist, vlsize);
                    481:
                    482:                        if (matchvar != NULL)
                    483:                                matchvar->opfunc(&hitem, matchvar,
                    484:                                                 colls, collind,
1.3     ! nate      485:                                                 inreport.buffer->ucr_data);
1.1       pvalchev  486:                }
                    487:                hid_end_parse(hdata);
                    488:                printf("\n");
                    489:        }
                    490:        /* NOTREACHED */
                    491: }
                    492:
                    493: static void
                    494: devshow(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize,
                    495:        int kindset)
                    496: {
                    497:        struct hid_data *hdata;
                    498:        struct hid_item hitem;
                    499:        u_int32_t colls[128];
                    500:        size_t collind, repind, vlind;
                    501:
                    502:        struct Sreport reports[REPORT_MAXVAL + 1];
                    503:
                    504:
                    505:        for (repind = 0; repind < (sizeof(reports) / sizeof(*reports));
                    506:             repind++) {
                    507:                reports[repind].status = srs_uninit;
                    508:                reports[repind].buffer = NULL;
                    509:        }
                    510:
                    511:        collind = 0;
                    512:        hdata = hid_start_parse(rd, kindset |
                    513:                                (1 << hid_collection) |
                    514:                                (1 << hid_endcollection));
                    515:        if (hdata == NULL)
                    516:                errx(1, "Failed to start parser");
                    517:
                    518:        while (hid_get_item(hdata, &hitem)) {
                    519:                struct Susbvar *matchvar;
                    520:                int repindex;
                    521:
                    522:                repindex = -1;
                    523:                switch (hitem.kind) {
                    524:                case hid_collection:
                    525:                        if (collind >= (sizeof(colls) / sizeof(*colls)))
                    526:                                errx(1, "Excessive nested collections");
                    527:                        colls[collind++] = hitem.usage;
                    528:                        break;
                    529:                case hid_endcollection:
                    530:                        if (collind == 0)
                    531:                                errx(1, "Excessive collection ends");
                    532:                        collind--;
                    533:                        break;
                    534:                case hid_input:
                    535:                        repindex = REPORT_INPUT;
                    536:                        break;
                    537:                case hid_output:
                    538:                        repindex = REPORT_OUTPUT;
                    539:                        break;
                    540:                case hid_feature:
                    541:                        repindex = REPORT_FEATURE;
                    542:                        break;
                    543:                }
                    544:
                    545:                matchvar = hidmatch(colls, collind, &hitem, varlist, vlsize);
                    546:
                    547:                if (matchvar != NULL) {
                    548:                        u_char *bufdata;
                    549:                        struct Sreport *repptr;
                    550:
                    551:                        matchvar->mflags |= MATCH_WASMATCHED;
                    552:
                    553:                        if (repindex >= 0)
                    554:                                repptr = &reports[repindex];
                    555:                        else
                    556:                                repptr = NULL;
                    557:
                    558:                        if (repptr != NULL &&
                    559:                            !(matchvar->mflags & MATCH_NODATA))
                    560:                                getreport(repptr, hidfd, rd, repindex);
                    561:
                    562:                        bufdata = (repptr == NULL || repptr->buffer == NULL) ?
1.3     ! nate      563:                                NULL : repptr->buffer->ucr_data;
1.1       pvalchev  564:
                    565:                        if (matchvar->opfunc(&hitem, matchvar, colls, collind,
                    566:                                             bufdata))
                    567:                                repptr->status = srs_dirty;
                    568:                }
                    569:        }
                    570:        hid_end_parse(hdata);
                    571:
                    572:        for (repind = 0; repind < (sizeof(reports) / sizeof(*reports));
                    573:             repind++) {
                    574:                setreport(&reports[repind], hidfd, repind);
                    575:                freereport(&reports[repind]);
                    576:        }
                    577:
                    578:        /* Warn about any items that we couldn't find a match for */
                    579:        for (vlind = 0; vlind < vlsize; vlind++) {
                    580:                struct Susbvar *var;
                    581:
                    582:                var = &varlist[vlind];
                    583:
                    584:                if (var->variable != NULL &&
                    585:                    !(var->mflags & MATCH_WASMATCHED))
                    586:                        warnx("Failed to match: %.*s", (int)var->varlen,
                    587:                              var->variable);
                    588:        }
                    589: }
                    590:
                    591: static void
                    592: usage(void)
                    593: {
                    594:        extern char *__progname;
                    595:
                    596:        fprintf(stderr, "Usage: %s -f device [-t tablefile] [-l] [-v] -a\n",
                    597:            __progname);
                    598:        fprintf(stderr, "       %s -f device [-t tablefile] [-v] -r\n",
                    599:            __progname);
                    600:        fprintf(stderr,
                    601:            "       %s -f device [-t tablefile] [-l] [-n] [-v] name ...\n",
                    602:            __progname);
                    603:        fprintf(stderr,
                    604:            "       %s -f device [-t tablefile] -w name=value ...\n",
                    605:            __progname);
                    606:        exit(1);
                    607: }
                    608:
                    609: int
                    610: main(int argc, char **argv)
                    611: {
                    612:        int hidfd;
                    613:        report_desc_t repdesc;
                    614:        char devnamebuf[PATH_MAX];
                    615:        char const *dev;
                    616:        int ch, wflag, aflag, nflag, rflag, lflag;
                    617:        size_t varnum;
                    618:        char const *table;
                    619:        struct Susbvar variables[128];
                    620:
                    621:        wflag = aflag = nflag = verbose = rflag = lflag = 0;
                    622:        dev = NULL;
                    623:        table = NULL;
                    624:        while ((ch = getopt(argc, argv, "?af:lnrt:vw")) != -1) {
                    625:                switch (ch) {
                    626:                case 'a':
                    627:                        aflag = 1;
                    628:                        break;
                    629:                case 'f':
                    630:                        dev = optarg;
                    631:                        break;
                    632:                case 'l':
                    633:                        lflag = 1;
                    634:                        break;
                    635:                case 'n':
                    636:                        nflag = 1;
                    637:                        break;
                    638:                case 'r':
                    639:                        rflag = 1;
                    640:                        break;
                    641:                case 't':
                    642:                        table = optarg;
                    643:                        break;
                    644:                case 'v':
                    645:                        verbose++;
                    646:                        break;
                    647:                case 'w':
                    648:                        wflag = 1;
                    649:                        break;
                    650:                case '?':
                    651:                default:
                    652:                        usage();
                    653:                        /* NOTREACHED */
                    654:                }
                    655:        }
                    656:        argc -= optind;
                    657:        argv += optind;
                    658:        if (dev == NULL || (lflag && (wflag || rflag))) {
                    659:                /*
                    660:                 * No device specified, or attempting to loop and set
                    661:                 * or dump report at the same time
                    662:                 */
                    663:                usage();
                    664:                /* NOTREACHED */
                    665:        }
                    666:
                    667:        for (varnum = 0; varnum < (size_t)argc; varnum++) {
                    668:                char const *name, *valuesep;
                    669:                struct Susbvar *svar;
                    670:
                    671:                svar = &variables[varnum];
                    672:                name = argv[varnum];
                    673:                valuesep = strchr(name, DELIM_SET);
                    674:
                    675:                svar->variable = name;
                    676:                svar->mflags = 0;
                    677:
                    678:                if (valuesep == NULL) {
                    679:                        /* Read variable */
                    680:                        if (wflag)
                    681:                                errx(1, "Must not specify -w to read variables");
                    682:                        svar->value = NULL;
                    683:                        svar->varlen = strlen(name);
                    684:
                    685:                        if (nflag) {
                    686:                                /* Display value of variable only */
                    687:                                svar->opfunc = varop_value;
                    688:                        } else {
                    689:                                /* Display name and value of variable */
                    690:                                svar->opfunc = varop_display;
                    691:
                    692:                                if (verbose >= 1)
                    693:                                        /* Show page names in verbose modes */
                    694:                                        svar->mflags |= MATCH_SHOWPAGENAME;
                    695:                        }
                    696:                } else {
                    697:                        /* Write variable */
                    698:                        if (!wflag)
                    699:                                errx(2, "Must specify -w to set variables");
                    700:                        svar->mflags |= MATCH_WRITABLE;
                    701:                        svar->varlen = valuesep - name;
                    702:                        svar->value = valuesep + 1;
                    703:                        svar->opfunc = varop_modify;
                    704:                }
                    705:        }
                    706:
                    707:        if (aflag || rflag) {
                    708:                struct Susbvar *svar;
                    709:
                    710:                svar = &variables[varnum++];
                    711:
                    712:                svar->variable = NULL;
                    713:                svar->mflags = MATCH_ALL;
                    714:
                    715:                if (rflag) {
                    716:                        /*
                    717:                         * Dump report descriptor.  Do dump collection
                    718:                         * items also, and hint that it won't be
                    719:                         * necessary to get the item status.
                    720:                         */
                    721:                        svar->opfunc = varop_report;
                    722:                        svar->mflags |= MATCH_COLLECTIONS | MATCH_NODATA;
                    723:
                    724:                        switch (verbose) {
                    725:                        default:
                    726:                                /* Level 2: Show item numerics and constants */
                    727:                                svar->mflags |= MATCH_SHOWNUMERIC;
                    728:                                /* FALLTHROUGH */
                    729:                        case 1:
                    730:                                /* Level 1: Just show constants */
                    731:                                svar->mflags |= MATCH_CONSTANTS;
                    732:                                /* FALLTHROUGH */
                    733:                        case 0:
                    734:                                break;
                    735:                        }
                    736:                } else {
                    737:                        /* Display name and value of variable */
                    738:                        svar->opfunc = varop_display;
                    739:
                    740:                        switch (verbose) {
                    741:                        default:
                    742:                                /* Level 2: Show constants and page names */
                    743:                                svar->mflags |= MATCH_CONSTANTS;
                    744:                                /* FALLTHROUGH */
                    745:                        case 1:
                    746:                                /* Level 1: Just show page names */
                    747:                                svar->mflags |= MATCH_SHOWPAGENAME;
                    748:                                /* FALLTHROUGH */
                    749:                        case 0:
                    750:                                break;
                    751:                        }
                    752:                }
                    753:        }
                    754:
                    755:        if (varnum == 0) {
                    756:                /* Nothing to do...  Display usage information. */
                    757:                usage();
                    758:                /* NOTREACHED */
                    759:        }
                    760:
                    761:        hid_init(table);
                    762:
                    763:        if (dev[0] != '/') {
                    764:                snprintf(devnamebuf, sizeof(devnamebuf), "/dev/%s%s",
                    765:                         isdigit(dev[0]) ? "uhid" : "", dev);
                    766:                dev = devnamebuf;
                    767:        }
                    768:
                    769:        hidfd = open(dev, O_RDWR);
                    770:        if (hidfd < 0)
                    771:                err(1, "%s", dev);
                    772:
                    773:        repdesc = hid_get_report_desc(hidfd);
                    774:        if (repdesc == 0)
                    775:                errx(1, "USB_GET_REPORT_DESC");
                    776:
                    777:        if (lflag) {
                    778:                devloop(hidfd, repdesc, variables, varnum);
                    779:                /* NOTREACHED */
                    780:        }
                    781:
                    782:        if (rflag)
                    783:                /* Report mode header */
                    784:                printf("Report descriptor:\n");
                    785:
                    786:        devshow(hidfd, repdesc, variables, varnum,
                    787:                1 << hid_input |
                    788:                1 << hid_output |
                    789:                1 << hid_feature);
                    790:
                    791: #if 0
                    792:        {
                    793:                size_t repindex;
                    794:                for (repindex = 0;
                    795:                     repindex < (sizeof(reptoparam) / sizeof(*reptoparam));
                    796:                     repindex++)
                    797:                        devshow(hidfd, repdesc, variables, varnum,
                    798:                                1 << reptoparam[repindex].hid_kind);
                    799:        }
                    800: #endif
                    801:
                    802:        if (rflag) {
                    803:                /* Report mode trailer */
                    804:                size_t repindex;
                    805:                for (repindex = 0;
                    806:                     repindex < (sizeof(reptoparam) / sizeof(*reptoparam));
                    807:                     repindex++) {
                    808:                        int report_id, size;
                    809:                        size = hid_report_size(repdesc,
                    810:                                               reptoparam[repindex].hid_kind,
                    811:                                               &report_id);
                    812:                        size -= report_id != 0;
                    813:                        printf("Total %7s size %s%d bytes\n",
                    814:                               reptoparam[repindex].name,
                    815:                               report_id && size ? "1+" : "", size);
                    816:                }
                    817:        }
                    818:
                    819:        hid_dispose_report_desc(repdesc);
                    820:        exit(0);
                    821:        /* NOTREACHED */
                    822: }