162642Sn_hibma/* $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */ 262642Sn_hibma/* $FreeBSD: stable/11/usr.bin/usbhidctl/usbhid.c 351845 2019-09-05 09:35:41Z hselasky $ */ 362642Sn_hibma 4330449Seadler/*- 5330449Seadler * SPDX-License-Identifier: BSD-2-Clause-NetBSD 6330449Seadler * 762642Sn_hibma * Copyright (c) 1998 The NetBSD Foundation, Inc. 862642Sn_hibma * All rights reserved. 962642Sn_hibma * 1062642Sn_hibma * This code is derived from software contributed to The NetBSD Foundation 1162642Sn_hibma * by Lennart Augustsson (augustss@netbsd.org). 1262642Sn_hibma * 1362642Sn_hibma * Redistribution and use in source and binary forms, with or without 1462642Sn_hibma * modification, are permitted provided that the following conditions 1562642Sn_hibma * are met: 1662642Sn_hibma * 1. Redistributions of source code must retain the above copyright 1762642Sn_hibma * notice, this list of conditions and the following disclaimer. 1862642Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright 1962642Sn_hibma * notice, this list of conditions and the following disclaimer in the 2062642Sn_hibma * documentation and/or other materials provided with the distribution. 2162642Sn_hibma * 2262642Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2362642Sn_hibma * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2462642Sn_hibma * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2562642Sn_hibma * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2662642Sn_hibma * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2762642Sn_hibma * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2862642Sn_hibma * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2962642Sn_hibma * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3062642Sn_hibma * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3162642Sn_hibma * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3262642Sn_hibma * POSSIBILITY OF SUCH DAMAGE. 3362642Sn_hibma */ 3462642Sn_hibma 3562642Sn_hibma#include <stdio.h> 3662642Sn_hibma#include <stdlib.h> 3762642Sn_hibma#include <string.h> 3862642Sn_hibma#include <sys/types.h> 3962642Sn_hibma#include <fcntl.h> 4062642Sn_hibma#include <unistd.h> 4162642Sn_hibma#include <err.h> 4262642Sn_hibma#include <ctype.h> 4362642Sn_hibma#include <errno.h> 44113273Smdodd#include <usbhid.h> 45188945Sthompsa#include <dev/usb/usbhid.h> 4662642Sn_hibma 47227196Sedstatic struct variable { 48225839Smav char *name; 49225839Smav int instance; 50225839Smav int val; 51225839Smav struct hid_item h; 52225839Smav struct variable *next; 53225839Smav} *vars; 54225839Smav 55227196Sedstatic int verbose = 0; 56227196Sedstatic int noname = 0; 57227196Sedstatic int hexdump = 0; 58227196Sedstatic int wflag = 0; 59227196Sedstatic int zflag = 0; 6062642Sn_hibma 61225839Smavstatic void usage(void); 62225839Smavstatic void dumpitem(const char *label, struct hid_item *h); 63225839Smavstatic void dumpitems(report_desc_t r); 64225839Smavstatic void prdata(u_char *buf, struct hid_item *h); 65225839Smavstatic void dumpdata(int f, report_desc_t r, int loop); 66225839Smavstatic void writedata(int f, report_desc_t r); 6762642Sn_hibma 68225839Smavstatic void 69225839Smavparceargs(report_desc_t r, int all, int nnames, char **names) 7062642Sn_hibma{ 71225839Smav struct hid_data *d; 72225839Smav struct hid_item h; 73225839Smav char colls[1000]; 74225839Smav char hname[1000], *tmp1, *tmp2; 75225839Smav struct variable *var, **pnext; 76225839Smav int i, instance, cp, t; 7762642Sn_hibma 78225839Smav pnext = &vars; 79225839Smav if (all) { 80225839Smav if (wflag) 81225839Smav errx(1, "Must not specify -w to read variables"); 82225839Smav cp = 0; 83225839Smav for (d = hid_start_parse(r, 84225839Smav 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 85225839Smav hid_get_item(d, &h); ) { 86225839Smav if (h.kind == hid_collection) { 87225839Smav cp += sprintf(&colls[cp], "%s%s:%s", 88225839Smav cp != 0 ? "." : "", 89225839Smav hid_usage_page(HID_PAGE(h.usage)), 90225839Smav hid_usage_in_page(h.usage)); 91225839Smav } else if (h.kind == hid_endcollection) { 92225839Smav tmp1 = strrchr(colls, '.'); 93225839Smav if (tmp1 != NULL) { 94225839Smav cp -= strlen(tmp1); 95225839Smav tmp1[0] = 0; 96225839Smav } else { 97225839Smav cp = 0; 98225839Smav colls[0] = 0; 99225839Smav } 100225839Smav } 101225839Smav if ((h.kind != hid_input && h.kind != hid_output && 102225839Smav h.kind != hid_feature) || (h.flags & HIO_CONST)) 103225839Smav continue; 104225839Smav var = malloc(sizeof(*var)); 105225839Smav memset(var, 0, sizeof(*var)); 106225839Smav asprintf(&var->name, "%s%s%s:%s", 107225839Smav colls, colls[0] != 0 ? "." : "", 108225839Smav hid_usage_page(HID_PAGE(h.usage)), 109225839Smav hid_usage_in_page(h.usage)); 110225839Smav var->h = h; 111225839Smav *pnext = var; 112225839Smav pnext = &var->next; 113225839Smav } 114225839Smav hid_end_parse(d); 115225839Smav return; 116225839Smav } 117225839Smav for (i = 0; i < nnames; i++) { 118225839Smav var = malloc(sizeof(*var)); 119225839Smav memset(var, 0, sizeof(*var)); 120225839Smav tmp1 = tmp2 = strdup(names[i]); 121225839Smav strsep(&tmp2, "="); 122225839Smav var->name = strsep(&tmp1, "#"); 123225839Smav if (tmp1 != NULL) 124225839Smav var->instance = atoi(tmp1); 125225839Smav if (tmp2 != NULL) { 126225839Smav if (!wflag) 127225839Smav errx(1, "Must specify -w to write variables"); 128225839Smav var->val = atoi(tmp2); 129225839Smav } else 130225839Smav if (wflag) 131225839Smav errx(1, "Must not specify -w to read variables"); 132225839Smav *pnext = var; 133225839Smav pnext = &var->next; 13462642Sn_hibma 135225839Smav instance = 0; 136225839Smav cp = 0; 137225839Smav for (d = hid_start_parse(r, 138225839Smav 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 139225839Smav hid_get_item(d, &h); ) { 140225839Smav if (h.kind == hid_collection) { 141225839Smav cp += sprintf(&colls[cp], "%s%s:%s", 142225839Smav cp != 0 ? "." : "", 143225839Smav hid_usage_page(HID_PAGE(h.usage)), 144225839Smav hid_usage_in_page(h.usage)); 145225839Smav } else if (h.kind == hid_endcollection) { 146225839Smav tmp1 = strrchr(colls, '.'); 147225839Smav if (tmp1 != NULL) { 148225839Smav cp -= strlen(tmp1); 149225839Smav tmp1[0] = 0; 150225839Smav } else { 151225839Smav cp = 0; 152225839Smav colls[0] = 0; 153225839Smav } 154225839Smav } 155225839Smav if ((h.kind != hid_input && h.kind != hid_output && 156225839Smav h.kind != hid_feature) || (h.flags & HIO_CONST)) 157225839Smav continue; 158225839Smav snprintf(hname, sizeof(hname), "%s%s%s:%s", 159225839Smav colls, colls[0] != 0 ? "." : "", 160225839Smav hid_usage_page(HID_PAGE(h.usage)), 161225839Smav hid_usage_in_page(h.usage)); 162225839Smav t = strlen(hname) - strlen(var->name); 163225839Smav if (t > 0) { 164225839Smav if (strcmp(hname + t, var->name) != 0) 165225839Smav continue; 166225839Smav if (hname[t - 1] != '.') 167225839Smav continue; 168225839Smav } else if (strcmp(hname, var->name) != 0) 169225839Smav continue; 170225839Smav if (var->instance != instance++) 171225839Smav continue; 172225839Smav var->h = h; 173225839Smav break; 174225839Smav } 175225839Smav hid_end_parse(d); 176225839Smav if (var->h.usage == 0) 177225839Smav errx(1, "Unknown item '%s'", var->name); 178225839Smav } 17962642Sn_hibma} 18062642Sn_hibma 181225839Smavstatic void 18262642Sn_hibmausage(void) 18362642Sn_hibma{ 18462642Sn_hibma 185164531Sgrog fprintf(stderr, 186164531Sgrog "usage: %s -f device " 187235519Smav "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] name ...\n", 188194789Sdelphij getprogname()); 189164531Sgrog fprintf(stderr, 190164531Sgrog " %s -f device " 191235519Smav "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] -a\n", 192194789Sdelphij getprogname()); 193225839Smav fprintf(stderr, 194225839Smav " %s -f device " 195225839Smav "[-t tablefile] [-v] [-z] -w name=value\n", 196225839Smav getprogname()); 19762642Sn_hibma exit(1); 19862642Sn_hibma} 19962642Sn_hibma 200225839Smavstatic void 20187699Smarkmdumpitem(const char *label, struct hid_item *h) 20262642Sn_hibma{ 20362642Sn_hibma if ((h->flags & HIO_CONST) && !verbose) 20462642Sn_hibma return; 205351845Shselasky printf("%s rid=%d pos=%d size=%d count=%d page=%s usage=%s%s%s", label, 206351845Shselasky h->report_ID, h->pos, h->report_size, h->report_count, 207164531Sgrog hid_usage_page(HID_PAGE(h->usage)), 20862642Sn_hibma hid_usage_in_page(h->usage), 209224511Smav h->flags & HIO_CONST ? " Const" : "", 210224511Smav h->flags & HIO_VARIABLE ? "" : " Array"); 21162642Sn_hibma printf(", logical range %d..%d", 21262642Sn_hibma h->logical_minimum, h->logical_maximum); 21362642Sn_hibma if (h->physical_minimum != h->physical_maximum) 21462642Sn_hibma printf(", physical range %d..%d", 21562642Sn_hibma h->physical_minimum, h->physical_maximum); 21662642Sn_hibma if (h->unit) 21762642Sn_hibma printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 21862642Sn_hibma printf("\n"); 21962642Sn_hibma} 22062642Sn_hibma 221224511Smavstatic const char * 222224511Smavhid_collection_type(int32_t type) 223224511Smav{ 224224511Smav static char num[8]; 225224511Smav 226224511Smav switch (type) { 227224511Smav case 0: return ("Physical"); 228224511Smav case 1: return ("Application"); 229224511Smav case 2: return ("Logical"); 230224511Smav case 3: return ("Report"); 231224511Smav case 4: return ("Named_Array"); 232224511Smav case 5: return ("Usage_Switch"); 233224511Smav case 6: return ("Usage_Modifier"); 234224511Smav } 235224511Smav snprintf(num, sizeof(num), "0x%02x", type); 236224511Smav return (num); 237224511Smav} 238224511Smav 239225839Smavstatic void 24062642Sn_hibmadumpitems(report_desc_t r) 24162642Sn_hibma{ 24262642Sn_hibma struct hid_data *d; 24362642Sn_hibma struct hid_item h; 24467256Sn_hibma int size; 24562642Sn_hibma 246224511Smav for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { 24762642Sn_hibma switch (h.kind) { 24862642Sn_hibma case hid_collection: 249224511Smav printf("Collection type=%s page=%s usage=%s\n", 250224511Smav hid_collection_type(h.collection), 251164531Sgrog hid_usage_page(HID_PAGE(h.usage)), 25262642Sn_hibma hid_usage_in_page(h.usage)); 25362642Sn_hibma break; 25462642Sn_hibma case hid_endcollection: 25562642Sn_hibma printf("End collection\n"); 25662642Sn_hibma break; 25762642Sn_hibma case hid_input: 25862642Sn_hibma dumpitem("Input ", &h); 25962642Sn_hibma break; 26062642Sn_hibma case hid_output: 26162642Sn_hibma dumpitem("Output ", &h); 26262642Sn_hibma break; 26362642Sn_hibma case hid_feature: 26462642Sn_hibma dumpitem("Feature", &h); 26562642Sn_hibma break; 26662642Sn_hibma } 26762642Sn_hibma } 26862642Sn_hibma hid_end_parse(d); 269224511Smav size = hid_report_size(r, hid_input, -1); 27075606Sn_hibma printf("Total input size %d bytes\n", size); 27162642Sn_hibma 272224511Smav size = hid_report_size(r, hid_output, -1); 27367256Sn_hibma printf("Total output size %d bytes\n", size); 27467256Sn_hibma 275224511Smav size = hid_report_size(r, hid_feature, -1); 27667256Sn_hibma printf("Total feature size %d bytes\n", size); 27762642Sn_hibma} 27862642Sn_hibma 279225839Smavstatic void 28062642Sn_hibmaprdata(u_char *buf, struct hid_item *h) 28162642Sn_hibma{ 28262642Sn_hibma u_int data; 28362642Sn_hibma int i, pos; 28462642Sn_hibma 28562642Sn_hibma pos = h->pos; 28662642Sn_hibma for (i = 0; i < h->report_count; i++) { 28762642Sn_hibma data = hid_get_data(buf, h); 288224511Smav if (i > 0) 289224511Smav printf(" "); 29062642Sn_hibma if (h->logical_minimum < 0) 29162642Sn_hibma printf("%d", (int)data); 29262642Sn_hibma else 29362642Sn_hibma printf("%u", data); 294164531Sgrog if (hexdump) 295164531Sgrog printf(" [0x%x]", data); 296224511Smav h->pos += h->report_size; 29762642Sn_hibma } 298224511Smav h->pos = pos; 29962642Sn_hibma} 30062642Sn_hibma 301225839Smavstatic void 30262642Sn_hibmadumpdata(int f, report_desc_t rd, int loop) 30362642Sn_hibma{ 304225839Smav struct variable *var; 305225839Smav int dlen, havedata, i, match, r, rid, use_rid; 30662642Sn_hibma u_char *dbuf; 307225839Smav enum hid_kind kind; 30862642Sn_hibma 309235519Smav kind = zflag ? 3 : 0; 310225839Smav rid = -1; 311225839Smav use_rid = !!hid_get_report_id(f); 312225839Smav do { 313225839Smav if (kind < 3) { 314225839Smav if (++rid >= 256) { 315225839Smav rid = 0; 316225839Smav kind++; 317225839Smav } 318225839Smav if (kind >= 3) 319225839Smav rid = -1; 320225839Smav for (var = vars; var; var = var->next) { 321225839Smav if (rid == var->h.report_ID && 322225839Smav kind == var->h.kind) 323225839Smav break; 324225839Smav } 325225839Smav if (var == NULL) 326225839Smav continue; 327225839Smav } 328225839Smav dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid); 329225839Smav if (dlen <= 0) 33062642Sn_hibma continue; 331225839Smav dbuf = malloc(dlen); 332225839Smav memset(dbuf, 0, dlen); 333225839Smav if (kind < 3) { 334225839Smav dbuf[0] = rid; 335225839Smav r = hid_get_report(f, kind, dbuf, dlen); 336225839Smav if (r < 0) 337225839Smav warn("hid_get_report(rid %d)", rid); 338225839Smav havedata = !r && (rid == 0 || dbuf[0] == rid); 339225839Smav if (rid != 0) 340225839Smav dbuf[0] = rid; 341225839Smav } else { 342225839Smav r = read(f, dbuf, dlen); 343225839Smav if (r < 1) 344225839Smav err(1, "read error"); 345225839Smav havedata = 1; 34662642Sn_hibma } 347225839Smav if (verbose) { 348225839Smav printf("Got %s report %d (%d bytes):", 349225839Smav kind == hid_output ? "output" : 350225839Smav kind == hid_feature ? "feature" : "input", 351225839Smav use_rid ? dbuf[0] : 0, dlen); 352225839Smav if (havedata) { 353225839Smav for (i = 0; i < dlen; i++) 354225839Smav printf(" %02x", dbuf[i]); 355225839Smav } 356225839Smav printf("\n"); 35762642Sn_hibma } 358225839Smav match = 0; 359225839Smav for (var = vars; var; var = var->next) { 360225839Smav if ((kind < 3 ? kind : hid_input) != var->h.kind) 361224511Smav continue; 362225839Smav if (var->h.report_ID != 0 && 363225839Smav dbuf[0] != var->h.report_ID) 364225839Smav continue; 365225839Smav match = 1; 366225839Smav if (!noname) 367225839Smav printf("%s=", var->name); 368225839Smav if (havedata) 369225839Smav prdata(dbuf, &var->h); 370225839Smav printf("\n"); 371225839Smav } 372225839Smav if (match) 373225839Smav printf("\n"); 374225839Smav free(dbuf); 375225839Smav } while (loop || kind < 3); 376225839Smav} 377225839Smav 378225839Smavstatic void 379225839Smavwritedata(int f, report_desc_t rd) 380225839Smav{ 381225839Smav struct variable *var; 382225839Smav int dlen, i, r, rid; 383225839Smav u_char *dbuf; 384225839Smav enum hid_kind kind; 385225839Smav 386225839Smav kind = 0; 387225839Smav rid = 0; 388225839Smav for (kind = 0; kind < 3; kind ++) { 389225839Smav for (rid = 0; rid < 256; rid ++) { 390225839Smav for (var = vars; var; var = var->next) { 391225839Smav if (rid == var->h.report_ID && kind == var->h.kind) 392225839Smav break; 393225839Smav } 394225839Smav if (var == NULL) 395225839Smav continue; 396225839Smav dlen = hid_report_size(rd, kind, rid); 397225839Smav if (dlen <= 0) 398225839Smav continue; 399225839Smav dbuf = malloc(dlen); 400225839Smav memset(dbuf, 0, dlen); 401225839Smav dbuf[0] = rid; 402225839Smav if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) { 403225839Smav if (verbose) { 404225839Smav printf("Got %s report %d (%d bytes):", 405225839Smav kind == hid_input ? "input" : 406225839Smav kind == hid_output ? "output" : "feature", 407225839Smav rid, dlen); 408225839Smav for (i = 0; i < dlen; i++) 409225839Smav printf(" %02x", dbuf[i]); 41062642Sn_hibma printf("\n"); 41162642Sn_hibma } 412225839Smav } else if (!zflag) { 413225839Smav warn("hid_get_report(rid %d)", rid); 414225839Smav if (verbose) { 415225839Smav printf("Can't get %s report %d (%d bytes). " 416225839Smav "Will be initialized with zeros.\n", 417225839Smav kind == hid_input ? "input" : 418225839Smav kind == hid_output ? "output" : "feature", 419225839Smav rid, dlen); 420225839Smav } 42162642Sn_hibma } 422225839Smav for (var = vars; var; var = var->next) { 423225839Smav if (rid != var->h.report_ID || kind != var->h.kind) 424225839Smav continue; 425225839Smav hid_set_data(dbuf, &var->h, var->val); 426225839Smav } 427225839Smav if (verbose) { 428225839Smav printf("Setting %s report %d (%d bytes):", 429225839Smav kind == hid_output ? "output" : 430225839Smav kind == hid_feature ? "feature" : "input", 431225839Smav rid, dlen); 432225839Smav for (i = 0; i < dlen; i++) 433225839Smav printf(" %02x", dbuf[i]); 43462642Sn_hibma printf("\n"); 435225839Smav } 436225839Smav r = hid_set_report(f, kind, dbuf, dlen); 437225839Smav if (r != 0) 438225839Smav warn("hid_set_report(rid %d)", rid); 439225839Smav free(dbuf); 440225839Smav } 441225839Smav } 44262642Sn_hibma} 44362642Sn_hibma 44462642Sn_hibmaint 44562642Sn_hibmamain(int argc, char **argv) 44662642Sn_hibma{ 447225839Smav report_desc_t r; 448225839Smav char *table = 0; 449225839Smav char devnam[100], *dev = NULL; 45062642Sn_hibma int f; 451225839Smav int all = 0; 45262642Sn_hibma int ch; 45362642Sn_hibma int repdump = 0; 45462642Sn_hibma int loop = 0; 45562642Sn_hibma 456225839Smav while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) { 45762642Sn_hibma switch(ch) { 45862642Sn_hibma case 'a': 45962642Sn_hibma all++; 46062642Sn_hibma break; 46162642Sn_hibma case 'f': 46262642Sn_hibma dev = optarg; 46362642Sn_hibma break; 46462642Sn_hibma case 'l': 46562642Sn_hibma loop ^= 1; 46662642Sn_hibma break; 46762642Sn_hibma case 'n': 46862642Sn_hibma noname++; 46962642Sn_hibma break; 47062642Sn_hibma case 'r': 47162642Sn_hibma repdump++; 47262642Sn_hibma break; 47362642Sn_hibma case 't': 47462642Sn_hibma table = optarg; 47562642Sn_hibma break; 47662642Sn_hibma case 'v': 47762642Sn_hibma verbose++; 47862642Sn_hibma break; 479225839Smav case 'w': 480225839Smav wflag = 1; 481225839Smav break; 482164531Sgrog case 'x': 483164544Sgrog hexdump = 1; 484164531Sgrog break; 485225839Smav case 'z': 486225839Smav zflag = 1; 487225839Smav break; 48862642Sn_hibma case '?': 48962642Sn_hibma default: 49062642Sn_hibma usage(); 49162642Sn_hibma } 49262642Sn_hibma } 49362642Sn_hibma argc -= optind; 49462642Sn_hibma argv += optind; 495225839Smav if (dev == NULL) 49662642Sn_hibma usage(); 49762642Sn_hibma 498225839Smav if (argc == 0 && !all && !repdump) 49962642Sn_hibma usage(); 50062642Sn_hibma 50162642Sn_hibma if (dev[0] != '/') { 50262642Sn_hibma if (isdigit(dev[0])) 50387699Smarkm snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); 50462642Sn_hibma else 50587699Smarkm snprintf(devnam, sizeof(devnam), "/dev/%s", dev); 50687699Smarkm dev = devnam; 50762642Sn_hibma } 50862642Sn_hibma 50962642Sn_hibma hid_init(table); 51062642Sn_hibma 51162642Sn_hibma f = open(dev, O_RDWR); 51262642Sn_hibma if (f < 0) 51362642Sn_hibma err(1, "%s", dev); 51462642Sn_hibma 51562642Sn_hibma r = hid_get_report_desc(f); 516164531Sgrog if (r == 0) 51762642Sn_hibma errx(1, "USB_GET_REPORT_DESC"); 518164531Sgrog 51962642Sn_hibma if (repdump) { 52062642Sn_hibma printf("Report descriptor:\n"); 52162642Sn_hibma dumpitems(r); 52262642Sn_hibma } 523225839Smav if (argc != 0 || all) { 524225839Smav parceargs(r, all, argc, argv); 525225839Smav if (wflag) 526225839Smav writedata(f, r); 527225839Smav else 528225839Smav dumpdata(f, r, loop); 529225839Smav } 53062642Sn_hibma 53162642Sn_hibma hid_dispose_report_desc(r); 53262642Sn_hibma exit(0); 53362642Sn_hibma} 534