/* $FreeBSD: head/usr.sbin/usbconfig/usbconfig.c 248236 2013-03-13 12:23:14Z hselasky $ */ /*- * 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 * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dump.h" struct options { const char *quirkname; void *buffer; int template; gid_t gid; uid_t uid; mode_t mode; uint32_t got_any; struct LIBUSB20_CONTROL_SETUP_DECODED setup; uint16_t bus; uint16_t addr; uint16_t iface; uint16_t vid; uint16_t pid; uint16_t lo_rev; /* inclusive */ uint16_t hi_rev; /* inclusive */ uint8_t string_index; uint8_t config_index; uint8_t alt_index; uint8_t got_list:1; uint8_t got_bus:1; uint8_t got_addr:1; uint8_t got_iface:1; uint8_t got_set_config:1; uint8_t got_set_alt:1; uint8_t got_set_template:1; uint8_t got_get_template:1; uint8_t got_suspend:1; uint8_t got_resume:1; uint8_t got_reset:1; uint8_t got_power_off:1; uint8_t got_power_save:1; uint8_t got_power_on:1; uint8_t got_dump_device_quirks:1; uint8_t got_dump_quirk_names:1; uint8_t got_dump_device_desc:1; uint8_t got_dump_curr_config:1; uint8_t got_dump_all_config:1; uint8_t got_dump_info:1; 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; }; struct token { const char *name; uint8_t value; uint8_t narg; }; enum { T_UNIT, T_ADDR, T_UGEN, T_IFACE, T_SET_CONFIG, T_SET_ALT, T_SET_TEMPLATE, 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, T_DUMP_DEVICE_DESC, T_DUMP_CURR_CONFIG_DESC, T_DUMP_ALL_CONFIG_DESC, T_DUMP_STRING, T_DUMP_INFO, T_SUSPEND, T_RESUME, T_POWER_OFF, T_POWER_SAVE, T_POWER_ON, T_RESET, T_LIST, T_DO_REQUEST, }; 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}, {"set_template", T_SET_TEMPLATE, 1}, {"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}, {"dump_curr_config_desc", T_DUMP_CURR_CONFIG_DESC, 0}, {"dump_all_config_desc", T_DUMP_ALL_CONFIG_DESC, 0}, {"dump_string", T_DUMP_STRING, 1}, {"dump_info", T_DUMP_INFO, 0}, {"show_ifdrv", T_SHOW_IFACE_DRIVER, 0}, {"suspend", T_SUSPEND, 0}, {"resume", T_RESUME, 0}, {"power_off", T_POWER_OFF, 0}, {"power_save", T_POWER_SAVE, 0}, {"power_on", T_POWER_ON, 0}, {"reset", T_RESET, 0}, {"list", T_LIST, 0}, {"do_request", T_DO_REQUEST, 5}, }; static void be_dev_remove_quirk(struct libusb20_backend *pbe, uint16_t vid, uint16_t pid, uint16_t lorev, uint16_t hirev, const char *str) { struct libusb20_quirk q; int error; memset(&q, 0, sizeof(q)); q.vid = vid; q.pid = pid; q.bcdDeviceLow = lorev; q.bcdDeviceHigh = hirev; strlcpy(q.quirkname, str, sizeof(q.quirkname)); error = libusb20_be_remove_dev_quirk(pbe, &q); if (error) { fprintf(stderr, "Removing quirk '%s' failed, continuing.\n", str); } return; } static void be_dev_add_quirk(struct libusb20_backend *pbe, uint16_t vid, uint16_t pid, uint16_t lorev, uint16_t hirev, const char *str) { struct libusb20_quirk q; int error; memset(&q, 0, sizeof(q)); q.vid = vid; q.pid = pid; q.bcdDeviceLow = lorev; q.bcdDeviceHigh = hirev; strlcpy(q.quirkname, str, sizeof(q.quirkname)); error = libusb20_be_add_dev_quirk(pbe, &q); if (error) { fprintf(stderr, "Adding quirk '%s' failed, continuing.\n", str); } return; } static uint8_t get_token(const char *str, uint8_t narg) { uint8_t n; for (n = 0; n != (sizeof(token) / sizeof(token[0])); n++) { if (strcasecmp(str, token[n].name) == 0) { if (token[n].narg > narg) { /* too few arguments */ break; } return (token[n].value); } } return (0 - 1); } static uid_t num_id(const char *name, const char *type) { uid_t val; char *ep; errno = 0; val = strtoul(name, &ep, 0); if (errno) { err(1, "%s", name); } if (*ep != '\0') { errx(1, "%s: illegal %s name", name, type); } return (val); } static int get_int(const char *s) { int val; char *ep; errno = 0; val = strtoul(s, &ep, 0); if (errno) { err(1, "%s", s); } if (*ep != '\0') { errx(1, "illegal number: %s", s); } return val; } static void duplicate_option(const char *ptr) { fprintf(stderr, "Syntax error: " "Duplicate option: '%s'\n", ptr); exit(1); } static void usage(void) { fprintf(stderr, "" "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" " set_template