diff --git a/usr.sbin/usbconfig/dump.c b/usr.sbin/usbconfig/dump.c index 6dfc6ec4dfb6..4e527eaacbf5 100644 --- a/usr.sbin/usbconfig/dump.c +++ b/usr.sbin/usbconfig/dump.c @@ -365,3 +365,40 @@ dump_config(struct libusb20_device *pdev, uint8_t all_cfg) } return; } + +void +dump_string_by_index(struct libusb20_device *pdev, uint8_t str_index) +{ + char *pbuf; + uint8_t n; + uint8_t len; + + pbuf = malloc(256); + if (pbuf == NULL) + err(1, "out of memory"); + + if (str_index == 0) { + /* language table */ + if (libusb20_dev_req_string_sync(pdev, + str_index, 0, pbuf, 256)) { + printf("STRING_0x%02x = \n", str_index); + } else { + printf("STRING_0x%02x = ", str_index); + len = (uint8_t)pbuf[0]; + for (n = 0; n != len; n++) { + printf("0x%02x%s", (uint8_t)pbuf[n], + (n != (len-1)) ? ", " : ""); + } + printf("\n"); + } + } else { + /* ordinary string */ + if (libusb20_dev_req_string_simple_sync(pdev, + str_index, pbuf, 256)) { + printf("STRING_0x%02x = \n", str_index); + } else { + printf("STRING_0x%02x = <%s>\n", str_index, pbuf); + } + } + free(pbuf); +} diff --git a/usr.sbin/usbconfig/dump.h b/usr.sbin/usbconfig/dump.h index 7fafdfd34dbf..581684a4cf28 100644 --- a/usr.sbin/usbconfig/dump.h +++ b/usr.sbin/usbconfig/dump.h @@ -24,11 +24,17 @@ * SUCH DAMAGE. */ +#ifndef _DUMP_H_ +#define _DUMP_H_ + const char *dump_mode(uint8_t value); const char *dump_speed(uint8_t value); const char *dump_power_mode(uint8_t value); +void dump_string_by_index(struct libusb20_device *pdev, uint8_t index); void dump_device_info(struct libusb20_device *pdev, uint8_t show_drv); void dump_be_quirk_names(struct libusb20_backend *pbe); void dump_be_dev_quirks(struct libusb20_backend *pbe); void dump_device_desc(struct libusb20_device *pdev); void dump_config(struct libusb20_device *pdev, uint8_t all_cfg); + +#endif /* _DUMP_H_ */ diff --git a/usr.sbin/usbconfig/usbconfig.8 b/usr.sbin/usbconfig/usbconfig.8 index 0914d9ebb177..971367d2650a 100644 --- a/usr.sbin/usbconfig/usbconfig.8 +++ b/usr.sbin/usbconfig/usbconfig.8 @@ -1,6 +1,6 @@ .\" $FreeBSD$ .\" -.\" Copyright (c) 2008 Hans Petter Selasky. All rights reserved. +.\" Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd November 1, 2009 +.Dd January 6, 2010 .Dt USBCONFIG 8 .Os .Sh NAME @@ -34,6 +34,9 @@ .Op Fl u Ar unit .Op Fl a Ar addr .Op cmds... +.Nm +.Op Fl d Ar [ugen]. +.Op cmds... .Sh DESCRIPTION The .Nm @@ -46,6 +49,9 @@ Limit device range to USB devices connected to the given USBUS unit. .It Fl a Ar addr Limit device range to the given USB device index. Should only be used in conjunction with the unit argument. +.It Fl d Ar [ugen]. +Limit device range to USB devices connected to the given unit and address. +The unit and address coordinates may be prefixed by the lowercased word "ugen". .It Fl h Show help and available commands. .El @@ -57,5 +63,34 @@ prints a list of all available USB devices. Show information about the device on USB bus 1 at address 2: .Pp .Dl usbconfig -u 1 -a 2 dump_info +.Pp +Dump HID descriptor for device on USB bus 1 at address 2: +.Pp +.Dl usbconfig -u 1 -a 2 do_request 0x81 0x06 0x2200 0 0x100 +.Pp +Dump string descriptor at index Z for device on USB bus 1 at address 2: +.Pp +.Dl usbconfig -u 1 -a 2 dump_string Z +.Pp +Dump current configuration descriptor for device on USB bus 1 at address 2: +.Pp +.Dl usbconfig -u 1 -a 2 dump_curr_config_desc +.Pp +Dump device descriptor for device on USB bus 1 at address 2: +.Pp +.Dl usbconfig -u 1 -a 2 dump_device_desc +.Pp +Program the device on USB bus 1 at address 2 to suspend, resume, power off, go into power save, or power on: +.Pp +.Dl usbconfig -u 1 -a 2 suspend +.Dl usbconfig -u 1 -a 2 resume +.Dl usbconfig -u 1 -a 2 power_off +.Dl usbconfig -u 1 -a 2 power_save +.Dl usbconfig -u 1 -a 2 power_on +.Pp +Display a list of available quirk names: +.Pp +.Dl usbconfig dump_quirk_names +.Pp .Sh SEE ALSO .Xr usb 4 diff --git a/usr.sbin/usbconfig/usbconfig.c b/usr.sbin/usbconfig/usbconfig.c index 810e183bf89d..fd701a7a8b05 100644 --- a/usr.sbin/usbconfig/usbconfig.c +++ b/usr.sbin/usbconfig/usbconfig.c @@ -1,6 +1,6 @@ /* $FreeBSD$ */ /*- - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2008-2009 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -81,6 +81,8 @@ struct options { uint8_t got_show_iface_driver:1; uint8_t got_remove_device_quirk:1; uint8_t got_add_device_quirk:1; + uint8_t got_remove_quirk:1; + uint8_t got_add_quirk:1; uint8_t got_dump_string:1; uint8_t got_do_request:1; }; @@ -94,6 +96,7 @@ struct token { enum { T_UNIT, T_ADDR, + T_UGEN, T_IFACE, T_SET_CONFIG, T_SET_ALT, @@ -101,6 +104,8 @@ enum { T_GET_TEMPLATE, T_ADD_DEVICE_QUIRK, T_REMOVE_DEVICE_QUIRK, + T_ADD_QUIRK, + T_REMOVE_QUIRK, T_SHOW_IFACE_DRIVER, T_DUMP_QUIRK_NAMES, T_DUMP_DEVICE_QUIRKS, @@ -124,6 +129,7 @@ static struct options options; static const struct token token[] = { {"-u", T_UNIT, 1}, {"-a", T_ADDR, 1}, + {"-d", T_UGEN, 1}, {"-i", T_IFACE, 1}, {"set_config", T_SET_CONFIG, 1}, {"set_alt", T_SET_ALT, 1}, @@ -131,6 +137,8 @@ static const struct token token[] = { {"get_template", T_GET_TEMPLATE, 0}, {"add_dev_quirk_vplh", T_ADD_DEVICE_QUIRK, 5}, {"remove_dev_quirk_vplh", T_REMOVE_DEVICE_QUIRK, 5}, + {"add_quirk", T_ADD_QUIRK, 1}, + {"remove_quirk", T_REMOVE_QUIRK, 1}, {"dump_quirk_names", T_DUMP_QUIRK_NAMES, 0}, {"dump_device_quirks", T_DUMP_DEVICE_QUIRKS, 0}, {"dump_device_desc", T_DUMP_DEVICE_DESC, 0}, @@ -246,12 +254,21 @@ get_int(const char *s) return val; } +static void +duplicate_option(const char *ptr) +{ + printf("Syntax error: " + "Duplicate option: '%s'\n", ptr); + exit(1); +} + static void usage(void) { printf("" "usbconfig - configure the USB subsystem" "\n" "usage: usbconfig -u -a -i [cmds...]" "\n" + "usage: usbconfig -d [ugen]. -i [cmds...]" "\n" "commands:" "\n" " set_config " "\n" " set_alt " "\n" @@ -259,6 +276,8 @@ usage(void) " get_template" "\n" " add_dev_quirk_vplh " "\n" " remove_dev_quirk_vplh " "\n" + " add_quirk " "\n" + " remove_quirk " "\n" " dump_quirk_names" "\n" " dump_device_quirks" "\n" " dump_device_desc" "\n" @@ -360,25 +379,33 @@ flush_command(struct libusb20_backend *pbe, struct options *opt) } matches++; + if (opt->got_remove_quirk) { + struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; + + ddesc = libusb20_dev_get_device_desc(pdev); + + be_dev_remove_quirk(pbe, + ddesc->idVendor, ddesc->idProduct, + ddesc->bcdDevice, ddesc->bcdDevice, + opt->quirkname); + } + + if (opt->got_add_quirk) { + struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; + + ddesc = libusb20_dev_get_device_desc(pdev); + + be_dev_add_quirk(pbe, + ddesc->idVendor, ddesc->idProduct, + ddesc->bcdDevice, ddesc->bcdDevice, + opt->quirkname); + } + if (libusb20_dev_open(pdev, 0)) { err(1, "could not open device"); } if (opt->got_dump_string) { - char *pbuf; - - pbuf = malloc(256); - if (pbuf == NULL) { - err(1, "out of memory"); - } - if (libusb20_dev_req_string_simple_sync(pdev, - opt->string_index, pbuf, 256)) { - printf("STRING_0x%02x = \n", - opt->string_index); - } else { - printf("STRING_0x%02x = <%s>\n", - opt->string_index, pbuf); - } - free(pbuf); + dump_string_by_index(pdev, opt->string_index); } if (opt->got_do_request) { uint16_t actlen; @@ -501,6 +528,9 @@ main(int argc, char **argv) { struct libusb20_backend *pbe; struct options *opt = &options; + const char *ptr; + int unit; + int addr; int n; int t; @@ -518,6 +548,28 @@ main(int argc, char **argv) if (t > 255) t = 255; switch (get_token(argv[n], t)) { + case T_ADD_QUIRK: + if (opt->got_add_quirk) { + flush_command(pbe, opt); + } + opt->quirkname = argv[n + 1]; + n++; + + opt->got_add_quirk = 1; + opt->got_any++; + break; + + case T_REMOVE_QUIRK: + if (opt->got_remove_quirk) { + flush_command(pbe, opt); + } + opt->quirkname = argv[n + 1]; + n++; + + opt->got_remove_quirk = 1; + opt->got_any++; + break; + case T_ADD_DEVICE_QUIRK: if (opt->got_add_device_quirk) { flush_command(pbe, opt); @@ -548,11 +600,15 @@ main(int argc, char **argv) break; case T_DUMP_QUIRK_NAMES: + if (opt->got_dump_quirk_names) + duplicate_option(argv[n]); opt->got_dump_quirk_names = 1; opt->got_any++; break; case T_DUMP_DEVICE_QUIRKS: + if (opt->got_dump_device_quirks) + duplicate_option(argv[n]); opt->got_dump_device_quirks = 1; opt->got_any++; break; @@ -561,6 +617,33 @@ main(int argc, char **argv) opt->got_show_iface_driver = 1; break; + case T_UGEN: + if (opt->got_any) { + /* allow multiple commands on the same line */ + flush_command(pbe, opt); + } + ptr = argv[n + 1]; + + if ((ptr[0] == 'u') && + (ptr[1] == 'g') && + (ptr[2] == 'e') && + (ptr[3] == 'n')) + ptr += 4; + + if ((sscanf(ptr, "%d.%d", + &unit, &addr) != 2) || + (unit < 0) || (unit > 65535) || + (addr < 0) || (addr > 65535)) { + errx(1, "cannot " + "parse '%s'", argv[n + 1]); + } + opt->bus = unit; + opt->addr = addr; + opt->got_bus = 1; +; opt->got_addr = 1; + n++; + break; + case T_UNIT: if (opt->got_any) { /* allow multiple commands on the same line */ @@ -581,84 +664,112 @@ main(int argc, char **argv) n++; break; case T_SET_CONFIG: + if (opt->got_set_config) + duplicate_option(argv[n]); opt->config_index = num_id(argv[n + 1], "cfg_index"); opt->got_set_config = 1; opt->got_any++; n++; break; case T_SET_ALT: + if (opt->got_set_alt) + duplicate_option(argv[n]); opt->alt_index = num_id(argv[n + 1], "cfg_index"); opt->got_set_alt = 1; opt->got_any++; n++; break; case T_SET_TEMPLATE: + if (opt->got_set_template) + duplicate_option(argv[n]); opt->template = get_int(argv[n + 1]); opt->got_set_template = 1; opt->got_any++; n++; break; case T_GET_TEMPLATE: + if (opt->got_get_template) + duplicate_option(argv[n]); opt->got_get_template = 1; opt->got_any++; break; case T_DUMP_DEVICE_DESC: + if (opt->got_dump_device_desc) + duplicate_option(argv[n]); opt->got_dump_device_desc = 1; opt->got_any++; break; case T_DUMP_CURR_CONFIG_DESC: + if (opt->got_dump_curr_config) + duplicate_option(argv[n]); opt->got_dump_curr_config = 1; opt->got_any++; break; case T_DUMP_ALL_CONFIG_DESC: + if (opt->got_dump_all_config) + duplicate_option(argv[n]); opt->got_dump_all_config = 1; opt->got_any++; break; case T_DUMP_INFO: + if (opt->got_dump_info) + duplicate_option(argv[n]); opt->got_dump_info = 1; opt->got_any++; break; case T_DUMP_STRING: - if (opt->got_dump_string) { - flush_command(pbe, opt); - } + if (opt->got_dump_string) + duplicate_option(argv[n]); opt->string_index = num_id(argv[n + 1], "str_index"); opt->got_dump_string = 1; opt->got_any++; n++; break; case T_SUSPEND: + if (opt->got_suspend) + duplicate_option(argv[n]); opt->got_suspend = 1; opt->got_any++; break; case T_RESUME: + if (opt->got_resume) + duplicate_option(argv[n]); opt->got_resume = 1; opt->got_any++; break; case T_POWER_OFF: + if (opt->got_power_off) + duplicate_option(argv[n]); opt->got_power_off = 1; opt->got_any++; break; case T_POWER_SAVE: + if (opt->got_power_save) + duplicate_option(argv[n]); opt->got_power_save = 1; opt->got_any++; break; case T_POWER_ON: + if (opt->got_power_on) + duplicate_option(argv[n]); opt->got_power_on = 1; opt->got_any++; break; case T_RESET: + if (opt->got_reset) + duplicate_option(argv[n]); opt->got_reset = 1; opt->got_any++; break; case T_LIST: + if (opt->got_list) + duplicate_option(argv[n]); opt->got_list = 1; opt->got_any++; break; case T_DO_REQUEST: - if (opt->got_do_request) { - flush_command(pbe, opt); - } + if (opt->got_do_request) + duplicate_option(argv[n]); LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &opt->setup); opt->setup.bmRequestType = num_id(argv[n + 1], "bmReqTyp"); opt->setup.bRequest = num_id(argv[n + 2], "bReq");