1 1.38 dsainty /* $NetBSD: usbhid.c,v 1.38 2019/09/22 07:34:33 dsainty Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.18 augustss * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.5 augustss * This code is derived from software contributed to The NetBSD Foundation 8 1.38 dsainty * by David Sainty <dsainty (at) NetBSD.org> 9 1.1 augustss * 10 1.1 augustss * Redistribution and use in source and binary forms, with or without 11 1.1 augustss * modification, are permitted provided that the following conditions 12 1.1 augustss * are met: 13 1.1 augustss * 1. Redistributions of source code must retain the above copyright 14 1.1 augustss * notice, this list of conditions and the following disclaimer. 15 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 augustss * notice, this list of conditions and the following disclaimer in the 17 1.1 augustss * documentation and/or other materials provided with the distribution. 18 1.1 augustss * 19 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 30 1.1 augustss */ 31 1.23 agc #include <sys/cdefs.h> 32 1.23 agc 33 1.23 agc #ifndef lint 34 1.38 dsainty __RCSID("$NetBSD: usbhid.c,v 1.38 2019/09/22 07:34:33 dsainty Exp $"); 35 1.23 agc #endif 36 1.1 augustss 37 1.15 augustss #include <sys/types.h> 38 1.15 augustss 39 1.15 augustss #include <dev/usb/usb.h> 40 1.15 augustss #include <dev/usb/usbhid.h> 41 1.37 bouyer #include <dev/hid/hid.h> 42 1.15 augustss 43 1.15 augustss #include <ctype.h> 44 1.15 augustss #include <err.h> 45 1.15 augustss #include <errno.h> 46 1.15 augustss #include <fcntl.h> 47 1.15 augustss #include <limits.h> 48 1.1 augustss #include <stdio.h> 49 1.1 augustss #include <stdlib.h> 50 1.14 matt #include <string.h> 51 1.1 augustss #include <unistd.h> 52 1.20 augustss #include <usbhid.h> 53 1.20 augustss 54 1.20 augustss /* 55 1.20 augustss * Zero if not in a verbose mode. Greater levels of verbosity 56 1.20 augustss * are indicated by values larger than one. 57 1.20 augustss */ 58 1.36 joerg static unsigned int verbose; 59 1.1 augustss 60 1.15 augustss /* Parser tokens */ 61 1.15 augustss #define DELIM_USAGE '.' 62 1.15 augustss #define DELIM_PAGE ':' 63 1.15 augustss #define DELIM_SET '=' 64 1.31 dsainty #define DELIM_INSTANCE '#' 65 1.15 augustss 66 1.20 augustss static int reportid; 67 1.20 augustss 68 1.15 augustss struct Susbvar { 69 1.15 augustss /* Variable name, not NUL terminated */ 70 1.15 augustss char const *variable; 71 1.15 augustss size_t varlen; 72 1.15 augustss 73 1.15 augustss char const *value; /* Value to set variable to */ 74 1.15 augustss 75 1.15 augustss #define MATCH_ALL (1 << 0) 76 1.15 augustss #define MATCH_COLLECTIONS (1 << 1) 77 1.15 augustss #define MATCH_NODATA (1 << 2) 78 1.15 augustss #define MATCH_CONSTANTS (1 << 3) 79 1.15 augustss #define MATCH_WASMATCHED (1 << 4) 80 1.15 augustss #define MATCH_SHOWPAGENAME (1 << 5) 81 1.15 augustss #define MATCH_SHOWNUMERIC (1 << 6) 82 1.15 augustss #define MATCH_WRITABLE (1 << 7) 83 1.18 augustss #define MATCH_SHOWVALUES (1 << 8) 84 1.15 augustss unsigned int mflags; 85 1.15 augustss 86 1.31 dsainty /* 87 1.31 dsainty * An instance number can be used to identify an item by 88 1.31 dsainty * position as well as by name. This allows us to manipulate 89 1.31 dsainty * devices that don't assign unique names to all usage items. 90 1.31 dsainty */ 91 1.31 dsainty int usageinstance; 92 1.31 dsainty 93 1.15 augustss /* Workspace for hidmatch() */ 94 1.15 augustss ssize_t matchindex; 95 1.31 dsainty int matchcount; 96 1.15 augustss 97 1.15 augustss int (*opfunc)(struct hid_item *item, struct Susbvar *var, 98 1.15 augustss u_int32_t const *collist, size_t collen, u_char *buf); 99 1.15 augustss }; 100 1.15 augustss 101 1.15 augustss struct Sreport { 102 1.15 augustss struct usb_ctl_report *buffer; 103 1.15 augustss 104 1.15 augustss enum {srs_uninit, srs_clean, srs_dirty} status; 105 1.32 dsainty int use_getreport; /* Non-zero if we expect USB_GET_REPORT to work */ 106 1.15 augustss int report_id; 107 1.15 augustss size_t size; 108 1.15 augustss }; 109 1.15 augustss 110 1.15 augustss static struct { 111 1.15 augustss int uhid_report; 112 1.15 augustss hid_kind_t hid_kind; 113 1.15 augustss char const *name; 114 1.15 augustss } const reptoparam[] = { 115 1.15 augustss #define REPORT_INPUT 0 116 1.15 augustss { UHID_INPUT_REPORT, hid_input, "input" }, 117 1.15 augustss #define REPORT_OUTPUT 1 118 1.15 augustss { UHID_OUTPUT_REPORT, hid_output, "output" }, 119 1.15 augustss #define REPORT_FEATURE 2 120 1.15 augustss { UHID_FEATURE_REPORT, hid_feature, "feature" } 121 1.15 augustss #define REPORT_MAXVAL 2 122 1.15 augustss }; 123 1.15 augustss 124 1.18 augustss /* 125 1.18 augustss * Extract 16-bit unsigned usage ID from a numeric string. Returns -1 126 1.18 augustss * if string failed to parse correctly. 127 1.18 augustss */ 128 1.18 augustss static int 129 1.18 augustss strtousage(const char *nptr, size_t nlen) 130 1.18 augustss { 131 1.18 augustss char *endptr; 132 1.18 augustss long result; 133 1.18 augustss char numstr[16]; 134 1.18 augustss 135 1.18 augustss if (nlen >= sizeof(numstr) || !isdigit((unsigned char)*nptr)) 136 1.18 augustss return -1; 137 1.18 augustss 138 1.18 augustss /* 139 1.18 augustss * We use strtol() here, but unfortunately strtol() requires a 140 1.18 augustss * NUL terminated string - which we don't have - at least not 141 1.18 augustss * officially. 142 1.18 augustss */ 143 1.18 augustss memcpy(numstr, nptr, nlen); 144 1.18 augustss numstr[nlen] = '\0'; 145 1.18 augustss 146 1.18 augustss result = strtol(numstr, &endptr, 0); 147 1.18 augustss 148 1.18 augustss if (result < 0 || result > 0xffff || endptr != &numstr[nlen]) 149 1.18 augustss return -1; 150 1.18 augustss 151 1.18 augustss return result; 152 1.18 augustss } 153 1.18 augustss 154 1.18 augustss struct usagedata { 155 1.18 augustss char const *page_name; 156 1.18 augustss char const *usage_name; 157 1.18 augustss size_t page_len; 158 1.18 augustss size_t usage_len; 159 1.18 augustss int isfinal; 160 1.18 augustss u_int32_t usage_id; 161 1.18 augustss }; 162 1.18 augustss 163 1.18 augustss /* 164 1.18 augustss * Test a rule against the current usage data. Returns -1 on no 165 1.18 augustss * match, 0 on partial match and 1 on complete match. 166 1.18 augustss */ 167 1.18 augustss static int 168 1.18 augustss hidtestrule(struct Susbvar *var, struct usagedata *cache) 169 1.18 augustss { 170 1.18 augustss char const *varname; 171 1.18 augustss ssize_t matchindex, pagesplit; 172 1.18 augustss size_t strind, varlen; 173 1.18 augustss int numusage; 174 1.18 augustss u_int32_t usage_id; 175 1.18 augustss 176 1.18 augustss matchindex = var->matchindex; 177 1.18 augustss varname = var->variable; 178 1.18 augustss varlen = var->varlen; 179 1.18 augustss 180 1.18 augustss usage_id = cache->usage_id; 181 1.18 augustss 182 1.18 augustss /* 183 1.18 augustss * Parse the current variable name, locating the end of the 184 1.18 augustss * current 'usage', and possibly where the usage page name 185 1.18 augustss * ends. 186 1.18 augustss */ 187 1.18 augustss pagesplit = -1; 188 1.18 augustss for (strind = matchindex; strind < varlen; strind++) { 189 1.18 augustss if (varname[strind] == DELIM_USAGE) 190 1.18 augustss break; 191 1.18 augustss if (varname[strind] == DELIM_PAGE) 192 1.18 augustss pagesplit = strind; 193 1.18 augustss } 194 1.18 augustss 195 1.18 augustss if (cache->isfinal && strind != varlen) 196 1.18 augustss /* 197 1.18 augustss * Variable name is too long (hit delimiter instead of 198 1.18 augustss * end-of-variable). 199 1.18 augustss */ 200 1.18 augustss return -1; 201 1.18 augustss 202 1.18 augustss if (pagesplit >= 0) { 203 1.18 augustss /* 204 1.18 augustss * Page name was specified, determine whether it was 205 1.31 dsainty * symbolic or numeric. 206 1.18 augustss */ 207 1.18 augustss char const *strstart; 208 1.18 augustss int numpage; 209 1.18 augustss 210 1.18 augustss strstart = &varname[matchindex]; 211 1.18 augustss 212 1.18 augustss numpage = strtousage(strstart, pagesplit - matchindex); 213 1.18 augustss 214 1.18 augustss if (numpage >= 0) { 215 1.18 augustss /* Valid numeric */ 216 1.18 augustss 217 1.35 lukem if (numpage != (int)HID_PAGE(usage_id)) 218 1.18 augustss /* Numeric didn't match page ID */ 219 1.18 augustss return -1; 220 1.18 augustss } else { 221 1.18 augustss /* Not a valid numeric */ 222 1.18 augustss 223 1.18 augustss /* 224 1.18 augustss * Load and cache the page name if and only if 225 1.18 augustss * it hasn't already been loaded (it's a 226 1.18 augustss * fairly expensive operation). 227 1.18 augustss */ 228 1.18 augustss if (cache->page_name == NULL) { 229 1.18 augustss cache->page_name = hid_usage_page(HID_PAGE(usage_id)); 230 1.18 augustss cache->page_len = strlen(cache->page_name); 231 1.18 augustss } 232 1.18 augustss 233 1.18 augustss /* 234 1.18 augustss * Compare specified page name to actual page 235 1.18 augustss * name. 236 1.18 augustss */ 237 1.18 augustss if (cache->page_len != 238 1.18 augustss (size_t)(pagesplit - matchindex) || 239 1.18 augustss memcmp(cache->page_name, 240 1.18 augustss &varname[matchindex], 241 1.18 augustss cache->page_len) != 0) 242 1.18 augustss /* Mismatch, page name wrong */ 243 1.18 augustss return -1; 244 1.18 augustss } 245 1.18 augustss 246 1.18 augustss /* Page matches, discard page name */ 247 1.18 augustss matchindex = pagesplit + 1; 248 1.18 augustss } 249 1.18 augustss 250 1.18 augustss numusage = strtousage(&varname[matchindex], strind - matchindex); 251 1.18 augustss 252 1.18 augustss if (numusage >= 0) { 253 1.18 augustss /* Valid numeric */ 254 1.18 augustss 255 1.35 lukem if (numusage != (int)HID_USAGE(usage_id)) 256 1.18 augustss /* Numeric didn't match usage ID */ 257 1.18 augustss return -1; 258 1.18 augustss } else { 259 1.18 augustss /* Not a valid numeric */ 260 1.18 augustss 261 1.18 augustss /* Load and cache the usage name */ 262 1.18 augustss if (cache->usage_name == NULL) { 263 1.18 augustss cache->usage_name = hid_usage_in_page(usage_id); 264 1.18 augustss cache->usage_len = strlen(cache->usage_name); 265 1.18 augustss } 266 1.18 augustss 267 1.18 augustss /* 268 1.18 augustss * Compare specified usage name to actual usage name 269 1.18 augustss */ 270 1.18 augustss if (cache->usage_len != (size_t)(strind - matchindex) || 271 1.18 augustss memcmp(cache->usage_name, &varname[matchindex], 272 1.18 augustss cache->usage_len) != 0) 273 1.18 augustss /* Mismatch, usage name wrong */ 274 1.18 augustss return -1; 275 1.18 augustss } 276 1.18 augustss 277 1.18 augustss if (cache->isfinal) 278 1.18 augustss /* Match */ 279 1.18 augustss return 1; 280 1.18 augustss 281 1.18 augustss /* 282 1.18 augustss * Partial match: Move index past this usage string + 283 1.18 augustss * delimiter 284 1.18 augustss */ 285 1.18 augustss var->matchindex = strind + 1; 286 1.18 augustss 287 1.18 augustss return 0; 288 1.18 augustss } 289 1.18 augustss 290 1.18 augustss /* 291 1.31 dsainty * Clear state in HID variable records used by hidmatch(). 292 1.31 dsainty */ 293 1.31 dsainty static void 294 1.31 dsainty resethidvars(struct Susbvar *varlist, size_t vlsize) 295 1.31 dsainty { 296 1.31 dsainty size_t vlind; 297 1.31 dsainty for (vlind = 0; vlind < vlsize; vlind++) 298 1.31 dsainty varlist[vlind].matchcount = 0; 299 1.31 dsainty } 300 1.31 dsainty 301 1.31 dsainty /* 302 1.18 augustss * hidmatch() determines whether the item specified in 'item', and 303 1.25 dsainty * nested within a hierarchy of collections specified in 'collist' 304 1.18 augustss * matches any of the rules in the list 'varlist'. Returns the 305 1.18 augustss * matching rule on success, or NULL on no match. 306 1.18 augustss */ 307 1.15 augustss static struct Susbvar* 308 1.15 augustss hidmatch(u_int32_t const *collist, size_t collen, struct hid_item *item, 309 1.15 augustss struct Susbvar *varlist, size_t vlsize) 310 1.15 augustss { 311 1.31 dsainty struct Susbvar *result; 312 1.18 augustss size_t colind, vlactive, vlind; 313 1.15 augustss int iscollection; 314 1.15 augustss 315 1.15 augustss /* 316 1.15 augustss * Keep track of how many variables are still "active". When 317 1.15 augustss * the active count reaches zero, don't bother to continue 318 1.15 augustss * looking for matches. 319 1.15 augustss */ 320 1.15 augustss vlactive = vlsize; 321 1.15 augustss 322 1.15 augustss iscollection = item->kind == hid_collection || 323 1.15 augustss item->kind == hid_endcollection; 324 1.15 augustss 325 1.15 augustss for (vlind = 0; vlind < vlsize; vlind++) { 326 1.15 augustss struct Susbvar *var; 327 1.15 augustss 328 1.15 augustss var = &varlist[vlind]; 329 1.15 augustss 330 1.15 augustss var->matchindex = 0; 331 1.15 augustss 332 1.15 augustss if (!(var->mflags & MATCH_COLLECTIONS) && iscollection) { 333 1.15 augustss /* Don't match collections for this variable */ 334 1.15 augustss var->matchindex = -1; 335 1.15 augustss vlactive--; 336 1.15 augustss } else if (!iscollection && !(var->mflags & MATCH_CONSTANTS) && 337 1.15 augustss (item->flags & HIO_CONST)) { 338 1.15 augustss /* 339 1.15 augustss * Don't match constants for this variable, 340 1.15 augustss * but ignore the constant bit on collections. 341 1.15 augustss */ 342 1.15 augustss var->matchindex = -1; 343 1.15 augustss vlactive--; 344 1.15 augustss } else if ((var->mflags & MATCH_WRITABLE) && 345 1.15 augustss ((item->kind != hid_output && 346 1.15 augustss item->kind != hid_feature) || 347 1.15 augustss (item->flags & HIO_CONST))) { 348 1.15 augustss /* 349 1.15 augustss * If we are only matching writable items, if 350 1.15 augustss * this is not an output or feature kind, or 351 1.15 augustss * it is a constant, reject it. 352 1.15 augustss */ 353 1.15 augustss var->matchindex = -1; 354 1.15 augustss vlactive--; 355 1.15 augustss } else if (var->mflags & MATCH_ALL) { 356 1.15 augustss /* Match immediately */ 357 1.15 augustss return &varlist[vlind]; 358 1.15 augustss } 359 1.15 augustss } 360 1.15 augustss 361 1.18 augustss /* 362 1.18 augustss * Loop through each usage in the collection list, including 363 1.18 augustss * the 'item' itself on the final iteration. For each usage, 364 1.18 augustss * test which variables named in the rule list are still 365 1.18 augustss * applicable - if any. 366 1.18 augustss */ 367 1.31 dsainty result = NULL; 368 1.15 augustss for (colind = 0; vlactive > 0 && colind <= collen; colind++) { 369 1.18 augustss struct usagedata cache; 370 1.15 augustss 371 1.30 mrg cache.page_len = 0; /* XXX gcc */ 372 1.30 mrg cache.usage_len = 0; /* XXX gcc */ 373 1.30 mrg 374 1.18 augustss cache.isfinal = (colind == collen); 375 1.18 augustss if (cache.isfinal) 376 1.18 augustss cache.usage_id = item->usage; 377 1.15 augustss else 378 1.18 augustss cache.usage_id = collist[colind]; 379 1.15 augustss 380 1.18 augustss cache.usage_name = NULL; 381 1.18 augustss cache.page_name = NULL; 382 1.15 augustss 383 1.18 augustss /* 384 1.18 augustss * Loop through each rule, testing whether the rule is 385 1.18 augustss * still applicable or not. For each rule, 386 1.18 augustss * 'matchindex' retains the current match state as an 387 1.18 augustss * index into the variable name string, or -1 if this 388 1.18 augustss * rule has been proven not to match. 389 1.18 augustss */ 390 1.15 augustss for (vlind = 0; vlind < vlsize; vlind++) { 391 1.15 augustss struct Susbvar *var; 392 1.18 augustss int matchres; 393 1.15 augustss 394 1.15 augustss var = &varlist[vlind]; 395 1.15 augustss 396 1.18 augustss if (var->matchindex < 0) 397 1.15 augustss /* Mismatch at a previous level */ 398 1.15 augustss continue; 399 1.15 augustss 400 1.18 augustss matchres = hidtestrule(var, &cache); 401 1.15 augustss 402 1.31 dsainty if (matchres == 0) 403 1.31 dsainty /* Partial match */ 404 1.15 augustss continue; 405 1.31 dsainty 406 1.31 dsainty if (matchres > 0) { 407 1.18 augustss /* Complete match */ 408 1.31 dsainty if (var->usageinstance < 0 || 409 1.31 dsainty var->matchcount == var->usageinstance) 410 1.31 dsainty result = var; 411 1.31 dsainty var->matchcount++; 412 1.15 augustss } 413 1.31 dsainty 414 1.31 dsainty /* 415 1.31 dsainty * We either matched completely, or not at 416 1.31 dsainty * all. Either way, this variable is no 417 1.31 dsainty * longer active. 418 1.31 dsainty */ 419 1.31 dsainty var->matchindex = -1; 420 1.31 dsainty vlactive--; 421 1.15 augustss } 422 1.15 augustss } 423 1.15 augustss 424 1.31 dsainty return result; 425 1.15 augustss } 426 1.15 augustss 427 1.15 augustss static void 428 1.15 augustss allocreport(struct Sreport *report, report_desc_t rd, int repindex) 429 1.15 augustss { 430 1.15 augustss int reptsize; 431 1.15 augustss 432 1.20 augustss reptsize = hid_report_size(rd, reptoparam[repindex].hid_kind, reportid); 433 1.15 augustss if (reptsize < 0) 434 1.15 augustss errx(1, "Negative report size"); 435 1.15 augustss report->size = reptsize; 436 1.15 augustss 437 1.15 augustss if (report->size > 0) { 438 1.15 augustss /* 439 1.15 augustss * Allocate a buffer with enough space for the 440 1.15 augustss * report in the variable-sized data field. 441 1.15 augustss */ 442 1.15 augustss report->buffer = malloc(sizeof(*report->buffer) - 443 1.22 christos sizeof(report->buffer->ucr_data) + 444 1.15 augustss report->size); 445 1.15 augustss if (report->buffer == NULL) 446 1.15 augustss err(1, NULL); 447 1.15 augustss } else 448 1.15 augustss report->buffer = NULL; 449 1.3 augustss 450 1.15 augustss report->status = srs_clean; 451 1.15 augustss } 452 1.15 augustss 453 1.15 augustss static void 454 1.15 augustss freereport(struct Sreport *report) 455 1.15 augustss { 456 1.15 augustss if (report->buffer != NULL) 457 1.15 augustss free(report->buffer); 458 1.15 augustss report->status = srs_uninit; 459 1.15 augustss } 460 1.15 augustss 461 1.15 augustss static void 462 1.15 augustss getreport(struct Sreport *report, int hidfd, report_desc_t rd, int repindex) 463 1.15 augustss { 464 1.15 augustss if (report->status == srs_uninit) { 465 1.15 augustss allocreport(report, rd, repindex); 466 1.15 augustss if (report->size == 0) 467 1.15 augustss return; 468 1.15 augustss 469 1.22 christos report->buffer->ucr_report = reptoparam[repindex].uhid_report; 470 1.32 dsainty 471 1.32 dsainty if (report->use_getreport) { 472 1.32 dsainty if (ioctl(hidfd, USB_GET_REPORT, report->buffer) < 0) 473 1.32 dsainty err(1, "USB_GET_REPORT(%s) [probably not " 474 1.32 dsainty "supported by device]", 475 1.32 dsainty reptoparam[repindex].name); 476 1.32 dsainty } else { 477 1.32 dsainty memset(report->buffer->ucr_data, '\0', report->size); 478 1.32 dsainty } 479 1.15 augustss } 480 1.15 augustss } 481 1.15 augustss 482 1.15 augustss static void 483 1.15 augustss setreport(struct Sreport *report, int hidfd, int repindex) 484 1.3 augustss { 485 1.15 augustss if (report->status == srs_dirty) { 486 1.22 christos report->buffer->ucr_report = reptoparam[repindex].uhid_report; 487 1.3 augustss 488 1.15 augustss if (ioctl(hidfd, USB_SET_REPORT, report->buffer) < 0) 489 1.15 augustss err(1, "USB_SET_REPORT(%s)", 490 1.15 augustss reptoparam[repindex].name); 491 1.15 augustss 492 1.15 augustss report->status = srs_clean; 493 1.15 augustss } 494 1.15 augustss } 495 1.15 augustss 496 1.15 augustss /* ARGSUSED1 */ 497 1.15 augustss static int 498 1.15 augustss varop_value(struct hid_item *item, struct Susbvar *var, 499 1.15 augustss u_int32_t const *collist, size_t collen, u_char *buf) 500 1.15 augustss { 501 1.15 augustss printf("%d\n", hid_get_data(buf, item)); 502 1.3 augustss return 0; 503 1.3 augustss } 504 1.1 augustss 505 1.15 augustss /* ARGSUSED1 */ 506 1.15 augustss static int 507 1.15 augustss varop_display(struct hid_item *item, struct Susbvar *var, 508 1.15 augustss u_int32_t const *collist, size_t collen, u_char *buf) 509 1.1 augustss { 510 1.15 augustss size_t colitem; 511 1.21 augustss int val, i; 512 1.1 augustss 513 1.21 augustss for (i = 0; i < item->report_count; i++) { 514 1.21 augustss for (colitem = 0; colitem < collen; colitem++) { 515 1.21 augustss if (var->mflags & MATCH_SHOWPAGENAME) 516 1.21 augustss printf("%s:", 517 1.21 augustss hid_usage_page(HID_PAGE(collist[colitem]))); 518 1.21 augustss printf("%s.", hid_usage_in_page(collist[colitem])); 519 1.21 augustss } 520 1.15 augustss if (var->mflags & MATCH_SHOWPAGENAME) 521 1.21 augustss printf("%s:", hid_usage_page(HID_PAGE(item->usage))); 522 1.21 augustss val = hid_get_data(buf, item); 523 1.21 augustss item->pos += item->report_size; 524 1.21 augustss if (item->usage_minimum != 0 || item->usage_maximum != 0) { 525 1.21 augustss val += item->usage_minimum; 526 1.21 augustss printf("%s=1", hid_usage_in_page(val)); 527 1.21 augustss } else { 528 1.21 augustss printf("%s=%d%s", hid_usage_in_page(item->usage), 529 1.21 augustss val, item->flags & HIO_CONST ? " (const)" : ""); 530 1.21 augustss } 531 1.21 augustss if (item->report_count > 1) 532 1.21 augustss printf(" [%d]", i); 533 1.21 augustss printf("\n"); 534 1.15 augustss } 535 1.15 augustss return 0; 536 1.1 augustss } 537 1.1 augustss 538 1.15 augustss /* ARGSUSED1 */ 539 1.15 augustss static int 540 1.15 augustss varop_modify(struct hid_item *item, struct Susbvar *var, 541 1.15 augustss u_int32_t const *collist, size_t collen, u_char *buf) 542 1.1 augustss { 543 1.15 augustss u_int dataval; 544 1.15 augustss 545 1.15 augustss dataval = (u_int)strtol(var->value, NULL, 10); 546 1.15 augustss 547 1.15 augustss hid_set_data(buf, item, dataval); 548 1.15 augustss 549 1.18 augustss if (var->mflags & MATCH_SHOWVALUES) 550 1.18 augustss /* Display set value */ 551 1.15 augustss varop_display(item, var, collist, collen, buf); 552 1.1 augustss 553 1.15 augustss return 1; 554 1.1 augustss } 555 1.1 augustss 556 1.15 augustss static void 557 1.15 augustss reportitem(char const *label, struct hid_item const *item, unsigned int mflags) 558 1.8 augustss { 559 1.20 augustss int isconst = item->flags & HIO_CONST, 560 1.20 augustss isvar = item->flags & HIO_VARIABLE; 561 1.20 augustss printf("%s size=%d count=%d%s%s page=%s", label, 562 1.15 augustss item->report_size, item->report_count, 563 1.20 augustss isconst ? " Const" : "", 564 1.20 augustss !isvar && !isconst ? " Array" : "", 565 1.20 augustss hid_usage_page(HID_PAGE(item->usage))); 566 1.20 augustss if (item->usage_minimum != 0 || item->usage_maximum != 0) { 567 1.20 augustss printf(" usage=%s..%s", hid_usage_in_page(item->usage_minimum), 568 1.20 augustss hid_usage_in_page(item->usage_maximum)); 569 1.20 augustss if (mflags & MATCH_SHOWNUMERIC) 570 1.20 augustss printf(" (%u:0x%x..%u:0x%x)", 571 1.20 augustss HID_PAGE(item->usage_minimum), 572 1.20 augustss HID_USAGE(item->usage_minimum), 573 1.20 augustss HID_PAGE(item->usage_maximum), 574 1.20 augustss HID_USAGE(item->usage_maximum)); 575 1.20 augustss } else { 576 1.20 augustss printf(" usage=%s", hid_usage_in_page(item->usage)); 577 1.20 augustss if (mflags & MATCH_SHOWNUMERIC) 578 1.20 augustss printf(" (%u:0x%x)", 579 1.20 augustss HID_PAGE(item->usage), HID_USAGE(item->usage)); 580 1.20 augustss } 581 1.8 augustss printf(", logical range %d..%d", 582 1.15 augustss item->logical_minimum, item->logical_maximum); 583 1.15 augustss if (item->physical_minimum != item->physical_maximum) 584 1.8 augustss printf(", physical range %d..%d", 585 1.15 augustss item->physical_minimum, item->physical_maximum); 586 1.15 augustss if (item->unit) 587 1.15 augustss printf(", unit=0x%02x exp=%d", item->unit, 588 1.15 augustss item->unit_exponent); 589 1.8 augustss printf("\n"); 590 1.8 augustss } 591 1.8 augustss 592 1.15 augustss /* ARGSUSED1 */ 593 1.15 augustss static int 594 1.15 augustss varop_report(struct hid_item *item, struct Susbvar *var, 595 1.15 augustss u_int32_t const *collist, size_t collen, u_char *buf) 596 1.1 augustss { 597 1.15 augustss switch (item->kind) { 598 1.15 augustss case hid_collection: 599 1.18 augustss printf("Collection page=%s usage=%s", 600 1.15 augustss hid_usage_page(HID_PAGE(item->usage)), 601 1.15 augustss hid_usage_in_page(item->usage)); 602 1.18 augustss if (var->mflags & MATCH_SHOWNUMERIC) 603 1.18 augustss printf(" (%u:0x%x)\n", 604 1.18 augustss HID_PAGE(item->usage), HID_USAGE(item->usage)); 605 1.18 augustss else 606 1.18 augustss printf("\n"); 607 1.15 augustss break; 608 1.15 augustss case hid_endcollection: 609 1.15 augustss printf("End collection\n"); 610 1.15 augustss break; 611 1.15 augustss case hid_input: 612 1.15 augustss reportitem("Input ", item, var->mflags); 613 1.15 augustss break; 614 1.15 augustss case hid_output: 615 1.15 augustss reportitem("Output ", item, var->mflags); 616 1.15 augustss break; 617 1.15 augustss case hid_feature: 618 1.15 augustss reportitem("Feature", item, var->mflags); 619 1.15 augustss break; 620 1.15 augustss } 621 1.15 augustss 622 1.15 augustss return 0; 623 1.15 augustss } 624 1.15 augustss 625 1.36 joerg __dead static void 626 1.15 augustss devloop(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize) 627 1.15 augustss { 628 1.18 augustss u_char *dbuf; 629 1.15 augustss struct hid_data *hdata; 630 1.18 augustss size_t collind, dlen; 631 1.15 augustss struct hid_item hitem; 632 1.28 jdolecek u_int32_t colls[256]; 633 1.15 augustss struct Sreport inreport; 634 1.15 augustss 635 1.15 augustss allocreport(&inreport, rd, REPORT_INPUT); 636 1.15 augustss 637 1.15 augustss if (inreport.size <= 0) 638 1.15 augustss errx(1, "Input report descriptor invalid length"); 639 1.15 augustss 640 1.15 augustss dlen = inreport.size; 641 1.22 christos dbuf = inreport.buffer->ucr_data; 642 1.15 augustss 643 1.15 augustss for (;;) { 644 1.15 augustss ssize_t readlen; 645 1.15 augustss 646 1.15 augustss readlen = read(hidfd, dbuf, dlen); 647 1.19 augustss if (readlen < 0) 648 1.19 augustss err(1, "Device read error"); 649 1.19 augustss if (dlen != (size_t)readlen) 650 1.19 augustss errx(1, "Unexpected response length: %lu != %lu", 651 1.19 augustss (unsigned long)readlen, (unsigned long)dlen); 652 1.15 augustss 653 1.15 augustss collind = 0; 654 1.31 dsainty resethidvars(varlist, vlsize); 655 1.31 dsainty 656 1.20 augustss hdata = hid_start_parse(rd, 1 << hid_input, reportid); 657 1.15 augustss if (hdata == NULL) 658 1.15 augustss errx(1, "Failed to start parser"); 659 1.15 augustss 660 1.15 augustss while (hid_get_item(hdata, &hitem)) { 661 1.15 augustss struct Susbvar *matchvar; 662 1.15 augustss 663 1.15 augustss switch (hitem.kind) { 664 1.15 augustss case hid_collection: 665 1.15 augustss if (collind >= (sizeof(colls) / sizeof(*colls))) 666 1.15 augustss errx(1, "Excessive nested collections"); 667 1.15 augustss colls[collind++] = hitem.usage; 668 1.15 augustss break; 669 1.15 augustss case hid_endcollection: 670 1.15 augustss if (collind == 0) 671 1.15 augustss errx(1, "Excessive collection ends"); 672 1.15 augustss collind--; 673 1.15 augustss break; 674 1.15 augustss case hid_input: 675 1.15 augustss break; 676 1.15 augustss case hid_output: 677 1.15 augustss case hid_feature: 678 1.15 augustss errx(1, "Unexpected non-input item returned"); 679 1.15 augustss } 680 1.15 augustss 681 1.20 augustss if (reportid != -1 && hitem.report_ID != reportid) 682 1.20 augustss continue; 683 1.20 augustss 684 1.15 augustss matchvar = hidmatch(colls, collind, &hitem, 685 1.15 augustss varlist, vlsize); 686 1.15 augustss 687 1.15 augustss if (matchvar != NULL) 688 1.15 augustss matchvar->opfunc(&hitem, matchvar, 689 1.15 augustss colls, collind, 690 1.22 christos inreport.buffer->ucr_data); 691 1.15 augustss } 692 1.15 augustss hid_end_parse(hdata); 693 1.15 augustss printf("\n"); 694 1.15 augustss } 695 1.15 augustss /* NOTREACHED */ 696 1.15 augustss } 697 1.15 augustss 698 1.15 augustss static void 699 1.15 augustss devshow(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize, 700 1.32 dsainty int zeromode, int kindset) 701 1.15 augustss { 702 1.15 augustss struct hid_data *hdata; 703 1.18 augustss size_t collind, repind, vlind; 704 1.15 augustss struct hid_item hitem; 705 1.28 jdolecek u_int32_t colls[256]; 706 1.15 augustss struct Sreport reports[REPORT_MAXVAL + 1]; 707 1.1 augustss 708 1.15 augustss 709 1.15 augustss for (repind = 0; repind < (sizeof(reports) / sizeof(*reports)); 710 1.15 augustss repind++) { 711 1.15 augustss reports[repind].status = srs_uninit; 712 1.15 augustss reports[repind].buffer = NULL; 713 1.32 dsainty reports[repind].use_getreport = !zeromode; 714 1.15 augustss } 715 1.15 augustss 716 1.15 augustss collind = 0; 717 1.31 dsainty resethidvars(varlist, vlsize); 718 1.31 dsainty 719 1.20 augustss hdata = hid_start_parse(rd, kindset, reportid); 720 1.15 augustss if (hdata == NULL) 721 1.15 augustss errx(1, "Failed to start parser"); 722 1.15 augustss 723 1.15 augustss while (hid_get_item(hdata, &hitem)) { 724 1.15 augustss struct Susbvar *matchvar; 725 1.15 augustss int repindex; 726 1.15 augustss 727 1.20 augustss if (verbose > 3) 728 1.20 augustss printf("item: kind=%d repid=%d usage=0x%x\n", 729 1.20 augustss hitem.kind, hitem.report_ID, hitem.usage); 730 1.15 augustss repindex = -1; 731 1.15 augustss switch (hitem.kind) { 732 1.1 augustss case hid_collection: 733 1.15 augustss if (collind >= (sizeof(colls) / sizeof(*colls))) 734 1.15 augustss errx(1, "Excessive nested collections"); 735 1.15 augustss colls[collind++] = hitem.usage; 736 1.1 augustss break; 737 1.1 augustss case hid_endcollection: 738 1.15 augustss if (collind == 0) 739 1.15 augustss errx(1, "Excessive collection ends"); 740 1.15 augustss collind--; 741 1.1 augustss break; 742 1.1 augustss case hid_input: 743 1.15 augustss repindex = REPORT_INPUT; 744 1.1 augustss break; 745 1.1 augustss case hid_output: 746 1.15 augustss repindex = REPORT_OUTPUT; 747 1.1 augustss break; 748 1.1 augustss case hid_feature: 749 1.15 augustss repindex = REPORT_FEATURE; 750 1.1 augustss break; 751 1.1 augustss } 752 1.15 augustss 753 1.20 augustss if (reportid != -1 && hitem.report_ID != reportid) 754 1.20 augustss continue; 755 1.20 augustss 756 1.15 augustss matchvar = hidmatch(colls, collind, &hitem, varlist, vlsize); 757 1.15 augustss 758 1.15 augustss if (matchvar != NULL) { 759 1.15 augustss u_char *bufdata; 760 1.15 augustss struct Sreport *repptr; 761 1.15 augustss 762 1.15 augustss matchvar->mflags |= MATCH_WASMATCHED; 763 1.15 augustss 764 1.15 augustss if (repindex >= 0) 765 1.15 augustss repptr = &reports[repindex]; 766 1.15 augustss else 767 1.15 augustss repptr = NULL; 768 1.15 augustss 769 1.15 augustss if (repptr != NULL && 770 1.15 augustss !(matchvar->mflags & MATCH_NODATA)) 771 1.15 augustss getreport(repptr, hidfd, rd, repindex); 772 1.15 augustss 773 1.15 augustss bufdata = (repptr == NULL || repptr->buffer == NULL) ? 774 1.22 christos NULL : repptr->buffer->ucr_data; 775 1.15 augustss 776 1.15 augustss if (matchvar->opfunc(&hitem, matchvar, colls, collind, 777 1.29 christos bufdata) && repptr) 778 1.15 augustss repptr->status = srs_dirty; 779 1.15 augustss } 780 1.1 augustss } 781 1.15 augustss hid_end_parse(hdata); 782 1.15 augustss 783 1.15 augustss for (repind = 0; repind < (sizeof(reports) / sizeof(*reports)); 784 1.15 augustss repind++) { 785 1.15 augustss setreport(&reports[repind], hidfd, repind); 786 1.15 augustss freereport(&reports[repind]); 787 1.15 augustss } 788 1.15 augustss 789 1.15 augustss /* Warn about any items that we couldn't find a match for */ 790 1.15 augustss for (vlind = 0; vlind < vlsize; vlind++) { 791 1.15 augustss struct Susbvar *var; 792 1.15 augustss 793 1.15 augustss var = &varlist[vlind]; 794 1.15 augustss 795 1.15 augustss if (var->variable != NULL && 796 1.15 augustss !(var->mflags & MATCH_WASMATCHED)) 797 1.15 augustss warnx("Failed to match: %.*s", (int)var->varlen, 798 1.15 augustss var->variable); 799 1.1 augustss } 800 1.1 augustss } 801 1.1 augustss 802 1.36 joerg __dead static void 803 1.15 augustss usage(void) 804 1.1 augustss { 805 1.16 cgd const char *progname = getprogname(); 806 1.1 augustss 807 1.33 wiz fprintf(stderr, "usage: %s -f device [-t tablefile] [-lv] -a\n", 808 1.17 simonb progname); 809 1.17 simonb fprintf(stderr, " %s -f device [-t tablefile] [-v] -r\n", 810 1.17 simonb progname); 811 1.17 simonb fprintf(stderr, 812 1.33 wiz " %s -f device [-t tablefile] [-lnv] item [...]\n", 813 1.17 simonb progname); 814 1.17 simonb fprintf(stderr, 815 1.33 wiz " %s -f device [-t tablefile] [-z] -w item=value [...]\n", 816 1.17 simonb progname); 817 1.15 augustss exit(1); 818 1.1 augustss } 819 1.1 augustss 820 1.1 augustss int 821 1.1 augustss main(int argc, char **argv) 822 1.1 augustss { 823 1.18 augustss char const *dev; 824 1.18 augustss char const *table; 825 1.18 augustss size_t varnum; 826 1.32 dsainty int aflag, lflag, nflag, rflag, wflag, zflag; 827 1.18 augustss int ch, hidfd; 828 1.15 augustss report_desc_t repdesc; 829 1.15 augustss char devnamebuf[PATH_MAX]; 830 1.15 augustss struct Susbvar variables[128]; 831 1.15 augustss 832 1.32 dsainty aflag = lflag = nflag = rflag = verbose = wflag = zflag = 0; 833 1.15 augustss dev = NULL; 834 1.15 augustss table = NULL; 835 1.32 dsainty while ((ch = getopt(argc, argv, "?af:lnrt:vwz")) != -1) { 836 1.15 augustss switch (ch) { 837 1.3 augustss case 'a': 838 1.15 augustss aflag = 1; 839 1.3 augustss break; 840 1.1 augustss case 'f': 841 1.1 augustss dev = optarg; 842 1.1 augustss break; 843 1.1 augustss case 'l': 844 1.15 augustss lflag = 1; 845 1.1 augustss break; 846 1.1 augustss case 'n': 847 1.15 augustss nflag = 1; 848 1.1 augustss break; 849 1.1 augustss case 'r': 850 1.15 augustss rflag = 1; 851 1.1 augustss break; 852 1.1 augustss case 't': 853 1.1 augustss table = optarg; 854 1.1 augustss break; 855 1.1 augustss case 'v': 856 1.1 augustss verbose++; 857 1.1 augustss break; 858 1.15 augustss case 'w': 859 1.15 augustss wflag = 1; 860 1.15 augustss break; 861 1.32 dsainty case 'z': 862 1.32 dsainty zflag = 1; 863 1.32 dsainty break; 864 1.1 augustss case '?': 865 1.1 augustss default: 866 1.1 augustss usage(); 867 1.15 augustss /* NOTREACHED */ 868 1.1 augustss } 869 1.1 augustss } 870 1.1 augustss argc -= optind; 871 1.1 augustss argv += optind; 872 1.15 augustss if (dev == NULL || (lflag && (wflag || rflag))) { 873 1.15 augustss /* 874 1.15 augustss * No device specified, or attempting to loop and set 875 1.15 augustss * or dump report at the same time 876 1.15 augustss */ 877 1.1 augustss usage(); 878 1.15 augustss /* NOTREACHED */ 879 1.15 augustss } 880 1.15 augustss 881 1.15 augustss for (varnum = 0; varnum < (size_t)argc; varnum++) { 882 1.31 dsainty char const *name, *valuesep, *varinst; 883 1.15 augustss struct Susbvar *svar; 884 1.31 dsainty size_t namelen; 885 1.15 augustss 886 1.15 augustss svar = &variables[varnum]; 887 1.15 augustss name = argv[varnum]; 888 1.15 augustss valuesep = strchr(name, DELIM_SET); 889 1.15 augustss 890 1.15 augustss svar->variable = name; 891 1.15 augustss svar->mflags = 0; 892 1.31 dsainty svar->usageinstance = 0; 893 1.15 augustss 894 1.15 augustss if (valuesep == NULL) { 895 1.15 augustss /* Read variable */ 896 1.15 augustss if (wflag) 897 1.15 augustss errx(1, "Must not specify -w to read variables"); 898 1.15 augustss svar->value = NULL; 899 1.31 dsainty namelen = strlen(name); 900 1.15 augustss 901 1.15 augustss if (nflag) { 902 1.15 augustss /* Display value of variable only */ 903 1.15 augustss svar->opfunc = varop_value; 904 1.15 augustss } else { 905 1.15 augustss /* Display name and value of variable */ 906 1.15 augustss svar->opfunc = varop_display; 907 1.15 augustss 908 1.15 augustss if (verbose >= 1) 909 1.15 augustss /* Show page names in verbose modes */ 910 1.15 augustss svar->mflags |= MATCH_SHOWPAGENAME; 911 1.15 augustss } 912 1.15 augustss } else { 913 1.15 augustss /* Write variable */ 914 1.15 augustss if (!wflag) 915 1.15 augustss errx(2, "Must specify -w to set variables"); 916 1.15 augustss svar->mflags |= MATCH_WRITABLE; 917 1.18 augustss if (verbose >= 1) 918 1.18 augustss /* 919 1.18 augustss * Allow displaying of set value in 920 1.18 augustss * verbose mode. This isn't 921 1.18 augustss * particularly useful though, so 922 1.18 augustss * don't bother documenting it. 923 1.18 augustss */ 924 1.18 augustss svar->mflags |= MATCH_SHOWVALUES; 925 1.31 dsainty namelen = valuesep - name; 926 1.15 augustss svar->value = valuesep + 1; 927 1.15 augustss svar->opfunc = varop_modify; 928 1.15 augustss } 929 1.31 dsainty 930 1.31 dsainty varinst = memchr(name, DELIM_INSTANCE, namelen); 931 1.31 dsainty 932 1.31 dsainty if (varinst != NULL && ++varinst != &name[namelen]) { 933 1.31 dsainty char *endptr; 934 1.31 dsainty 935 1.31 dsainty svar->usageinstance = strtol(varinst, &endptr, 0); 936 1.31 dsainty 937 1.31 dsainty if (&name[namelen] != (char const*)endptr) 938 1.31 dsainty errx(1, "%s%c%s", "Error parsing item " 939 1.31 dsainty "instance number after '", 940 1.31 dsainty DELIM_INSTANCE, "'"); 941 1.31 dsainty 942 1.31 dsainty namelen = varinst - 1 - name; 943 1.31 dsainty } 944 1.31 dsainty 945 1.31 dsainty svar->varlen = namelen; 946 1.15 augustss } 947 1.6 augustss 948 1.15 augustss if (aflag || rflag) { 949 1.15 augustss struct Susbvar *svar; 950 1.15 augustss 951 1.15 augustss svar = &variables[varnum++]; 952 1.15 augustss 953 1.15 augustss svar->variable = NULL; 954 1.15 augustss svar->mflags = MATCH_ALL; 955 1.15 augustss 956 1.15 augustss if (rflag) { 957 1.15 augustss /* 958 1.15 augustss * Dump report descriptor. Do dump collection 959 1.15 augustss * items also, and hint that it won't be 960 1.15 augustss * necessary to get the item status. 961 1.15 augustss */ 962 1.15 augustss svar->opfunc = varop_report; 963 1.15 augustss svar->mflags |= MATCH_COLLECTIONS | MATCH_NODATA; 964 1.15 augustss 965 1.15 augustss switch (verbose) { 966 1.15 augustss default: 967 1.15 augustss /* Level 2: Show item numerics and constants */ 968 1.15 augustss svar->mflags |= MATCH_SHOWNUMERIC; 969 1.15 augustss /* FALLTHROUGH */ 970 1.15 augustss case 1: 971 1.15 augustss /* Level 1: Just show constants */ 972 1.15 augustss svar->mflags |= MATCH_CONSTANTS; 973 1.15 augustss /* FALLTHROUGH */ 974 1.15 augustss case 0: 975 1.15 augustss break; 976 1.15 augustss } 977 1.15 augustss } else { 978 1.15 augustss /* Display name and value of variable */ 979 1.15 augustss svar->opfunc = varop_display; 980 1.15 augustss 981 1.15 augustss switch (verbose) { 982 1.15 augustss default: 983 1.15 augustss /* Level 2: Show constants and page names */ 984 1.15 augustss svar->mflags |= MATCH_CONSTANTS; 985 1.15 augustss /* FALLTHROUGH */ 986 1.15 augustss case 1: 987 1.15 augustss /* Level 1: Just show page names */ 988 1.15 augustss svar->mflags |= MATCH_SHOWPAGENAME; 989 1.15 augustss /* FALLTHROUGH */ 990 1.15 augustss case 0: 991 1.15 augustss break; 992 1.15 augustss } 993 1.15 augustss } 994 1.15 augustss } 995 1.15 augustss 996 1.15 augustss if (varnum == 0) { 997 1.15 augustss /* Nothing to do... Display usage information. */ 998 1.6 augustss usage(); 999 1.15 augustss /* NOTREACHED */ 1000 1.15 augustss } 1001 1.15 augustss 1002 1.15 augustss hid_init(table); 1003 1.4 augustss 1004 1.4 augustss if (dev[0] != '/') { 1005 1.15 augustss snprintf(devnamebuf, sizeof(devnamebuf), "/dev/%s%s", 1006 1.27 dsl isdigit((unsigned char)dev[0]) ? "uhid" : "", dev); 1007 1.15 augustss dev = devnamebuf; 1008 1.4 augustss } 1009 1.1 augustss 1010 1.15 augustss hidfd = open(dev, O_RDWR); 1011 1.15 augustss if (hidfd < 0) 1012 1.1 augustss err(1, "%s", dev); 1013 1.1 augustss 1014 1.20 augustss if (ioctl(hidfd, USB_GET_REPORT_ID, &reportid) < 0) 1015 1.20 augustss reportid = -1; 1016 1.20 augustss if (verbose > 1) 1017 1.20 augustss printf("report ID=%d\n", reportid); 1018 1.15 augustss repdesc = hid_get_report_desc(hidfd); 1019 1.15 augustss if (repdesc == 0) 1020 1.1 augustss errx(1, "USB_GET_REPORT_DESC"); 1021 1.15 augustss 1022 1.15 augustss if (lflag) { 1023 1.15 augustss devloop(hidfd, repdesc, variables, varnum); 1024 1.15 augustss /* NOTREACHED */ 1025 1.15 augustss } 1026 1.15 augustss 1027 1.15 augustss if (rflag) 1028 1.15 augustss /* Report mode header */ 1029 1.9 augustss printf("Report descriptor:\n"); 1030 1.15 augustss 1031 1.32 dsainty devshow(hidfd, repdesc, variables, varnum, zflag, 1032 1.15 augustss 1 << hid_input | 1033 1.15 augustss 1 << hid_output | 1034 1.15 augustss 1 << hid_feature); 1035 1.15 augustss 1036 1.15 augustss if (rflag) { 1037 1.15 augustss /* Report mode trailer */ 1038 1.15 augustss size_t repindex; 1039 1.15 augustss for (repindex = 0; 1040 1.15 augustss repindex < (sizeof(reptoparam) / sizeof(*reptoparam)); 1041 1.15 augustss repindex++) { 1042 1.20 augustss int size; 1043 1.15 augustss size = hid_report_size(repdesc, 1044 1.15 augustss reptoparam[repindex].hid_kind, 1045 1.20 augustss reportid); 1046 1.20 augustss printf("Total %7s size %d bytes\n", 1047 1.20 augustss reptoparam[repindex].name, size); 1048 1.15 augustss } 1049 1.1 augustss } 1050 1.1 augustss 1051 1.15 augustss hid_dispose_report_desc(repdesc); 1052 1.1 augustss exit(0); 1053 1.15 augustss /* NOTREACHED */ 1054 1.1 augustss } 1055