1 /* $NetBSD: usbhid.c,v 1.34 2008/04/28 20:24:15 martin Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by David Sainty <David.Sainty@dtsp.co.nz>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: usbhid.c,v 1.34 2008/04/28 20:24:15 martin Exp $");
37 #include <sys/types.h>
39 #include <dev/usb/usb.h>
40 #include <dev/usb/usbhid.h>
54 * Zero if not in a verbose mode. Greater levels of verbosity
55 * are indicated by values larger than one.
60 #define DELIM_USAGE '.'
61 #define DELIM_PAGE ':'
63 #define DELIM_INSTANCE '#'
68 /* Variable name, not NUL terminated */
72 char const *value
; /* Value to set variable to */
74 #define MATCH_ALL (1 << 0)
75 #define MATCH_COLLECTIONS (1 << 1)
76 #define MATCH_NODATA (1 << 2)
77 #define MATCH_CONSTANTS (1 << 3)
78 #define MATCH_WASMATCHED (1 << 4)
79 #define MATCH_SHOWPAGENAME (1 << 5)
80 #define MATCH_SHOWNUMERIC (1 << 6)
81 #define MATCH_WRITABLE (1 << 7)
82 #define MATCH_SHOWVALUES (1 << 8)
86 * An instance number can be used to identify an item by
87 * position as well as by name. This allows us to manipulate
88 * devices that don't assign unique names to all usage items.
92 /* Workspace for hidmatch() */
96 int (*opfunc
)(struct hid_item
*item
, struct Susbvar
*var
,
97 u_int32_t
const *collist
, size_t collen
, u_char
*buf
);
101 struct usb_ctl_report
*buffer
;
103 enum {srs_uninit
, srs_clean
, srs_dirty
} status
;
104 int use_getreport
; /* Non-zero if we expect USB_GET_REPORT to work */
113 } const reptoparam
[] = {
114 #define REPORT_INPUT 0
115 { UHID_INPUT_REPORT
, hid_input
, "input" },
116 #define REPORT_OUTPUT 1
117 { UHID_OUTPUT_REPORT
, hid_output
, "output" },
118 #define REPORT_FEATURE 2
119 { UHID_FEATURE_REPORT
, hid_feature
, "feature" }
120 #define REPORT_MAXVAL 2
124 * Extract 16-bit unsigned usage ID from a numeric string. Returns -1
125 * if string failed to parse correctly.
128 strtousage(const char *nptr
, size_t nlen
)
134 if (nlen
>= sizeof(numstr
) || !isdigit((unsigned char)*nptr
))
138 * We use strtol() here, but unfortunately strtol() requires a
139 * NUL terminated string - which we don't have - at least not
142 memcpy(numstr
, nptr
, nlen
);
145 result
= strtol(numstr
, &endptr
, 0);
147 if (result
< 0 || result
> 0xffff || endptr
!= &numstr
[nlen
])
154 char const *page_name
;
155 char const *usage_name
;
163 * Test a rule against the current usage data. Returns -1 on no
164 * match, 0 on partial match and 1 on complete match.
167 hidtestrule(struct Susbvar
*var
, struct usagedata
*cache
)
170 ssize_t matchindex
, pagesplit
;
171 size_t strind
, varlen
;
175 matchindex
= var
->matchindex
;
176 varname
= var
->variable
;
177 varlen
= var
->varlen
;
179 usage_id
= cache
->usage_id
;
182 * Parse the current variable name, locating the end of the
183 * current 'usage', and possibly where the usage page name
187 for (strind
= matchindex
; strind
< varlen
; strind
++) {
188 if (varname
[strind
] == DELIM_USAGE
)
190 if (varname
[strind
] == DELIM_PAGE
)
194 if (cache
->isfinal
&& strind
!= varlen
)
196 * Variable name is too long (hit delimiter instead of
201 if (pagesplit
>= 0) {
203 * Page name was specified, determine whether it was
204 * symbolic or numeric.
206 char const *strstart
;
209 strstart
= &varname
[matchindex
];
211 numpage
= strtousage(strstart
, pagesplit
- matchindex
);
216 if (numpage
!= (int)HID_PAGE(usage_id
))
217 /* Numeric didn't match page ID */
220 /* Not a valid numeric */
223 * Load and cache the page name if and only if
224 * it hasn't already been loaded (it's a
225 * fairly expensive operation).
227 if (cache
->page_name
== NULL
) {
228 cache
->page_name
= hid_usage_page(HID_PAGE(usage_id
));
229 cache
->page_len
= strlen(cache
->page_name
);
233 * Compare specified page name to actual page
236 if (cache
->page_len
!=
237 (size_t)(pagesplit
- matchindex
) ||
238 memcmp(cache
->page_name
,
239 &varname
[matchindex
],
240 cache
->page_len
) != 0)
241 /* Mismatch, page name wrong */
245 /* Page matches, discard page name */
246 matchindex
= pagesplit
+ 1;
249 numusage
= strtousage(&varname
[matchindex
], strind
- matchindex
);
254 if (numusage
!= (int)HID_USAGE(usage_id
))
255 /* Numeric didn't match usage ID */
258 /* Not a valid numeric */
260 /* Load and cache the usage name */
261 if (cache
->usage_name
== NULL
) {
262 cache
->usage_name
= hid_usage_in_page(usage_id
);
263 cache
->usage_len
= strlen(cache
->usage_name
);
267 * Compare specified usage name to actual usage name
269 if (cache
->usage_len
!= (size_t)(strind
- matchindex
) ||
270 memcmp(cache
->usage_name
, &varname
[matchindex
],
271 cache
->usage_len
) != 0)
272 /* Mismatch, usage name wrong */
281 * Partial match: Move index past this usage string +
284 var
->matchindex
= strind
+ 1;
290 * Clear state in HID variable records used by hidmatch().
293 resethidvars(struct Susbvar
*varlist
, size_t vlsize
)
296 for (vlind
= 0; vlind
< vlsize
; vlind
++)
297 varlist
[vlind
].matchcount
= 0;
301 * hidmatch() determines whether the item specified in 'item', and
302 * nested within a hierarchy of collections specified in 'collist'
303 * matches any of the rules in the list 'varlist'. Returns the
304 * matching rule on success, or NULL on no match.
306 static struct Susbvar
*
307 hidmatch(u_int32_t
const *collist
, size_t collen
, struct hid_item
*item
,
308 struct Susbvar
*varlist
, size_t vlsize
)
310 struct Susbvar
*result
;
311 size_t colind
, vlactive
, vlind
;
315 * Keep track of how many variables are still "active". When
316 * the active count reaches zero, don't bother to continue
317 * looking for matches.
321 iscollection
= item
->kind
== hid_collection
||
322 item
->kind
== hid_endcollection
;
324 for (vlind
= 0; vlind
< vlsize
; vlind
++) {
327 var
= &varlist
[vlind
];
331 if (!(var
->mflags
& MATCH_COLLECTIONS
) && iscollection
) {
332 /* Don't match collections for this variable */
333 var
->matchindex
= -1;
335 } else if (!iscollection
&& !(var
->mflags
& MATCH_CONSTANTS
) &&
336 (item
->flags
& HIO_CONST
)) {
338 * Don't match constants for this variable,
339 * but ignore the constant bit on collections.
341 var
->matchindex
= -1;
343 } else if ((var
->mflags
& MATCH_WRITABLE
) &&
344 ((item
->kind
!= hid_output
&&
345 item
->kind
!= hid_feature
) ||
346 (item
->flags
& HIO_CONST
))) {
348 * If we are only matching writable items, if
349 * this is not an output or feature kind, or
350 * it is a constant, reject it.
352 var
->matchindex
= -1;
354 } else if (var
->mflags
& MATCH_ALL
) {
355 /* Match immediately */
356 return &varlist
[vlind
];
361 * Loop through each usage in the collection list, including
362 * the 'item' itself on the final iteration. For each usage,
363 * test which variables named in the rule list are still
364 * applicable - if any.
367 for (colind
= 0; vlactive
> 0 && colind
<= collen
; colind
++) {
368 struct usagedata cache
;
370 cache
.page_len
= 0; /* XXX gcc */
371 cache
.usage_len
= 0; /* XXX gcc */
373 cache
.isfinal
= (colind
== collen
);
375 cache
.usage_id
= item
->usage
;
377 cache
.usage_id
= collist
[colind
];
379 cache
.usage_name
= NULL
;
380 cache
.page_name
= NULL
;
383 * Loop through each rule, testing whether the rule is
384 * still applicable or not. For each rule,
385 * 'matchindex' retains the current match state as an
386 * index into the variable name string, or -1 if this
387 * rule has been proven not to match.
389 for (vlind
= 0; vlind
< vlsize
; vlind
++) {
393 var
= &varlist
[vlind
];
395 if (var
->matchindex
< 0)
396 /* Mismatch at a previous level */
399 matchres
= hidtestrule(var
, &cache
);
407 if (var
->usageinstance
< 0 ||
408 var
->matchcount
== var
->usageinstance
)
414 * We either matched completely, or not at
415 * all. Either way, this variable is no
418 var
->matchindex
= -1;
427 allocreport(struct Sreport
*report
, report_desc_t rd
, int repindex
)
431 reptsize
= hid_report_size(rd
, reptoparam
[repindex
].hid_kind
, reportid
);
433 errx(1, "Negative report size");
434 report
->size
= reptsize
;
436 if (report
->size
> 0) {
438 * Allocate a buffer with enough space for the
439 * report in the variable-sized data field.
441 report
->buffer
= malloc(sizeof(*report
->buffer
) -
442 sizeof(report
->buffer
->ucr_data
) +
444 if (report
->buffer
== NULL
)
447 report
->buffer
= NULL
;
449 report
->status
= srs_clean
;
453 freereport(struct Sreport
*report
)
455 if (report
->buffer
!= NULL
)
456 free(report
->buffer
);
457 report
->status
= srs_uninit
;
461 getreport(struct Sreport
*report
, int hidfd
, report_desc_t rd
, int repindex
)
463 if (report
->status
== srs_uninit
) {
464 allocreport(report
, rd
, repindex
);
465 if (report
->size
== 0)
468 report
->buffer
->ucr_report
= reptoparam
[repindex
].uhid_report
;
470 if (report
->use_getreport
) {
471 if (ioctl(hidfd
, USB_GET_REPORT
, report
->buffer
) < 0)
472 err(1, "USB_GET_REPORT(%s) [probably not "
473 "supported by device]",
474 reptoparam
[repindex
].name
);
476 memset(report
->buffer
->ucr_data
, '\0', report
->size
);
482 setreport(struct Sreport
*report
, int hidfd
, int repindex
)
484 if (report
->status
== srs_dirty
) {
485 report
->buffer
->ucr_report
= reptoparam
[repindex
].uhid_report
;
487 if (ioctl(hidfd
, USB_SET_REPORT
, report
->buffer
) < 0)
488 err(1, "USB_SET_REPORT(%s)",
489 reptoparam
[repindex
].name
);
491 report
->status
= srs_clean
;
497 varop_value(struct hid_item
*item
, struct Susbvar
*var
,
498 u_int32_t
const *collist
, size_t collen
, u_char
*buf
)
500 printf("%d\n", hid_get_data(buf
, item
));
506 varop_display(struct hid_item
*item
, struct Susbvar
*var
,
507 u_int32_t
const *collist
, size_t collen
, u_char
*buf
)
512 for (i
= 0; i
< item
->report_count
; i
++) {
513 for (colitem
= 0; colitem
< collen
; colitem
++) {
514 if (var
->mflags
& MATCH_SHOWPAGENAME
)
516 hid_usage_page(HID_PAGE(collist
[colitem
])));
517 printf("%s.", hid_usage_in_page(collist
[colitem
]));
519 if (var
->mflags
& MATCH_SHOWPAGENAME
)
520 printf("%s:", hid_usage_page(HID_PAGE(item
->usage
)));
521 val
= hid_get_data(buf
, item
);
522 item
->pos
+= item
->report_size
;
523 if (item
->usage_minimum
!= 0 || item
->usage_maximum
!= 0) {
524 val
+= item
->usage_minimum
;
525 printf("%s=1", hid_usage_in_page(val
));
527 printf("%s=%d%s", hid_usage_in_page(item
->usage
),
528 val
, item
->flags
& HIO_CONST
? " (const)" : "");
530 if (item
->report_count
> 1)
539 varop_modify(struct hid_item
*item
, struct Susbvar
*var
,
540 u_int32_t
const *collist
, size_t collen
, u_char
*buf
)
544 dataval
= (u_int
)strtol(var
->value
, NULL
, 10);
546 hid_set_data(buf
, item
, dataval
);
548 if (var
->mflags
& MATCH_SHOWVALUES
)
549 /* Display set value */
550 varop_display(item
, var
, collist
, collen
, buf
);
556 reportitem(char const *label
, struct hid_item
const *item
, unsigned int mflags
)
558 int isconst
= item
->flags
& HIO_CONST
,
559 isvar
= item
->flags
& HIO_VARIABLE
;
560 printf("%s size=%d count=%d%s%s page=%s", label
,
561 item
->report_size
, item
->report_count
,
562 isconst
? " Const" : "",
563 !isvar
&& !isconst
? " Array" : "",
564 hid_usage_page(HID_PAGE(item
->usage
)));
565 if (item
->usage_minimum
!= 0 || item
->usage_maximum
!= 0) {
566 printf(" usage=%s..%s", hid_usage_in_page(item
->usage_minimum
),
567 hid_usage_in_page(item
->usage_maximum
));
568 if (mflags
& MATCH_SHOWNUMERIC
)
569 printf(" (%u:0x%x..%u:0x%x)",
570 HID_PAGE(item
->usage_minimum
),
571 HID_USAGE(item
->usage_minimum
),
572 HID_PAGE(item
->usage_maximum
),
573 HID_USAGE(item
->usage_maximum
));
575 printf(" usage=%s", hid_usage_in_page(item
->usage
));
576 if (mflags
& MATCH_SHOWNUMERIC
)
578 HID_PAGE(item
->usage
), HID_USAGE(item
->usage
));
580 printf(", logical range %d..%d",
581 item
->logical_minimum
, item
->logical_maximum
);
582 if (item
->physical_minimum
!= item
->physical_maximum
)
583 printf(", physical range %d..%d",
584 item
->physical_minimum
, item
->physical_maximum
);
586 printf(", unit=0x%02x exp=%d", item
->unit
,
587 item
->unit_exponent
);
593 varop_report(struct hid_item
*item
, struct Susbvar
*var
,
594 u_int32_t
const *collist
, size_t collen
, u_char
*buf
)
596 switch (item
->kind
) {
598 printf("Collection page=%s usage=%s",
599 hid_usage_page(HID_PAGE(item
->usage
)),
600 hid_usage_in_page(item
->usage
));
601 if (var
->mflags
& MATCH_SHOWNUMERIC
)
602 printf(" (%u:0x%x)\n",
603 HID_PAGE(item
->usage
), HID_USAGE(item
->usage
));
607 case hid_endcollection
:
608 printf("End collection\n");
611 reportitem("Input ", item
, var
->mflags
);
614 reportitem("Output ", item
, var
->mflags
);
617 reportitem("Feature", item
, var
->mflags
);
625 devloop(int hidfd
, report_desc_t rd
, struct Susbvar
*varlist
, size_t vlsize
)
628 struct hid_data
*hdata
;
629 size_t collind
, dlen
;
630 struct hid_item hitem
;
631 u_int32_t colls
[256];
632 struct Sreport inreport
;
634 allocreport(&inreport
, rd
, REPORT_INPUT
);
636 if (inreport
.size
<= 0)
637 errx(1, "Input report descriptor invalid length");
639 dlen
= inreport
.size
;
640 dbuf
= inreport
.buffer
->ucr_data
;
645 readlen
= read(hidfd
, dbuf
, dlen
);
647 err(1, "Device read error");
648 if (dlen
!= (size_t)readlen
)
649 errx(1, "Unexpected response length: %lu != %lu",
650 (unsigned long)readlen
, (unsigned long)dlen
);
653 resethidvars(varlist
, vlsize
);
655 hdata
= hid_start_parse(rd
, 1 << hid_input
, reportid
);
657 errx(1, "Failed to start parser");
659 while (hid_get_item(hdata
, &hitem
)) {
660 struct Susbvar
*matchvar
;
662 switch (hitem
.kind
) {
664 if (collind
>= (sizeof(colls
) / sizeof(*colls
)))
665 errx(1, "Excessive nested collections");
666 colls
[collind
++] = hitem
.usage
;
668 case hid_endcollection
:
670 errx(1, "Excessive collection ends");
677 errx(1, "Unexpected non-input item returned");
680 if (reportid
!= -1 && hitem
.report_ID
!= reportid
)
683 matchvar
= hidmatch(colls
, collind
, &hitem
,
686 if (matchvar
!= NULL
)
687 matchvar
->opfunc(&hitem
, matchvar
,
689 inreport
.buffer
->ucr_data
);
691 hid_end_parse(hdata
);
698 devshow(int hidfd
, report_desc_t rd
, struct Susbvar
*varlist
, size_t vlsize
,
699 int zeromode
, int kindset
)
701 struct hid_data
*hdata
;
702 size_t collind
, repind
, vlind
;
703 struct hid_item hitem
;
704 u_int32_t colls
[256];
705 struct Sreport reports
[REPORT_MAXVAL
+ 1];
708 for (repind
= 0; repind
< (sizeof(reports
) / sizeof(*reports
));
710 reports
[repind
].status
= srs_uninit
;
711 reports
[repind
].buffer
= NULL
;
712 reports
[repind
].use_getreport
= !zeromode
;
716 resethidvars(varlist
, vlsize
);
718 hdata
= hid_start_parse(rd
, kindset
, reportid
);
720 errx(1, "Failed to start parser");
722 while (hid_get_item(hdata
, &hitem
)) {
723 struct Susbvar
*matchvar
;
727 printf("item: kind=%d repid=%d usage=0x%x\n",
728 hitem
.kind
, hitem
.report_ID
, hitem
.usage
);
730 switch (hitem
.kind
) {
732 if (collind
>= (sizeof(colls
) / sizeof(*colls
)))
733 errx(1, "Excessive nested collections");
734 colls
[collind
++] = hitem
.usage
;
736 case hid_endcollection
:
738 errx(1, "Excessive collection ends");
742 repindex
= REPORT_INPUT
;
745 repindex
= REPORT_OUTPUT
;
748 repindex
= REPORT_FEATURE
;
752 if (reportid
!= -1 && hitem
.report_ID
!= reportid
)
755 matchvar
= hidmatch(colls
, collind
, &hitem
, varlist
, vlsize
);
757 if (matchvar
!= NULL
) {
759 struct Sreport
*repptr
;
761 matchvar
->mflags
|= MATCH_WASMATCHED
;
764 repptr
= &reports
[repindex
];
768 if (repptr
!= NULL
&&
769 !(matchvar
->mflags
& MATCH_NODATA
))
770 getreport(repptr
, hidfd
, rd
, repindex
);
772 bufdata
= (repptr
== NULL
|| repptr
->buffer
== NULL
) ?
773 NULL
: repptr
->buffer
->ucr_data
;
775 if (matchvar
->opfunc(&hitem
, matchvar
, colls
, collind
,
777 repptr
->status
= srs_dirty
;
780 hid_end_parse(hdata
);
782 for (repind
= 0; repind
< (sizeof(reports
) / sizeof(*reports
));
784 setreport(&reports
[repind
], hidfd
, repind
);
785 freereport(&reports
[repind
]);
788 /* Warn about any items that we couldn't find a match for */
789 for (vlind
= 0; vlind
< vlsize
; vlind
++) {
792 var
= &varlist
[vlind
];
794 if (var
->variable
!= NULL
&&
795 !(var
->mflags
& MATCH_WASMATCHED
))
796 warnx("Failed to match: %.*s", (int)var
->varlen
,
804 const char *progname
= getprogname();
806 fprintf(stderr
, "usage: %s -f device [-t tablefile] [-lv] -a\n",
808 fprintf(stderr
, " %s -f device [-t tablefile] [-v] -r\n",
811 " %s -f device [-t tablefile] [-lnv] item [...]\n",
814 " %s -f device [-t tablefile] [-z] -w item=value [...]\n",
820 main(int argc
, char **argv
)
825 int aflag
, lflag
, nflag
, rflag
, wflag
, zflag
;
827 report_desc_t repdesc
;
828 char devnamebuf
[PATH_MAX
];
829 struct Susbvar variables
[128];
831 aflag
= lflag
= nflag
= rflag
= verbose
= wflag
= zflag
= 0;
834 while ((ch
= getopt(argc
, argv
, "?af:lnrt:vwz")) != -1) {
871 if (dev
== NULL
|| (lflag
&& (wflag
|| rflag
))) {
873 * No device specified, or attempting to loop and set
874 * or dump report at the same time
880 for (varnum
= 0; varnum
< (size_t)argc
; varnum
++) {
881 char const *name
, *valuesep
, *varinst
;
882 struct Susbvar
*svar
;
885 svar
= &variables
[varnum
];
887 valuesep
= strchr(name
, DELIM_SET
);
889 svar
->variable
= name
;
891 svar
->usageinstance
= 0;
893 if (valuesep
== NULL
) {
896 errx(1, "Must not specify -w to read variables");
898 namelen
= strlen(name
);
901 /* Display value of variable only */
902 svar
->opfunc
= varop_value
;
904 /* Display name and value of variable */
905 svar
->opfunc
= varop_display
;
908 /* Show page names in verbose modes */
909 svar
->mflags
|= MATCH_SHOWPAGENAME
;
914 errx(2, "Must specify -w to set variables");
915 svar
->mflags
|= MATCH_WRITABLE
;
918 * Allow displaying of set value in
919 * verbose mode. This isn't
920 * particularly useful though, so
921 * don't bother documenting it.
923 svar
->mflags
|= MATCH_SHOWVALUES
;
924 namelen
= valuesep
- name
;
925 svar
->value
= valuesep
+ 1;
926 svar
->opfunc
= varop_modify
;
929 varinst
= memchr(name
, DELIM_INSTANCE
, namelen
);
931 if (varinst
!= NULL
&& ++varinst
!= &name
[namelen
]) {
934 svar
->usageinstance
= strtol(varinst
, &endptr
, 0);
936 if (&name
[namelen
] != (char const*)endptr
)
937 errx(1, "%s%c%s", "Error parsing item "
938 "instance number after '",
939 DELIM_INSTANCE
, "'");
941 namelen
= varinst
- 1 - name
;
944 svar
->varlen
= namelen
;
947 if (aflag
|| rflag
) {
948 struct Susbvar
*svar
;
950 svar
= &variables
[varnum
++];
952 svar
->variable
= NULL
;
953 svar
->mflags
= MATCH_ALL
;
957 * Dump report descriptor. Do dump collection
958 * items also, and hint that it won't be
959 * necessary to get the item status.
961 svar
->opfunc
= varop_report
;
962 svar
->mflags
|= MATCH_COLLECTIONS
| MATCH_NODATA
;
966 /* Level 2: Show item numerics and constants */
967 svar
->mflags
|= MATCH_SHOWNUMERIC
;
970 /* Level 1: Just show constants */
971 svar
->mflags
|= MATCH_CONSTANTS
;
977 /* Display name and value of variable */
978 svar
->opfunc
= varop_display
;
982 /* Level 2: Show constants and page names */
983 svar
->mflags
|= MATCH_CONSTANTS
;
986 /* Level 1: Just show page names */
987 svar
->mflags
|= MATCH_SHOWPAGENAME
;
996 /* Nothing to do... Display usage information. */
1003 if (dev
[0] != '/') {
1004 snprintf(devnamebuf
, sizeof(devnamebuf
), "/dev/%s%s",
1005 isdigit((unsigned char)dev
[0]) ? "uhid" : "", dev
);
1009 hidfd
= open(dev
, O_RDWR
);
1013 if (ioctl(hidfd
, USB_GET_REPORT_ID
, &reportid
) < 0)
1016 printf("report ID=%d\n", reportid
);
1017 repdesc
= hid_get_report_desc(hidfd
);
1019 errx(1, "USB_GET_REPORT_DESC");
1022 devloop(hidfd
, repdesc
, variables
, varnum
);
1027 /* Report mode header */
1028 printf("Report descriptor:\n");
1030 devshow(hidfd
, repdesc
, variables
, varnum
, zflag
,
1036 /* Report mode trailer */
1039 repindex
< (sizeof(reptoparam
) / sizeof(*reptoparam
));
1042 size
= hid_report_size(repdesc
,
1043 reptoparam
[repindex
].hid_kind
,
1045 printf("Total %7s size %d bytes\n",
1046 reptoparam
[repindex
].name
, size
);
1050 hid_dispose_report_desc(repdesc
);