-/*****************************************************************************/
-
+// SPDX-License-Identifier: GPL-2.0+
/*
- * lsusb.c -- lspci like utility for the USB bus
- *
- * Copyright (C) 1999-2001, 2003
- * Thomas Sailer (t.sailer@alumni.ethz.ch)
- * Copyright (C) 2003-2005 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * lspci like utility for the USB bus
*
+ * Copyright (C) 1999-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
+ * Copyright (C) 2003-2005 David Brownell
*/
-/*****************************************************************************/
-
#include "config.h"
-#include <sys/types.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <stdbool.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#include "lsusb.h"
#include "names.h"
+#include "sysfs.h"
#include "usbmisc.h"
+#include "desc-defs.h"
+#include "desc-dump.h"
#include <getopt.h>
#define USB_DC_20_EXTENSION 0x02
#define USB_DC_SUPERSPEED 0x03
#define USB_DC_CONTAINER_ID 0x04
+#define USB_DC_PLATFORM 0x05
+#define USB_DC_SUPERSPEEDPLUS 0x0a
+#define USB_DC_BILLBOARD 0x0d
+#define USB_DC_BILLBOARD_ALT_MODE 0x0f
+#define USB_DC_CONFIGURATION_SUMMARY 0x10
/* Conventional codes for class-specific descriptors. The convention is
* defined in the USB "Common Class" Spec (3.11). Individual class specs
#define USB_AUDIO_CLASS_2 0x20
#endif
+/* USB DCD for Audio Devices Release 3.0: Section A.6, pp139 */
+#ifndef USB_AUDIO_CLASS_3
+#define USB_AUDIO_CLASS_3 0x30
+#endif
+
+#ifndef USB_VIDEO_PROTOCOL_15
+#define USB_VIDEO_PROTOCOL_15 0x01
+#endif
+
#define VERBLEVEL_DEFAULT 0 /* 0 gives lspci behaviour; 1, lsusb-0.9 */
#define CTRL_RETRIES 2
#define HUB_STATUS_BYTELEN 3 /* max 3 bytes status = hub + 23 ports */
-static const char procbususb[] = "/proc/bus/usb";
-static unsigned int verblevel = VERBLEVEL_DEFAULT;
+#define BILLBOARD_MAX_NUM_ALT_MODE (0x34)
+
+/* from WebUSB specification : https://wicg.github.io/webusb/ */
+#define WEBUSB_GUID "{3408b638-09a9-47a0-8bfd-a0768815b665}"
+#define WEBUSB_GET_URL 0x02
+#define USB_DT_WEBUSB_URL 0x03
+
+unsigned int verblevel = VERBLEVEL_DEFAULT;
static int do_report_desc = 1;
static const char * const encryption_type[] = {
"UNSECURE",
"RESERVED"
};
+static const char * const vconn_power[] = {
+ "1W",
+ "1.5W",
+ "2W",
+ "3W",
+ "4W",
+ "5W",
+ "6W",
+ "reserved"
+};
+
+static const char * const alt_mode_state[] = {
+ "Unspecified Error",
+ "Alternate Mode configuration not attempted",
+ "Alternate Mode configuration attempted but unsuccessful",
+ "Alternate Mode configuration successful"
+};
+
static void dump_interface(libusb_device_handle *dev, const struct libusb_interface *interface);
static void dump_endpoint(libusb_device_handle *dev, const struct libusb_interface_descriptor *interface, const struct libusb_endpoint_descriptor *endpoint);
static void dump_audiocontrol_interface(libusb_device_handle *dev, const unsigned char *buf, int protocol);
static void dump_audiostreaming_interface(libusb_device_handle *dev, const unsigned char *buf, int protocol);
static void dump_midistreaming_interface(libusb_device_handle *dev, const unsigned char *buf);
-static void dump_videocontrol_interface(libusb_device_handle *dev, const unsigned char *buf);
+static void dump_videocontrol_interface(libusb_device_handle *dev, const unsigned char *buf, int protocol);
static void dump_videostreaming_interface(const unsigned char *buf);
static void dump_dfu_interface(const unsigned char *buf);
static char *dump_comm_descriptor(libusb_device_handle *dev, const unsigned char *buf, char *indent);
static void dump_hid_device(libusb_device_handle *dev, const struct libusb_interface_descriptor *interface, const unsigned char *buf);
-static void dump_audiostreaming_endpoint(const unsigned char *buf, int protocol);
+static void dump_printer_device(libusb_device_handle *dev, const struct libusb_interface_descriptor *interface, const unsigned char *buf);
+static void dump_audiostreaming_endpoint(libusb_device_handle *dev, const unsigned char *buf, int protocol);
static void dump_midistreaming_endpoint(const unsigned char *buf);
static void dump_hub(const char *prefix, const unsigned char *p, int tt_type);
static void dump_ccid_device(const unsigned char *buf);
+static void dump_billboard_device_capability_desc(libusb_device_handle *dev, unsigned char *buf);
+static void dump_billboard_alt_mode_capability_desc(libusb_device_handle *dev, unsigned char *buf);
/* ---------------------------------------------------------------------- */
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}
+static unsigned int convert_le_u16 (const unsigned char *buf)
+{
+ return buf[0] | (buf[1] << 8);
+}
+
/* ---------------------------------------------------------------------- */
/* workaround libusb API goofs: "byte" should never be sign extended;
- * using "char" is trouble. Likewise, sizes should never be negative.
+ * using "char" is trouble.
*/
static inline int typesafe_control_msg(libusb_device_handle *dev,
int ret = libusb_control_transfer(dev, requesttype, request, value,
idx, bytes, size, timeout);
- if (ret < 0)
- return -ret;
- else
- return ret;
+ return ret;
}
#define usb_control_msg typesafe_control_msg
-static int get_protocol_string(char *buf, size_t size, u_int8_t cls, u_int8_t subcls, u_int8_t proto)
+static int get_protocol_string(char *buf, size_t size, uint8_t cls, uint8_t subcls, uint8_t proto)
{
const char *cp;
return snprintf(buf, size, "%s", cp);
}
-static int get_audioterminal_string(char *buf, size_t size, u_int16_t termt)
-{
- const char *cp;
-
- if (size < 1)
- return 0;
- *buf = 0;
- if (!(cp = names_audioterminal(termt)))
- return 0;
- return snprintf(buf, size, "%s", cp);
-}
-
-static int get_videoterminal_string(char *buf, size_t size, u_int16_t termt)
+static int get_videoterminal_string(char *buf, size_t size, uint16_t termt)
{
const char *cp;
"-%02x%02x"
"-%02x%02x"
"-%02x%02x%02x%02x%02x%02x}",
- buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5],
- buf[6], buf[7],
+ buf[3], buf[2], buf[1], buf[0],
+ buf[5], buf[4],
+ buf[7], buf[6],
buf[8], buf[9],
buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
return guid;
*/
static void dump_device(
- libusb_device_handle *dev,
+ libusb_device *dev,
struct libusb_device_descriptor *descriptor
)
{
char vendor[128], product[128];
char cls[128], subcls[128], proto[128];
- char *mfg, *prod, *serial;
+ char mfg[128] = {0}, prod[128] = {0}, serial[128] = {0};
+ char sysfs_name[PATH_MAX];
get_vendor_string(vendor, sizeof(vendor), descriptor->idVendor);
get_product_string(product, sizeof(product),
get_protocol_string(proto, sizeof(proto), descriptor->bDeviceClass,
descriptor->bDeviceSubClass, descriptor->bDeviceProtocol);
- mfg = get_dev_string(dev, descriptor->iManufacturer);
- prod = get_dev_string(dev, descriptor->iProduct);
- serial = get_dev_string(dev, descriptor->iSerialNumber);
+ if (get_sysfs_name(sysfs_name, sizeof(sysfs_name), dev) >= 0) {
+ read_sysfs_prop(mfg, sizeof(vendor), sysfs_name, "manufacturer");
+ read_sysfs_prop(prod, sizeof(vendor), sysfs_name, "product");
+ read_sysfs_prop(serial, sizeof(vendor), sysfs_name, "serial");
+ }
printf("Device Descriptor:\n"
" bLength %5u\n"
descriptor->iProduct, prod,
descriptor->iSerialNumber, serial,
descriptor->bNumConfigurations);
-
- free(mfg);
- free(prod);
- free(serial);
}
static void dump_wire_adapter(const unsigned char *buf)
printf(" Security Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
- " wTotalLength %5u\n"
+ " wTotalLength 0x%04x\n"
" bNumEncryptionTypes %5u\n",
buf[0], buf[1], (buf[3] << 8 | buf[2]), buf[4]);
}
free(func);
}
-static void dump_config(libusb_device_handle *dev, struct libusb_config_descriptor *config)
+static void dump_config(libusb_device_handle *dev, struct libusb_config_descriptor *config, unsigned speed)
{
char *cfg;
int i;
printf(" Configuration Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
- " wTotalLength %5u\n"
+ " wTotalLength 0x%04x\n"
" bNumInterfaces %5u\n"
" bConfigurationValue %5u\n"
" iConfiguration %5u %s\n"
printf(" Remote Wakeup\n");
if (config->bmAttributes & 0x10)
printf(" Battery Powered\n");
- printf(" MaxPower %5umA\n", config->MaxPower * 2);
+ printf(" MaxPower %5umA\n", config->MaxPower * (speed >= 0x0300 ? 8 : 2));
/* avoid re-ordering or hiding descriptors for display */
if (config->extra_length) {
if (interface->extra_length) {
size = interface->extra_length;
buf = interface->extra;
- while (size >= 2 * sizeof(u_int8_t)) {
+ while (size >= 2 * sizeof(uint8_t)) {
if (buf[0] < 2) {
dump_junk(buf, " ", size);
break;
case USB_CLASS_VIDEO:
switch (interface->bInterfaceSubClass) {
case 1:
- dump_videocontrol_interface(dev, buf);
+ dump_videocontrol_interface(dev, buf, interface->bInterfaceProtocol);
break;
case 2:
dump_videostreaming_interface(buf);
case LIBUSB_CLASS_HID:
dump_hid_device(dev, interface, buf);
break;
+ case LIBUSB_CLASS_PRINTER:
+ dump_printer_device(dev, interface, buf);
+ break;
case USB_CLASS_CCID:
dump_ccid_device(buf);
break;
case USB_DT_CS_ENDPOINT:
switch (interface->bInterfaceSubClass) {
case 2:
- dump_audiostreaming_endpoint(buf, interface->bInterfaceProtocol);
+ dump_audiostreaming_endpoint(dev, buf, interface->bInterfaceProtocol);
break;
default:
goto dump;
[0xE0 ... 0xEF] = "Vendor specific",
[0xF0 ... 0xFF] = "Reserved",
};
-
+
if (buf[0] == 4 && buf[1] == 0x24) {
printf(" %s (0x%02x)\n", pipe_name[buf[2]], buf[2]);
} else {
if (endpoint->extra_length) {
size = endpoint->extra_length;
buf = endpoint->extra;
- while (size >= 2 * sizeof(u_int8_t)) {
+ while (size >= 2 * sizeof(uint8_t)) {
if (buf[0] < 2) {
dump_junk(buf, " ", size);
break;
switch (buf[1]) {
case USB_DT_CS_ENDPOINT:
if (interface->bInterfaceClass == 1 && interface->bInterfaceSubClass == 2)
- dump_audiostreaming_endpoint(buf, interface->bInterfaceProtocol);
+ dump_audiostreaming_endpoint(dev, buf, interface->bInterfaceProtocol);
else if (interface->bInterfaceClass == 1 && interface->bInterfaceSubClass == 3)
dump_midistreaming_endpoint(buf);
break;
* Audio Class descriptor dump
*/
-struct bmcontrol {
- const char *name;
- unsigned int bit;
-};
-
-static const struct bmcontrol uac2_interface_header_bmcontrols[] = {
- { "Latency control", 0 },
- { NULL }
-};
-
-static const struct bmcontrol uac_fu_bmcontrols[] = {
- { "Mute", 0 },
- { "Volume", 1 },
- { "Bass", 2 },
- { "Mid", 3 },
- { "Treble", 4 },
- { "Graphic Equalizer", 5 },
- { "Automatic Gain", 6 },
- { "Delay", 7 },
- { "Bass Boost", 8 },
- { "Loudness", 9 },
- { "Input gain", 10 },
- { "Input gain pad", 11 },
- { "Phase inverter", 12 },
- { NULL }
-};
-
-static const struct bmcontrol uac2_input_term_bmcontrols[] = {
- { "Copy Protect", 0 },
- { "Connector", 1 },
- { "Overload", 2 },
- { "Cluster", 3 },
- { "Underflow", 4 },
- { "Overflow", 5 },
- { NULL }
-};
-
-static const struct bmcontrol uac2_output_term_bmcontrols[] = {
- { "Copy Protect", 0 },
- { "Connector", 1 },
- { "Overload", 2 },
- { "Underflow", 3 },
- { "Overflow", 4 },
- { NULL }
-};
-
-static const struct bmcontrol uac2_mixer_unit_bmcontrols[] = {
- { "Cluster", 0 },
- { "Underflow", 1 },
- { "Overflow", 2 },
- { NULL }
-};
+static void dump_audio_subtype(libusb_device_handle *dev,
+ const char *name,
+ const struct desc * const desc[3],
+ const unsigned char *buf,
+ int protocol,
+ unsigned int indent)
+{
+ static const char * const strings[] = { "UAC1", "UAC2", "UAC3" };
+ unsigned int idx = 0;
-static const struct bmcontrol uac2_extension_unit_bmcontrols[] = {
- { "Enable", 0 },
- { "Cluster", 1 },
- { "Underflow", 2 },
- { "Overflow", 3 },
- { NULL }
-};
+ switch (protocol) {
+ case USB_AUDIO_CLASS_2: idx = 1; break;
+ case USB_AUDIO_CLASS_3: idx = 2; break;
+ }
-static const struct bmcontrol uac2_clock_source_bmcontrols[] = {
- { "Clock Frequency", 0 },
- { "Clock Validity", 1 },
- { NULL }
-};
+ printf("(%s)\n", name);
-static const struct bmcontrol uac2_clock_selector_bmcontrols[] = {
- { "Clock Selector", 0 },
- { NULL }
-};
+ if (desc[idx] == NULL) {
+ printf("%*sWarning: %s descriptors are illegal for %s\n",
+ indent * 2, "", name, strings[idx]);
+ return;
+ }
-static const struct bmcontrol uac2_clock_multiplier_bmcontrols[] = {
- { "Clock Numerator", 0 },
- { "Clock Denominator", 1 },
- { NULL }
-};
+ /* Skip the first three bytes; those common fields have already
+ * been dumped. */
+ desc_dump(dev, desc[idx], buf + 3, buf[0] - 3, indent);
+}
-static const struct bmcontrol uac2_selector_bmcontrols[] = {
- { "Selector", 0 },
- { NULL }
+/* USB Audio Class subtypes */
+enum uac_interface_subtype {
+ UAC_INTERFACE_SUBTYPE_AC_DESCRIPTOR_UNDEFINED = 0x00,
+ UAC_INTERFACE_SUBTYPE_HEADER = 0x01,
+ UAC_INTERFACE_SUBTYPE_INPUT_TERMINAL = 0x02,
+ UAC_INTERFACE_SUBTYPE_OUTPUT_TERMINAL = 0x03,
+ UAC_INTERFACE_SUBTYPE_EXTENDED_TERMINAL = 0x04,
+ UAC_INTERFACE_SUBTYPE_MIXER_UNIT = 0x05,
+ UAC_INTERFACE_SUBTYPE_SELECTOR_UNIT = 0x06,
+ UAC_INTERFACE_SUBTYPE_FEATURE_UNIT = 0x07,
+ UAC_INTERFACE_SUBTYPE_EFFECT_UNIT = 0x08,
+ UAC_INTERFACE_SUBTYPE_PROCESSING_UNIT = 0x09,
+ UAC_INTERFACE_SUBTYPE_EXTENSION_UNIT = 0x0a,
+ UAC_INTERFACE_SUBTYPE_CLOCK_SOURCE = 0x0b,
+ UAC_INTERFACE_SUBTYPE_CLOCK_SELECTOR = 0x0c,
+ UAC_INTERFACE_SUBTYPE_CLOCK_MULTIPLIER = 0x0d,
+ UAC_INTERFACE_SUBTYPE_SAMPLE_RATE_CONVERTER = 0x0e,
+ UAC_INTERFACE_SUBTYPE_CONNECTORS = 0x0f,
+ UAC_INTERFACE_SUBTYPE_POWER_DOMAIN = 0x10,
};
-static void dump_audio_bmcontrols(const char *prefix, int bmcontrols, const struct bmcontrol *list, int protocol)
+/*
+ * UAC1, UAC2, and UAC3 define bDescriptorSubtype differently for the
+ * AudioControl interface, so we need to do some ugly remapping:
+ *
+ * val | UAC1 | UAC2 | UAC3
+ * -----|-----------------|-----------------------|---------------------
+ * 0x00 | AC UNDEFINED | AC UNDEFINED | AC UNDEFINED
+ * 0x01 | HEADER | HEADER | HEADER
+ * 0x02 | INPUT_TERMINAL | INPUT_TERMINAL | INPUT_TERMINAL
+ * 0x03 | OUTPUT_TERMINAL | OUTPUT_TERMINAL | OUTPUT_TERMINAL
+ * 0x04 | MIXER_UNIT | MIXER_UNIT | EXTENDED_TERMINAL
+ * 0x05 | SELECTOR_UNIT | SELECTOR_UNIT | MIXER_UNIT
+ * 0x06 | FEATURE_UNIT | FEATURE_UNIT | SELECTOR_UNIT
+ * 0x07 | PROCESSING_UNIT | EFFECT_UNIT | FEATURE_UNIT
+ * 0x08 | EXTENSION_UNIT | PROCESSING_UNIT | EFFECT_UNIT
+ * 0x09 | - | EXTENSION_UNIT | PROCESSING_UNIT
+ * 0x0a | - | CLOCK_SOURCE | EXTENSION_UNIT
+ * 0x0b | - | CLOCK_SELECTOR | CLOCK_SOURCE
+ * 0x0c | - | CLOCK_MULTIPLIER | CLOCK_SELECTOR
+ * 0x0d | - | SAMPLE_RATE_CONVERTER | CLOCK_MULTIPLIER
+ * 0x0e | - | - | SAMPLE_RATE_CONVERTER
+ * 0x0f | - | - | CONNECTORS
+ * 0x10 | - | - | POWER_DOMAIN
+ */
+static enum uac_interface_subtype get_uac_interface_subtype(unsigned char c, int protocol)
{
- while (list->name) {
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- if (bmcontrols & (1 << list->bit))
- printf("%s%s Control\n", prefix, list->name);
-
- break;
-
- case USB_AUDIO_CLASS_2: {
- const char * const ctrl_type[] = { "read-only", "ILLEGAL (0b10)", "read/write" };
- int ctrl = (bmcontrols >> (list->bit * 2)) & 0x3;
-
- if (ctrl)
- printf("%s%s Control (%s)\n", prefix, list->name, ctrl_type[ctrl-1]);
-
- break;
+ switch (protocol) {
+ case USB_AUDIO_CLASS_1:
+ switch(c) {
+ case 0x04: return UAC_INTERFACE_SUBTYPE_MIXER_UNIT;
+ case 0x05: return UAC_INTERFACE_SUBTYPE_SELECTOR_UNIT;
+ case 0x06: return UAC_INTERFACE_SUBTYPE_FEATURE_UNIT;
+ case 0x07: return UAC_INTERFACE_SUBTYPE_PROCESSING_UNIT;
+ case 0x08: return UAC_INTERFACE_SUBTYPE_EXTENSION_UNIT;
}
-
- } /* switch */
-
- list++;
+ break;
+ case USB_AUDIO_CLASS_2:
+ switch(c) {
+ case 0x04: return UAC_INTERFACE_SUBTYPE_MIXER_UNIT;
+ case 0x05: return UAC_INTERFACE_SUBTYPE_SELECTOR_UNIT;
+ case 0x06: return UAC_INTERFACE_SUBTYPE_FEATURE_UNIT;
+ case 0x07: return UAC_INTERFACE_SUBTYPE_EFFECT_UNIT;
+ case 0x08: return UAC_INTERFACE_SUBTYPE_PROCESSING_UNIT;
+ case 0x09: return UAC_INTERFACE_SUBTYPE_EXTENSION_UNIT;
+ case 0x0a: return UAC_INTERFACE_SUBTYPE_CLOCK_SOURCE;
+ case 0x0b: return UAC_INTERFACE_SUBTYPE_CLOCK_SELECTOR;
+ case 0x0c: return UAC_INTERFACE_SUBTYPE_CLOCK_MULTIPLIER;
+ case 0x0d: return UAC_INTERFACE_SUBTYPE_SAMPLE_RATE_CONVERTER;
+ }
+ break;
+ case USB_AUDIO_CLASS_3:
+ /* No mapping required. */
+ break;
+ default:
+ /* Unknown protocol */
+ break;
}
-}
-static const char * const chconfig_uac2[] = {
- "Front Left (FL)", "Front Right (FR)", "Front Center (FC)", "Low Frequency Effects (LFE)",
- "Back Left (BL)", "Back Right (BR)", "Front Left of Center (FLC)", "Front Right of Center (FRC)", "Back Center (BC)",
- "Side Left (SL)", "Side Right (SR)",
- "Top Center (TC)", "Top Front Left (TFL)", "Top Front Center (TFC)", "Top Front Right (TFR)", "Top Back Left (TBL)",
- "Top Back Center (TBC)", "Top Back Right (TBR)", "Top Front Left of Center (TFLC)", "Top Front Right of Center (TFRC)",
- "Left Low Frequency Effects (LLFE)", "Right Low Frequency Effects (RLFE)",
- "Top Side Left (TSL)", "Top Side Right (TSR)", "Bottom Center (BC)",
- "Back Left of Center (BLC)", "Back Right of Center (BRC)"
-};
+ /* If the protocol was unknown, or the value was not known to require
+ * mapping, just return it unchanged. */
+ return c;
+}
static void dump_audiocontrol_interface(libusb_device_handle *dev, const unsigned char *buf, int protocol)
{
- static const char * const chconfig[] = {
- "Left Front (L)", "Right Front (R)", "Center Front (C)", "Low Freqency Enhancement (LFE)",
- "Left Surround (LS)", "Right Surround (RS)", "Left of Center (LC)", "Right of Center (RC)",
- "Surround (S)", "Side Left (SL)", "Side Right (SR)", "Top (T)"
- };
- static const char * const clock_source_attrs[] = {
- "External", "Internal fixed", "Internal variable", "Internal programmable"
- };
- unsigned int i, chcfg, j, k, N, termt, subtype;
- char *chnames = NULL, *term = NULL, termts[128];
+ enum uac_interface_subtype subtype;
if (buf[1] != USB_DT_CS_INTERFACE)
printf(" Warning: Invalid descriptor\n");
" bDescriptorSubtype %5u ",
buf[0], buf[1], buf[2]);
- /*
- * This is an utter mess - UAC2 defines some bDescriptorSubtype differently, so we have to do some ugly remapping here:
- *
- * bDescriptorSubtype UAC1 UAC2
- * ------------------------------------------------------------------------
- * 0x07 PROCESSING_UNIT EFFECT_UNIT
- * 0x08 EXTENSION_UNIT PROCESSING_UNIT
- * 0x09 - EXTENSION_UNIT
- *
- */
-
- if (protocol == USB_AUDIO_CLASS_2)
- switch(buf[2]) {
- case 0x07: subtype = 0xf0; break; /* effect unit */
- case 0x08: subtype = 0x07; break; /* processing unit */
- case 0x09: subtype = 0x08; break; /* extension unit */
- default: subtype = buf[2]; break; /* everything else is identical */
- }
- else
- subtype = buf[2];
+ subtype = get_uac_interface_subtype(buf[2], protocol);
switch (subtype) {
- case 0x01: /* HEADER */
- printf("(HEADER)\n");
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- if (buf[0] < 8+buf[7])
- printf(" Warning: Descriptor too short\n");
- printf(" bcdADC %2x.%02x\n"
- " wTotalLength %5u\n"
- " bInCollection %5u\n",
- buf[4], buf[3], buf[5] | (buf[6] << 8), buf[7]);
- for (i = 0; i < buf[7]; i++)
- printf(" baInterfaceNr(%2u) %5u\n", i, buf[8+i]);
- dump_junk(buf, " ", 8+buf[7]);
- break;
- case USB_AUDIO_CLASS_2:
- if (buf[0] < 9)
- printf(" Warning: Descriptor too short\n");
- printf(" bcdADC %2x.%02x\n"
- " bCategory %5u\n"
- " wTotalLength %5u\n"
- " bmControl 0x%02x\n",
- buf[4], buf[3], buf[5], buf[6] | (buf[7] << 8), buf[8]);
- dump_audio_bmcontrols(" ", buf[8], uac2_interface_header_bmcontrols, protocol);
- break;
- }
+ case UAC_INTERFACE_SUBTYPE_HEADER:
+ dump_audio_subtype(dev, "HEADER", desc_audio_ac_header, buf, protocol, 4);
break;
- case 0x02: /* INPUT_TERMINAL */
- printf("(INPUT_TERMINAL)\n");
- termt = buf[4] | (buf[5] << 8);
- get_audioterminal_string(termts, sizeof(termts), termt);
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- chnames = get_dev_string(dev, buf[10]);
- term = get_dev_string(dev, buf[11]);
- if (buf[0] < 12)
- printf(" Warning: Descriptor too short\n");
- chcfg = buf[8] | (buf[9] << 8);
- printf(" bTerminalID %5u\n"
- " wTerminalType 0x%04x %s\n"
- " bAssocTerminal %5u\n"
- " bNrChannels %5u\n"
- " wChannelConfig 0x%04x\n",
- buf[3], termt, termts, buf[6], buf[7], chcfg);
- for (i = 0; i < 12; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig[i]);
- printf(" iChannelNames %5u %s\n"
- " iTerminal %5u %s\n",
- buf[10], chnames, buf[11], term);
- dump_junk(buf, " ", 12);
- break;
- case USB_AUDIO_CLASS_2:
- chnames = get_dev_string(dev, buf[13]);
- term = get_dev_string(dev, buf[16]);
- if (buf[0] < 17)
- printf(" Warning: Descriptor too short\n");
- chcfg = buf[9] | (buf[10] << 8) | (buf[11] << 16) | (buf[12] << 24);
- printf(" bTerminalID %5u\n"
- " wTerminalType 0x%04x %s\n"
- " bAssocTerminal %5u\n"
- " bCSourceID %5d\n"
- " bNrChannels %5u\n"
- " bmChannelConfig 0x%08x\n",
- buf[3], termt, termts, buf[6], buf[7], buf[8], chcfg);
- for (i = 0; i < 26; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig_uac2[i]);
- printf(" bmControls 0x%04x\n", buf[14] | (buf[15] << 8));
- dump_audio_bmcontrols(" ", buf[14] | (buf[15] << 8), uac2_input_term_bmcontrols, protocol);
- printf(" iChannelNames %5u %s\n"
- " iTerminal %5u %s\n",
- buf[13], chnames, buf[16], term);
- dump_junk(buf, " ", 17);
- break;
- } /* switch (protocol) */
-
+ case UAC_INTERFACE_SUBTYPE_INPUT_TERMINAL:
+ dump_audio_subtype(dev, "INPUT_TERMINAL", desc_audio_ac_input_terminal, buf, protocol, 4);
break;
- case 0x03: /* OUTPUT_TERMINAL */
- printf("(OUTPUT_TERMINAL)\n");
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- term = get_dev_string(dev, buf[8]);
- termt = buf[4] | (buf[5] << 8);
- get_audioterminal_string(termts, sizeof(termts), termt);
- if (buf[0] < 9)
- printf(" Warning: Descriptor too short\n");
- printf(" bTerminalID %5u\n"
- " wTerminalType 0x%04x %s\n"
- " bAssocTerminal %5u\n"
- " bSourceID %5u\n"
- " iTerminal %5u %s\n",
- buf[3], termt, termts, buf[6], buf[7], buf[8], term);
- dump_junk(buf, " ", 9);
- break;
- case USB_AUDIO_CLASS_2:
- term = get_dev_string(dev, buf[11]);
- termt = buf[4] | (buf[5] << 8);
- get_audioterminal_string(termts, sizeof(termts), termt);
- if (buf[0] < 12)
- printf(" Warning: Descriptor too short\n");
- printf(" bTerminalID %5u\n"
- " wTerminalType 0x%04x %s\n"
- " bAssocTerminal %5u\n"
- " bSourceID %5u\n"
- " bCSourceID %5u\n"
- " bmControls 0x%04x\n",
- buf[3], termt, termts, buf[6], buf[7], buf[8], buf[9] | (buf[10] << 8));
- dump_audio_bmcontrols(" ", buf[9] | (buf[10] << 8), uac2_output_term_bmcontrols, protocol);
- printf(" iTerminal %5u %s\n", buf[11], term);
- dump_junk(buf, " ", 12);
- break;
- } /* switch (protocol) */
-
+ case UAC_INTERFACE_SUBTYPE_OUTPUT_TERMINAL:
+ dump_audio_subtype(dev, "OUTPUT_TERMINAL", desc_audio_ac_output_terminal, buf, protocol, 4);
break;
- case 0x04: /* MIXER_UNIT */
- printf("(MIXER_UNIT)\n");
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- j = buf[4];
- k = buf[j+5];
- if (j == 0 || k == 0) {
- printf(" Warning: mixer with %5u input and %5u output channels.\n", j, k);
- N = 0;
- } else {
- N = 1+(j*k-1)/8;
- }
- chnames = get_dev_string(dev, buf[8+j]);
- term = get_dev_string(dev, buf[9+j+N]);
- if (buf[0] < 10+j+N)
- printf(" Warning: Descriptor too short\n");
- chcfg = buf[6+j] | (buf[7+j] << 8);
- printf(" bUnitID %5u\n"
- " bNrInPins %5u\n",
- buf[3], buf[4]);
- for (i = 0; i < j; i++)
- printf(" baSourceID(%2u) %5u\n", i, buf[5+i]);
- printf(" bNrChannels %5u\n"
- " wChannelConfig 0x%04x\n",
- buf[5+j], chcfg);
- for (i = 0; i < 12; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig[i]);
- printf(" iChannelNames %5u %s\n",
- buf[8+j], chnames);
- for (i = 0; i < N; i++)
- printf(" bmControls 0x%02x\n", buf[9+j+i]);
- printf(" iMixer %5u %s\n", buf[9+j+N], term);
- dump_junk(buf, " ", 10+j+N);
- break;
-
- case USB_AUDIO_CLASS_2:
- j = buf[4];
- k = buf[0] - 13 - j;
- chnames = get_dev_string(dev, buf[10+j]);
- term = get_dev_string(dev, buf[12+j+k]);
- chcfg = buf[6+j] | (buf[7+j] << 8) | (buf[8+j] << 16) | (buf[9+j] << 24);
-
- printf(" bUnitID %5u\n"
- " bNrPins %5u\n",
- buf[3], buf[4]);
- for (i = 0; i < j; i++)
- printf(" baSourceID(%2u) %5u\n", i, buf[5+i]);
- printf(" bNrChannels %5u\n"
- " bmChannelConfig 0x%08x\n", buf[5+j], chcfg);
- for (i = 0; i < 26; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig_uac2[i]);
- printf(" iChannelNames %5u %s\n", buf[10+j], chnames);
-
- N = 0;
- for (i = 0; i < k; i++)
- N |= buf[11+j+i] << (i * 8);
-
- dump_bytes(buf+11+j, k);
-
- printf(" bmControls %02x\n", buf[11+j+k]);
- dump_audio_bmcontrols(" ", buf[11+j+k], uac2_mixer_unit_bmcontrols, protocol);
-
- printf(" iMixer %5u %s\n", buf[12+j+k], term);
- dump_junk(buf, " ", 13+j+k);
- break;
- } /* switch (protocol) */
+ case UAC_INTERFACE_SUBTYPE_MIXER_UNIT:
+ dump_audio_subtype(dev, "MIXER_UNIT", desc_audio_ac_mixer_unit, buf, protocol, 4);
break;
- case 0x05: /* SELECTOR_UNIT */
- printf("(SELECTOR_UNIT)\n");
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- if (buf[0] < 6+buf[4])
- printf(" Warning: Descriptor too short\n");
- term = get_dev_string(dev, buf[5+buf[4]]);
-
- printf(" bUnitID %5u\n"
- " bNrInPins %5u\n",
- buf[3], buf[4]);
- for (i = 0; i < buf[4]; i++)
- printf(" baSource(%2u) %5u\n", i, buf[5+i]);
- printf(" iSelector %5u %s\n",
- buf[5+buf[4]], term);
- dump_junk(buf, " ", 6+buf[4]);
- break;
- case USB_AUDIO_CLASS_2:
- if (buf[0] < 7+buf[4])
- printf(" Warning: Descriptor too short\n");
- term = get_dev_string(dev, buf[6+buf[4]]);
-
- printf(" bUnitID %5u\n"
- " bNrInPins %5u\n",
- buf[3], buf[4]);
- for (i = 0; i < buf[4]; i++)
- printf(" baSource(%2u) %5u\n", i, buf[5+i]);
- printf(" bmControls 0x%02x\n", buf[5+buf[4]]);
- dump_audio_bmcontrols(" ", buf[5+buf[4]], uac2_selector_bmcontrols, protocol);
- printf(" iSelector %5u %s\n",
- buf[6+buf[4]], term);
- dump_junk(buf, " ", 7+buf[4]);
- break;
- } /* switch (protocol) */
-
+ case UAC_INTERFACE_SUBTYPE_SELECTOR_UNIT:
+ dump_audio_subtype(dev, "SELECTOR_UNIT", desc_audio_ac_selector_unit, buf, protocol, 4);
break;
- case 0x06: /* FEATURE_UNIT */
- printf("(FEATURE_UNIT)\n");
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- j = buf[5];
- if (!j)
- j = 1;
- k = (buf[0] - 7) / j;
- if (buf[0] < 7+buf[5]*k)
- printf(" Warning: Descriptor too short\n");
- term = get_dev_string(dev, buf[6+buf[5]*k]);
- printf(" bUnitID %5u\n"
- " bSourceID %5u\n"
- " bControlSize %5u\n",
- buf[3], buf[4], buf[5]);
- for (i = 0; i < k; i++) {
- chcfg = buf[6+buf[5]*i];
- if (buf[5] > 1)
- chcfg |= (buf[7+buf[5]*i] << 8);
- for (j = 0; j < buf[5]; j++)
- printf(" bmaControls(%2u) 0x%02x\n", i, buf[6+buf[5]*i+j]);
-
- dump_audio_bmcontrols(" ", chcfg, uac_fu_bmcontrols, protocol);
- }
- printf(" iFeature %5u %s\n", buf[6+buf[5]*k], term);
- dump_junk(buf, " ", 7+buf[5]*k);
- break;
- case USB_AUDIO_CLASS_2:
- if (buf[0] < 10)
- printf(" Warning: Descriptor too short\n");
- k = (buf[0] - 6) / 4;
- printf(" bUnitID %5u\n"
- " bSourceID %5u\n",
- buf[3], buf[4]);
- for (i = 0; i < k; i++) {
- chcfg = buf[5+(4*i)] |
- buf[6+(4*i)] << 8 |
- buf[7+(4*i)] << 16 |
- buf[8+(4*i)] << 24;
- printf(" bmaControls(%2u) 0x%08x\n", i, chcfg);
- dump_audio_bmcontrols(" ", chcfg, uac_fu_bmcontrols, protocol);
- }
- term = get_dev_string(dev, buf[5+k*4]);
- printf(" iFeature %5u %s\n", buf[5+(k*4)], term);
- dump_junk(buf, " ", 6+(k*4));
- break;
- } /* switch (protocol) */
-
+ case UAC_INTERFACE_SUBTYPE_FEATURE_UNIT:
+ dump_audio_subtype(dev, "FEATURE_UNIT", desc_audio_ac_feature_unit, buf, protocol, 4);
break;
- case 0x07: /* PROCESSING_UNIT */
- printf("(PROCESSING_UNIT)\n");
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- j = buf[6];
- k = buf[11+j];
- chnames = get_dev_string(dev, buf[10+j]);
- term = get_dev_string(dev, buf[12+j+k]);
- chcfg = buf[8+j] | (buf[9+j] << 8);
- if (buf[0] < 13+j+k)
- printf(" Warning: Descriptor too short\n");
- printf(" bUnitID %5u\n"
- " wProcessType %5u\n"
- " bNrPins %5u\n",
- buf[3], buf[4] | (buf[5] << 8), buf[6]);
- for (i = 0; i < j; i++)
- printf(" baSourceID(%2u) %5u\n", i, buf[7+i]);
- printf(" bNrChannels %5u\n"
- " wChannelConfig 0x%04x\n", buf[7+j], chcfg);
- for (i = 0; i < 12; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig[i]);
- printf(" iChannelNames %5u %s\n"
- " bControlSize %5u\n", buf[10+j], chnames, buf[11+j]);
- for (i = 0; i < k; i++)
- printf(" bmControls(%2u) 0x%02x\n", i, buf[12+j+i]);
- if (buf[12+j] & 1)
- printf(" Enable Processing\n");
- printf(" iProcessing %5u %s\n"
- " Process-Specific ", buf[12+j+k], term);
- dump_bytes(buf+(13+j+k), buf[0]-(13+j+k));
- break;
- case USB_AUDIO_CLASS_2:
- j = buf[6];
- k = buf[0] - 17 - j;
- chnames = get_dev_string(dev, buf[12+j]);
- term = get_dev_string(dev, buf[15+j+k]);
- chcfg = buf[8+j] |
- (buf[9+j] << 8) |
- (buf[10+j] << 16) |
- (buf[11+j] << 24);
-
- printf(" bUnitID %5u\n"
- " wProcessType %5u\n"
- " bNrPins %5u\n",
- buf[3], buf[4] | (buf[5] << 8), buf[6]);
- for (i = 0; i < j; i++)
- printf(" baSourceID(%2u) %5u\n", i, buf[5+i]);
- printf(" bNrChannels %5u\n"
- " bmChannelConfig 0x%08x\n", buf[7+j], chcfg);
- for (i = 0; i < 26; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig_uac2[i]);
- printf(" iChannelNames %5u %s\n"
- " bmControls 0x%04x\n", buf[12+j], chnames, buf[13+j] | (buf[14+j] << 8));
- if (buf[12+j] & 1)
- printf(" Enable Processing\n");
- printf(" iProcessing %5u %s\n"
- " Process-Specific ", buf[15+j], term);
- dump_bytes(buf+(16+j), k);
- break;
- } /* switch (protocol) */
-
+ case UAC_INTERFACE_SUBTYPE_PROCESSING_UNIT:
+ dump_audio_subtype(dev, "PROCESSING_UNIT", desc_audio_ac_processing_unit, buf, protocol, 4);
break;
- case 0x08: /* EXTENSION_UNIT */
- printf("(EXTENSION_UNIT)\n");
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- j = buf[6];
- k = buf[11+j];
- chnames = get_dev_string(dev, buf[10+j]);
- term = get_dev_string(dev, buf[12+j+k]);
- chcfg = buf[8+j] | (buf[9+j] << 8);
- if (buf[0] < 13+j+k)
- printf(" Warning: Descriptor too short\n");
- printf(" bUnitID %5u\n"
- " wExtensionCode %5u\n"
- " bNrPins %5u\n",
- buf[3], buf[4] | (buf[5] << 8), buf[6]);
- for (i = 0; i < j; i++)
- printf(" baSourceID(%2u) %5u\n", i, buf[7+i]);
- printf(" bNrChannels %5u\n"
- " wChannelConfig %5u\n", buf[7+j], chcfg);
- for (i = 0; i < 12; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig[i]);
- printf(" iChannelNames %5u %s\n"
- " bControlSize %5u\n", buf[10+j], chnames, buf[11+j]);
- for (i = 0; i < k; i++)
- printf(" bmControls(%2u) 0x%02x\n", i, buf[12+j+i]);
- if (buf[12+j] & 1)
- printf(" Enable Processing\n");
- printf(" iExtension %5u %s\n",
- buf[12+j+k], term);
- dump_junk(buf, " ", 13+j+k);
- break;
- case USB_AUDIO_CLASS_2:
- j = buf[6];
- chnames = get_dev_string(dev, buf[13+j]);
- term = get_dev_string(dev, buf[15+j]);
- chcfg = buf[9+j] | (buf[10+j] << 8) | (buf[11+j] << 16) | (buf[12+j] << 24);
- if (buf[0] < 16+j)
- printf(" Warning: Descriptor too short\n");
- printf(" bUnitID %5u\n"
- " wExtensionCode %5u\n"
- " bNrPins %5u\n",
- buf[3], buf[4] | (buf[5] << 8), buf[6]);
- for (i = 0; i < j; i++)
- printf(" baSourceID(%2u) %5u\n", i, buf[7+i]);
- printf(" bNrChannels %5u\n"
- " wChannelConfig %5u\n", buf[7+j], chcfg);
- for (i = 0; i < 12; i++)
- if ((chcfg >> i) & 1)
- printf(" %s\n", chconfig[i]);
- printf(" iChannelNames %5u %s\n"
- " bmControls 0x%02x\n", buf[13+j], chnames, buf[14+j]);
- dump_audio_bmcontrols(" ", buf[14+j], uac2_extension_unit_bmcontrols, protocol);
-
- printf(" iExtension %5u %s\n",
- buf[15+j], term);
- dump_junk(buf, " ", 16+j);
- break;
- } /* switch (protocol) */
-
+ case UAC_INTERFACE_SUBTYPE_EXTENSION_UNIT:
+ dump_audio_subtype(dev, "EXTENSION_UNIT", desc_audio_ac_extension_unit, buf, protocol, 4);
break;
- case 0x0a: /* CLOCK_SOURCE */
- printf ("(CLOCK_SOURCE)\n");
- if (protocol != USB_AUDIO_CLASS_2)
- printf(" Warning: CLOCK_SOURCE descriptors are illegal for UAC1\n");
-
- if (buf[0] < 8)
- printf(" Warning: Descriptor too short\n");
-
- printf(" bClockID %5u\n"
- " bmAttributes 0x%02x %s Clock %s\n",
- buf[3], buf[4], clock_source_attrs[buf[4] & 3],
- (buf[4] & 4) ? "(synced to SOF)" : "");
-
- printf(" bmControls 0x%02x\n", buf[5]);
- dump_audio_bmcontrols(" ", buf[5], uac2_clock_source_bmcontrols, protocol);
-
- term = get_dev_string(dev, buf[7]);
- printf(" bAssocTerminal %5u\n", buf[6]);
- printf(" iClockSource %5u %s\n", buf[7], term);
- dump_junk(buf, " ", 8);
+ case UAC_INTERFACE_SUBTYPE_CLOCK_SOURCE:
+ dump_audio_subtype(dev, "CLOCK_SOURCE", desc_audio_ac_clock_source, buf, protocol, 4);
break;
- case 0x0b: /* CLOCK_SELECTOR */
- printf("(CLOCK_SELECTOR)\n");
- if (protocol != USB_AUDIO_CLASS_2)
- printf(" Warning: CLOCK_SELECTOR descriptors are illegal for UAC1\n");
-
- if (buf[0] < 7+buf[4])
- printf(" Warning: Descriptor too short\n");
- term = get_dev_string(dev, buf[6+buf[4]]);
-
- printf(" bUnitID %5u\n"
- " bNrInPins %5u\n",
- buf[3], buf[4]);
- for (i = 0; i < buf[4]; i++)
- printf(" baCSourceID(%2u) %5u\n", i, buf[5+i]);
- printf(" bmControls 0x%02x\n", buf[5+buf[4]]);
- dump_audio_bmcontrols(" ", buf[5+buf[4]], uac2_clock_selector_bmcontrols, protocol);
-
- printf(" iClockSelector %5u %s\n",
- buf[6+buf[4]], term);
- dump_junk(buf, " ", 7+buf[4]);
+ case UAC_INTERFACE_SUBTYPE_CLOCK_SELECTOR:
+ dump_audio_subtype(dev, "CLOCK_SELECTOR", desc_audio_ac_clock_selector, buf, protocol, 4);
break;
- case 0x0c: /* CLOCK_MULTIPLIER */
- printf("(CLOCK_MULTIPLIER)\n");
- if (protocol != USB_AUDIO_CLASS_2)
- printf(" Warning: CLOCK_MULTIPLIER descriptors are illegal for UAC1\n");
-
- if (buf[0] < 7)
- printf(" Warning: Descriptor too short\n");
-
- printf(" bClockID %5u\n"
- " bCSourceID %5u\n",
- buf[3], buf[4]);
-
- printf(" bmControls 0x%02x\n", buf[5]);
- dump_audio_bmcontrols(" ", buf[5], uac2_clock_multiplier_bmcontrols, protocol);
-
- term = get_dev_string(dev, buf[6]);
- printf(" iClockMultiplier %5u %s\n", buf[6], term);
- dump_junk(buf, " ", 7);
+ case UAC_INTERFACE_SUBTYPE_CLOCK_MULTIPLIER:
+ dump_audio_subtype(dev, "CLOCK_MULTIPLIER", desc_audio_ac_clock_multiplier, buf, protocol, 4);
break;
- case 0x0d: /* SAMPLE_RATE_CONVERTER_UNIT */
- printf("(SAMPLE_RATE_CONVERTER_UNIT)\n");
- if (protocol != USB_AUDIO_CLASS_2)
- printf(" Warning: SAMPLE_RATE_CONVERTER_UNIT descriptors are illegal for UAC1\n");
-
- if (buf[0] < 8)
- printf(" Warning: Descriptor too short\n");
-
- term = get_dev_string(dev, buf[7]);
- printf(" bUnitID %5u\n"
- " bSourceID %5u\n"
- " bCSourceInID %5u\n"
- " bCSourceOutID %5u\n"
- " iSRC %5u %s\n",
- buf[3], buf[4], buf[5], buf[6], buf[7], term);
- dump_junk(buf, " ", 8);
+ case UAC_INTERFACE_SUBTYPE_SAMPLE_RATE_CONVERTER:
+ dump_audio_subtype(dev, "SAMPLING_RATE_CONVERTER", desc_audio_ac_clock_multiplier, buf, protocol, 4);
break;
- case 0xf0: /* EFFECT_UNIT - the real value is 0x07, see above for the reason for remapping */
- printf("(EFFECT_UNIT)\n");
+ case UAC_INTERFACE_SUBTYPE_EFFECT_UNIT:
+ dump_audio_subtype(dev, "EFFECT_UNIT", desc_audio_ac_effect_unit, buf, protocol, 4);
+ break;
- if (buf[0] < 16)
- printf(" Warning: Descriptor too short\n");
- k = (buf[0] - 16) / 4;
- term = get_dev_string(dev, buf[15+k*4]);
- printf(" bUnitID %5u\n"
- " wEffectType %5u\n"
- " bSourceID %5u\n",
- buf[3], buf[4] | (buf[5] << 8), buf[6]);
- for (i = 0; i < k; i++) {
- chcfg = buf[7+(4*i)] |
- buf[8+(4*i)] << 8 |
- buf[9+(4*i)] << 16 |
- buf[10+(4*i)] << 24;
- printf(" bmaControls(%2u) 0x%08x\n", i, chcfg);
- /* TODO: parse effect-specific controls */
- }
- printf(" iEffect %5u %s\n", buf[15+(k*4)], term);
- dump_junk(buf, " ", 16+(k*4));
+ case UAC_INTERFACE_SUBTYPE_POWER_DOMAIN:
+ dump_audio_subtype(dev, "POWER_DOMAIN", desc_audio_ac_power_domain, buf, protocol, 4);
break;
default:
dump_bytes(buf+3, buf[0]-3);
break;
}
-
- free(chnames);
- free(term);
}
-static const struct bmcontrol uac2_as_interface_bmcontrols[] = {
- { "Active Alternate Setting", 0 },
- { "Valid Alternate Setting", 1 },
- { NULL }
-};
static void dump_audiostreaming_interface(libusb_device_handle *dev, const unsigned char *buf, int protocol)
{
"IEC1937_MPEG-2_Layer1_LS", "IEC1937_MPEG-2_Layer2/3_LS" };
unsigned int i, j, fmttag;
const char *fmtptr = "undefined";
- char *name = NULL;
if (buf[1] != USB_DT_CS_INTERFACE)
printf(" Warning: Invalid descriptor\n");
buf[0], buf[1], buf[2]);
switch (buf[2]) {
case 0x01: /* AS_GENERAL */
- printf("(AS_GENERAL)\n");
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- if (buf[0] < 7)
- printf(" Warning: Descriptor too short\n");
- fmttag = buf[5] | (buf[6] << 8);
- if (fmttag <= 5)
- fmtptr = fmtItag[fmttag];
- else if (fmttag >= 0x1000 && fmttag <= 0x1002)
- fmtptr = fmtIItag[fmttag & 0xfff];
- else if (fmttag >= 0x2000 && fmttag <= 0x2006)
- fmtptr = fmtIIItag[fmttag & 0xfff];
- printf(" bTerminalLink %5u\n"
- " bDelay %5u frames\n"
- " wFormatTag %5u %s\n",
- buf[3], buf[4], fmttag, fmtptr);
- dump_junk(buf, " ", 7);
- break;
- case USB_AUDIO_CLASS_2:
- if (buf[0] < 16)
- printf(" Warning: Descriptor too short\n");
- printf(" bTerminalLink %5u\n"
- " bmControls 0x%02x\n",
- buf[3], buf[4]);
- dump_audio_bmcontrols(" ", buf[4], uac2_as_interface_bmcontrols, protocol);
-
- printf(" bFormatType %5u\n", buf[5]);
- fmttag = buf[6] | (buf[7] << 8) | (buf[8] << 16) | (buf[9] << 24);
- printf(" bmFormats 0x%08x\n", fmttag);
- for (i=0; i<5; i++)
- if ((fmttag >> i) & 1)
- printf(" %s\n", fmtItag[i+1]);
-
- j = buf[11] | (buf[12] << 8) | (buf[13] << 16) | (buf[14] << 24);
- printf(" bNrChannels %5u\n"
- " bmChannelConfig 0x%08x\n",
- buf[10], j);
- for (i = 0; i < 26; i++)
- if ((j >> i) & 1)
- printf(" %s\n", chconfig_uac2[i]);
-
- name = get_dev_string(dev, buf[15]);
- printf(" iChannelNames %5u %s\n", buf[15], name);
- dump_junk(buf, " ", 16);
- break;
- } /* switch (protocol) */
-
+ dump_audio_subtype(dev, "AS_GENERAL", desc_audio_as_interface, buf, protocol, 4);
break;
case 0x02: /* FORMAT_TYPE */
dump_bytes(buf+3, buf[0]-3);
break;
}
-
- free(name);
}
-static const struct bmcontrol uac2_audio_endpoint_bmcontrols[] = {
- { "Pitch", 0 },
- { "Data Overrun", 1 },
- { "Data Underrun", 2 },
- { NULL }
-};
-
-static void dump_audiostreaming_endpoint(const unsigned char *buf, int protocol)
+static void dump_audiostreaming_endpoint(libusb_device_handle *dev, const unsigned char *buf, int protocol)
{
- static const char * const lockdelunits[] = { "Undefined", "Milliseconds", "Decoded PCM samples", "Reserved" };
- unsigned int lckdelidx;
+ static const char * const subtype[] = { "invalid", "EP_GENERAL" };
if (buf[1] != USB_DT_CS_ENDPOINT)
printf(" Warning: Invalid descriptor\n");
- else if (buf[0] < ((protocol == USB_AUDIO_CLASS_1) ? 7 : 8))
- printf(" Warning: Descriptor too short\n");
- printf(" AudioControl Endpoint Descriptor:\n"
+
+ printf(" AudioStreaming Endpoint Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
- " bDescriptorSubtype %5u (%s)\n"
- " bmAttributes 0x%02x\n",
- buf[0], buf[1], buf[2], buf[2] == 1 ? "EP_GENERAL" : "invalid", buf[3]);
-
- switch (protocol) {
- case USB_AUDIO_CLASS_1:
- if (buf[3] & 1)
- printf(" Sampling Frequency\n");
- if (buf[3] & 2)
- printf(" Pitch\n");
- if (buf[3] & 128)
- printf(" MaxPacketsOnly\n");
- lckdelidx = buf[4];
- if (lckdelidx > 3)
- lckdelidx = 3;
- printf(" bLockDelayUnits %5u %s\n"
- " wLockDelay %5u %s\n",
- buf[4], lockdelunits[lckdelidx], buf[5] | (buf[6] << 8), lockdelunits[lckdelidx]);
- dump_junk(buf, " ", 7);
- break;
-
- case USB_AUDIO_CLASS_2:
- if (buf[3] & 128)
- printf(" MaxPacketsOnly\n");
-
- printf(" bmControls 0x%02x\n", buf[4]);
- dump_audio_bmcontrols(" ", buf[4], uac2_audio_endpoint_bmcontrols, protocol);
+ " bDescriptorSubtype %5u ",
+ buf[0], buf[1], buf[2]);
- lckdelidx = buf[5];
- if (lckdelidx > 3)
- lckdelidx = 3;
- printf(" bLockDelayUnits %5u %s\n"
- " wLockDelay %5u\n",
- buf[5], lockdelunits[lckdelidx], buf[6] | (buf[7] << 8));
- dump_junk(buf, " ", 8);
- break;
- } /* switch protocol */
+ dump_audio_subtype(dev, subtype[buf[2] == 1],
+ desc_audio_as_isochronous_audio_data_endpoint, buf, protocol, 5);
}
static void dump_midistreaming_interface(libusb_device_handle *dev, const unsigned char *buf)
printf(" Warning: Descriptor too short\n");
tlength = buf[5] | (buf[6] << 8);
printf(" bcdADC %2x.%02x\n"
- " wTotalLength %5u\n",
+ " wTotalLength 0x%04x\n",
buf[4], buf[3], tlength);
dump_junk(buf, " ", 7);
break;
* Video Class descriptor dump
*/
-static void dump_videocontrol_interface(libusb_device_handle *dev, const unsigned char *buf)
+static void dump_videocontrol_interface(libusb_device_handle *dev, const unsigned char *buf, int protocol)
{
static const char * const ctrlnames[] = {
"Brightness", "Contrast", "Hue", "Saturation", "Sharpness", "Gamma",
"White Balance Temperature", "White Balance Component", "Backlight Compensation",
"Gain", "Power Line Frequency", "Hue, Auto", "White Balance Temperature, Auto",
"White Balance Component, Auto", "Digital Multiplier", "Digital Multiplier Limit",
- "Analog Video Standard", "Analog Video Lock Status"
+ "Analog Video Standard", "Analog Video Lock Status", "Contrast, Auto"
};
static const char * const camctrlnames[] = {
"Scanning Mode", "Auto-Exposure Mode", "Auto-Exposure Priority",
"Focus (Relative)", "Iris (Absolute)", "Iris (Relative)", "Zoom (Absolute)",
"Zoom (Relative)", "PanTilt (Absolute)", "PanTilt (Relative)",
"Roll (Absolute)", "Roll (Relative)", "Reserved", "Reserved", "Focus, Auto",
- "Privacy"
+ "Privacy", "Focus, Simple", "Window", "Region of Interest"
+ };
+ static const char * const enctrlnames[] = {
+ "Select Layer", "Profile and Toolset", "Video Resolution", "Minimum Frame Interval",
+ "Slice Mode", "Rate Control Mode", "Average Bit Rate", "CPB Size", "Peak Bit Rate",
+ "Quantization Parameter", "Synchronization and Long-Term Reference Frame",
+ "Long-Term Buffer", "Picture Long-Term Reference", "LTR Validation",
+ "Level IDC", "SEI Message", "QP Range", "Priority ID", "Start or Stop Layer/View",
+ "Error Resiliency"
};
static const char * const stdnames[] = {
"None", "NTSC - 525/60", "PAL - 625/50", "SECAM - 625/50",
printf(" Warning: Descriptor too short\n");
freq = buf[7] | (buf[8] << 8) | (buf[9] << 16) | (buf[10] << 24);
printf(" bcdUVC %2x.%02x\n"
- " wTotalLength %5u\n"
+ " wTotalLength 0x%04x\n"
" dwClockFrequency %5u.%06uMHz\n"
" bInCollection %5u\n",
buf[4], buf[3], buf[5] | (buf[6] << 8), freq / 1000000,
for (i = 0; i < 3 && i < buf[14]; i++)
ctrls = (ctrls << 8) | buf[8+n-i-1];
printf(" bmControls 0x%08x\n", ctrls);
- for (i = 0; i < 19; i++)
- if ((ctrls >> i) & 1)
- printf(" %s\n", camctrlnames[i]);
+ if (protocol == USB_VIDEO_PROTOCOL_15) {
+ for (i = 0; i < 22; i++)
+ if ((ctrls >> i) & 1)
+ printf(" %s\n", camctrlnames[i]);
+ }
+ else {
+ for (i = 0; i < 19; i++)
+ if ((ctrls >> i) & 1)
+ printf(" %s\n", camctrlnames[i]);
+ }
}
dump_junk(buf, " ", 8+n);
break;
printf("(OUTPUT_TERMINAL)\n");
term = get_dev_string(dev, buf[8]);
termt = buf[4] | (buf[5] << 8);
- get_audioterminal_string(termts, sizeof(termts), termt);
+ get_videoterminal_string(termts, sizeof(termts), termt);
if (buf[0] < 9)
printf(" Warning: Descriptor too short\n");
printf(" bTerminalID %5u\n"
for (i = 0; i < 3 && i < n; i++)
ctrls = (ctrls << 8) | buf[8+n-i-1];
printf(" bmControls 0x%08x\n", ctrls);
- for (i = 0; i < 18; i++)
- if ((ctrls >> i) & 1)
- printf(" %s\n", ctrlnames[i]);
+ if (protocol == USB_VIDEO_PROTOCOL_15) {
+ for (i = 0; i < 19; i++)
+ if ((ctrls >> i) & 1)
+ printf(" %s\n", ctrlnames[i]);
+ }
+ else {
+ for (i = 0; i < 18; i++)
+ if ((ctrls >> i) & 1)
+ printf(" %s\n", ctrlnames[i]);
+ }
stds = buf[9+n];
printf(" iProcessing %5u %s\n"
- " bmVideoStandards 0x%2x\n", buf[8+n], term, stds);
+ " bmVideoStandards 0x%02x\n", buf[8+n], term, stds);
for (i = 0; i < 6; i++)
if ((stds >> i) & 1)
printf(" %s\n", stdnames[i]);
printf(" Warning: Descriptor too short\n");
printf(" bUnitID %5u\n"
" guidExtensionCode %s\n"
- " bNumControl %5u\n"
- " bNrPins %5u\n",
+ " bNumControls %5u\n"
+ " bNrInPins %5u\n",
buf[3], get_guid(&buf[4]), buf[20], buf[21]);
for (i = 0; i < p; i++)
printf(" baSourceID(%2u) %5u\n", i, buf[22+i]);
dump_junk(buf, " ", 24+p+n);
break;
+ case 0x07: /* ENCODING UNIT */
+ printf("(ENCODING UNIT)\n");
+ term = get_dev_string(dev, buf[5]);
+ if (buf[0] < 13)
+ printf(" Warning: Descriptor too short\n");
+ printf(" bUnitID %5u\n"
+ " bSourceID %5u\n"
+ " iEncoding %5u %s\n"
+ " bControlSize %5u\n",
+ buf[3], buf[4], buf[5], term, buf[6]);
+ ctrls = 0;
+ for (i = 0; i < 3; i++)
+ ctrls = (ctrls << 8) | buf[9-i];
+ printf(" bmControls 0x%08x\n", ctrls);
+ for (i = 0; i < 20; i++)
+ if ((ctrls >> i) & 1)
+ printf(" %s\n", enctrlnames[i]);
+ for (i = 0; i< 3; i++)
+ ctrls = (ctrls << 8) | buf[12-i];
+ printf(" bmControlsRuntime 0x%08x\n", ctrls);
+ for (i = 0; i < 20; i++)
+ if ((ctrls >> i) & 1)
+ printf(" %s\n", enctrlnames[i]);
+ break;
+
default:
printf("(unknown)\n"
" Invalid desc subtype:");
if (buf[0] < 13+p*n)
printf(" Warning: Descriptor too short\n");
printf(" bNumFormats %5u\n"
- " wTotalLength %5u\n"
+ " wTotalLength 0x%04x\n"
" bEndPointAddress %5u\n"
" bmInfo %5u\n"
" bTerminalLink %5u\n"
for (i = 0; i < p; i++)
printf(
" bmaControls(%2u) %5u\n",
- i, buf[13+p*n]);
+ i, buf[13+i*n]);
dump_junk(buf, " ", 13+p*n);
break;
if (buf[0] < 9+p*n)
printf(" Warning: Descriptor too short\n");
printf(" bNumFormats %5u\n"
- " wTotalLength %5u\n"
+ " wTotalLength 0x%04x\n"
" bEndpointAddress %5u\n"
" bTerminalLink %5u\n"
" bControlSize %5u\n",
for (i = 0; i < p; i++)
printf(
" bmaControls(%2u) %5u\n",
- i, buf[9+p*n]);
+ i, buf[9+i*n]);
dump_junk(buf, " ", 9+p*n);
break;
" wHeight(%2u) %5u\n",
i, buf[5+4*i] | (buf[6+4*i] << 8),
i, buf[7+4*i] | (buf[8+4*i] << 8));
- printf(" bNumCompressionPatterns %3u\n", n);
+ printf(" bNumCompressionPatterns %3u\n", m);
for (i = 0; i < m; i++)
printf(" bCompression(%2u) %5u\n",
i, buf[6+4*n+i]);
printf("Random pattern of fields 1 and 2\n");
break;
}
- printf(" bCopyProtect %5u\n", buf[26]);
+ printf(" bCopyProtect %5u\n", buf[26]);
if (buf[2] == 0x10)
- printf(" bVariableSize %5u\n", buf[27]);
+ printf(" bVariableSize %5u\n", buf[27]);
dump_junk(buf, " ", len);
break;
printf("Random pattern of fields 1 and 2\n");
break;
}
- printf(" bCopyProtect %5u\n", buf[10]);
+ printf(" bCopyProtect %5u\n", buf[10]);
dump_junk(buf, " ", 11);
break;
dump_junk(buf, " ", 6);
break;
+ case 0x12: /* FORMAT_STREAM_BASED */
+ printf("(FORMAT_STREAM_BASED)\n");
+ if (buf[0] != 24)
+ printf(" Warning: Incorrect descriptor length\n");
+
+ printf(" bFormatIndex %5u\n"
+ " guidFormat %s\n"
+ " dwPacketLength %7u\n",
+ buf[3], get_guid(&buf[4]), buf[20]);
+ dump_junk(buf, " ", 24);
+ break;
+
default:
printf(" Invalid desc subtype:");
dump_bytes(buf+3, buf[0]-3);
if ((us & 0x0020))
fputs(" Auto baud rate change\n", stdout);
if ((us & 0x0040))
- fputs(" Auto parameter negotation made by CCID\n", stdout);
+ fputs(" Auto parameter negotiation made by CCID\n", stdout);
else if ((us & 0x0080))
fputs(" Auto PPS made by CCID\n", stdout);
else if ((us & (0x0040 | 0x0080)))
- fputs(" WARNING: conflicting negotation features\n", stdout);
+ fputs(" WARNING: conflicting negotiation features\n", stdout);
if ((us & 0x0100))
fputs(" CCID can set ICC in clock stop mode\n", stdout);
if ((us & 0x0200))
- fputs(" NAD value other than 0x00 accpeted\n", stdout);
+ fputs(" NAD value other than 0x00 accepted\n", stdout);
if ((us & 0x0400))
fputs(" Auto IFSD exchange\n", stdout);
}
}
+static void dump_printer_device(libusb_device_handle *dev,
+ const struct libusb_interface_descriptor *interface,
+ const unsigned char *buf)
+{
+ unsigned int i;
+ unsigned int n;
+
+ if (interface->bInterfaceProtocol != 0x04) /* IPP-over-USB */
+ return;
+
+ printf(" IPP Printer Descriptor:\n"
+ " bLength %5u\n"
+ " bDescriptorType %5u\n"
+ " bcdReleaseNumber %5u\n"
+ " bcdNumDescriptors %5u\n",
+ buf[0], buf[1], buf[2], buf[3]);
+
+ n = 4;
+ for (i = 0 ; i < buf[3] ; i++) {
+ switch (buf[n]) {
+ case 0x00: { /* Basic capabilities */
+ uint16_t caps = le16_to_cpu(*((uint16_t*)&buf[n+2]));
+ char *uuid = get_dev_string(dev, buf[n+5]);
+
+ printf(" iIPPVersionsSupported %5u\n", buf[n+4]);
+ printf(" iIPPPrinterUUID %5u %s\n", buf[n+5], uuid);
+ printf(" wBasicCapabilities 0x%04x ", caps);
+ if (caps & 0x01)
+ printf(" Print");
+ if (caps & 0x02)
+ printf(" Scan");
+ if (caps & 0x04)
+ printf(" Fax");
+ if (caps & 0x08)
+ printf(" Other");
+ if (caps & 0x10)
+ printf(" HTTP-over-USB");
+ if ((caps & 0x60) == 0x00)
+ printf(" No-Auth");
+ else if ((caps & 0x60) == 0x20)
+ printf(" Username-Auth");
+ else if ((caps & 0x60) == 0x40)
+ printf(" Reserved-Auth");
+ else if ((caps & 0x60) == 0x60)
+ printf(" Negotiable-Auth");
+ printf("\n");
+ break;
+ }
+ default:
+ /* Vendor Specific, Ignore for now. */
+ printf(" UnknownCapabilities %5u %5u\n", buf[n], buf[n+1]);
+ break;
+ }
+ n += 2 + buf[n+1];
+ }
+}
+
static void dump_hid_device(libusb_device_handle *dev,
const struct libusb_interface_descriptor *interface,
const unsigned char *buf)
if (buf[11] & 0x08)
printf("%s max datagram size\n", indent);
break;
+ case 0x1c: /* MBIM extended functional desc */
+ type = "MBIM Extended";
+ if (buf[0] != 8)
+ goto bad;
+ printf("%sCDC MBIM Extended:\n"
+ "%s bcdMBIMExtendedVersion %2x.%02x\n"
+ "%s bMaxOutstandingCommandMessages %3d\n"
+ "%s wMTU %5d\n",
+ indent,
+ indent, buf[4], buf[3],
+ indent, buf[5],
+ indent, buf[6] | (buf[7] << 8));
+ break;
default:
/* FIXME there are about a dozen more descriptor types */
printf("%sUNRECOGNIZED CDC: ", indent);
+ 2 /* bitmasks */ * HUB_STATUS_BYTELEN];
int i, ret, value;
unsigned int link_state;
- char *link_state_descriptions[] = {
- " U0",
- " U1",
- " U2",
- " suspend",
- " SS.disabled",
- " Rx.Detect",
- " SS.Inactive",
- " Polling",
- " Recovery",
- " Hot Reset",
- " Compliance",
- " Loopback",
+ const char * const link_state_descriptions[] = {
+ "U0",
+ "U1",
+ "U2",
+ "suspend",
+ "SS.disabled",
+ "Rx.Detect",
+ "SS.Inactive",
+ "Polling",
+ "Recovery",
+ "Hot Reset",
+ "Compliance",
+ "Loopback",
};
- /* USB 3.0 hubs have a slightly different descriptor */
- if (speed == 0x0300)
+ /* USB 3.x hubs have a slightly different descriptor */
+ if (speed >= 0x0300)
value = 0x2A;
else
value = 0x29;
LIBUSB_REQUEST_GET_DESCRIPTOR,
value << 8, 0,
buf, sizeof buf, CTRL_TIMEOUT);
- if (ret < 9 /* at least one port's bitmasks */) {
- if (ret >= 0)
- fprintf(stderr,
- "incomplete hub descriptor, %d bytes\n",
- ret);
+ if (ret < 0) {
/* Linux returns EHOSTUNREACH for suspended devices */
- else if (errno != EHOSTUNREACH)
- perror("can't get hub descriptor");
+ if (errno != EHOSTUNREACH)
+ fprintf(stderr, "can't get hub descriptor, %s (%s)\n",
+ libusb_error_name(ret), strerror(errno));
+ return;
+ }
+ if (ret < 9 /* at least one port's bitmasks */) {
+ fprintf(stderr,
+ "incomplete hub descriptor, %d bytes\n",
+ ret);
return;
}
dump_hub("", buf, tt_type);
(status[2] & 0x04) ? " C_SUSPEND" : "",
(status[2] & 0x02) ? " C_ENABLE" : "",
(status[2] & 0x01) ? " C_CONNECT" : "");
- printf("%s%s%s%s%s%s%s%s%s%s\n",
+ printf("%s%s%s%s%s%s%s%s%s%s%s\n",
(status[1] & 0x10) ? " indicator" : "",
(status[1] & 0x08) ? " test" : "",
(status[1] & 0x04) ? " highspeed" : "",
(status[1] & 0x02) ? " lowspeed" : "",
(status[1] & 0x01) ? " power" : "",
+ (status[0] & 0x20) ? " L1" : "",
(status[0] & 0x10) ? " RESET" : "",
(status[0] & 0x08) ? " oc" : "",
(status[0] & 0x04) ? " suspend" : "",
/* Link state is bits 8:5 */
if (link_state < (sizeof(link_state_descriptions) /
sizeof(*link_state_descriptions)))
- printf("%s", link_state_descriptions[link_state]);
+ printf(" %s", link_state_descriptions[link_state]);
printf("%s%s%s%s\n",
(status[0] & 0x10) ? " RESET" : "",
(status[0] & 0x08) ? " oc" : "",
buf[0], buf[1], buf[2], wide);
if (!(wide & 0x02))
printf(" (Missing must-be-set LPM bit!)\n");
- else
- printf(" Link Power Management (LPM)"
+ else if (!(wide & 0x04))
+ printf(" HIRD Link Power Management (LPM)"
+ " Supported\n");
+ else {
+ printf(" BESL Link Power Management (LPM)"
" Supported\n");
+ if (wide & 0x08)
+ printf(" BESL value %5u us \n", wide & 0xf00);
+ if (wide & 0x10)
+ printf(" Deep BESL value %5u us \n",
+ wide & 0xf000);
+ }
}
static void dump_ss_device_capability_desc(unsigned char *buf)
{
if (buf[0] < 10) {
- printf(" Bad SuperSpeed USB Device Capability descriptor.\n");
+ fprintf(stderr, " Bad SuperSpeed USB Device Capability descriptor.\n");
return;
}
printf(" SuperSpeed USB Device Capability:\n"
printf(" bU2DevExitLat %8u micro seconds\n", buf[8] + (buf[9] << 8));
}
+static void dump_ssp_device_capability_desc(unsigned char *buf)
+{
+ int i;
+ unsigned int bm_attr, ss_attr;
+ char bitrate_prefix[] = " KMG";
+
+ if (buf[0] < 12) {
+ fprintf(stderr, " Bad SuperSpeedPlus USB Device Capability descriptor.\n");
+ return;
+ }
+
+ bm_attr = convert_le_u32(buf + 4);
+ printf(" SuperSpeedPlus USB Device Capability:\n"
+ " bLength %5u\n"
+ " bDescriptorType %5u\n"
+ " bDevCapabilityType %5u\n"
+ " bmAttributes 0x%08x\n",
+ buf[0], buf[1], buf[2], bm_attr);
+
+ printf(" Sublink Speed Attribute count %u\n", buf[4] & 0x1f);
+ printf(" Sublink Speed ID count %u\n", (bm_attr >> 5) & 0xf);
+ printf(" wFunctionalitySupport 0x%02x%02x\n", buf[9], buf[8]);
+
+ for (i = 0; i <= (buf[4] & 0x1f); i++) {
+ ss_attr = convert_le_u32(buf + 12 + (i * 4));
+ printf(" bmSublinkSpeedAttr[%u] 0x%08x\n", i, ss_attr);
+ printf(" Speed Attribute ID: %u %u%cb/s %s %s SuperSpeed%s\n",
+ ss_attr & 0x0f,
+ ss_attr >> 16,
+ (bitrate_prefix[((ss_attr >> 4) & 0x3)]),
+ (ss_attr & 0x40)? "Asymmetric" : "Symmetric",
+ (ss_attr & 0x80)? "TX" : "RX",
+ (ss_attr & 0x4000)? "Plus": "" );
+ }
+}
+
static void dump_container_id_device_capability_desc(unsigned char *buf)
{
if (buf[0] < 20) {
- printf(" Bad Container ID Device Capability descriptor.\n");
+ fprintf(stderr, " Bad Container ID Device Capability descriptor.\n");
return;
}
printf(" Container ID Device Capability:\n"
get_guid(&buf[4]));
}
+static char *get_webusb_url(libusb_device_handle *fd, uint8_t vendor_req, uint8_t id)
+{
+ unsigned char url_buf[255];
+ char *scheme;
+ char *url, *chr;
+ unsigned char i;
+ int ret;
+
+ ret = usb_control_msg(fd,
+ LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR,
+ vendor_req, id, WEBUSB_GET_URL,
+ url_buf, sizeof(url_buf), CTRL_TIMEOUT);
+ if (ret <= 0)
+ return strdup("");
+ else if (url_buf[0] <= 3 || url_buf[1] != USB_DT_WEBUSB_URL || ret != url_buf[0])
+ return strdup("");
+
+ switch (url_buf[2]) {
+ case 0:
+ scheme = "http://";
+ break;
+ case 1:
+ scheme = "https://";
+ break;
+ case 255:
+ scheme = "";
+ break;
+ default:
+ fprintf(stderr, "Bad URL scheme.\n");
+ return strdup("");
+ }
+ url = malloc(strlen(scheme) + (url_buf[0] - 3) + 1);
+ if (!url)
+ return strdup("");
+ strcpy(url, scheme);
+ chr = url + strlen(scheme);
+ for (i = 3; i < url_buf[0]; i++)
+ /* crude UTF-8 to ASCII conversion */
+ if (url_buf[i] < 0x80)
+ *chr++ = url_buf[i];
+ *chr = '\0';
+
+ return url;
+}
+
+static void dump_platform_device_capability_desc(libusb_device_handle *fd, unsigned char *buf)
+{
+ unsigned char desc_len = buf[0];
+ unsigned char cap_data_len = desc_len - 20;
+ unsigned char i;
+ const char *guid;
+ if (desc_len < 20) {
+ fprintf(stderr, " Bad Platform Device Capability descriptor.\n");
+ return;
+ }
+ printf(" Platform Device Capability:\n"
+ " bLength %5u\n"
+ " bDescriptorType %5u\n"
+ " bDevCapabilityType %5u\n"
+ " bReserved %5u\n",
+ buf[0], buf[1], buf[2], buf[3]);
+ guid = get_guid(&buf[4]);
+ printf(" PlatformCapabilityUUID %s\n", guid);
+
+ if (!strcmp(WEBUSB_GUID , guid) && desc_len == 24) {
+ /* WebUSB platform descriptor */
+ char *url = get_webusb_url(fd, buf[22], buf[23]);
+ printf(" WebUSB:\n"
+ " bcdVersion %2x.%02x\n"
+ " bVendorCode %5u\n"
+ " iLandingPage %5u %s\n",
+ buf[21], buf[20], buf[22], buf[23], url);
+ free(url);
+ return;
+ }
+
+ for (i = 0; i < cap_data_len; i++) {
+ printf(" CapabilityData[%u] 0x%02x\n", i, buf[20 + i]);
+ }
+}
+
+static void dump_billboard_device_capability_desc(libusb_device_handle *dev, unsigned char *buf)
+{
+ char *url, *alt_mode_str;
+ int w_vconn_power, alt_mode, i, svid, state;
+ const char *vconn;
+ unsigned char *bmConfigured;
+
+ if (buf[0] < 48) {
+ fprintf(stderr, " Bad Billboard Capability descriptor.\n");
+ return;
+ }
+
+ if (buf[4] > BILLBOARD_MAX_NUM_ALT_MODE) {
+ fprintf(stderr, " Invalid value for bNumberOfAlternateModes.\n");
+ return;
+ }
+
+ if (buf[0] < (44 + buf[4] * 4)) {
+ fprintf(stderr, " bLength does not match with bNumberOfAlternateModes.\n");
+ return;
+ }
+
+ url = get_dev_string(dev, buf[3]);
+ w_vconn_power = convert_le_u16(buf+6);
+ if (w_vconn_power & (1 << 15)) {
+ vconn = "VCONN power not required";
+ } else if (w_vconn_power < 7) {
+ vconn = vconn_power[w_vconn_power & 0x7];
+ } else {
+ vconn = "reserved";
+ }
+ printf(" Billboard Capability:\n"
+ " bLength %5u\n"
+ " bDescriptorType %5u\n"
+ " bDevCapabilityType %5u\n"
+ " iAddtionalInfoURL %5u %s\n"
+ " bNumberOfAlternateModes %5u\n"
+ " bPreferredAlternateMode %5u\n"
+ " VCONN Power %5u %s\n",
+ buf[0], buf[1], buf[2],
+ buf[3], url,
+ buf[4], buf[5],
+ w_vconn_power, vconn);
+
+ bmConfigured = &buf[8];
+
+ printf(" bmConfigured ");
+ dump_bytes(bmConfigured, 32);
+
+ printf(
+ " bcdVersion %2x.%02x\n"
+ " bAdditionalFailureInfo %5u\n"
+ " bReserved %5u\n",
+ (buf[41] == 0) ? 1 : buf[41], buf[40],
+ buf[42], buf[43]);
+
+ printf(" Alternate Modes supported by Device Container:\n");
+ i = 44; /* Alternate mode 0 starts at index 44 */
+ for (alt_mode = 0; alt_mode < buf[4]; alt_mode++) {
+ svid = convert_le_u16(buf+i);
+ alt_mode_str = get_dev_string(dev, buf[i+3]);
+ state = ((bmConfigured[alt_mode >> 2]) >> ((alt_mode & 0x3) << 1)) & 0x3;
+ printf(
+ " Alternate Mode %d : %s\n"
+ " wSVID[%d] 0x%04X\n"
+ " bAlternateMode[%d] %5u\n"
+ " iAlternateModeString[%d] %5u %s\n",
+ alt_mode, alt_mode_state[state],
+ alt_mode, svid,
+ alt_mode, buf[i+2],
+ alt_mode, buf[i+3], alt_mode_str);
+ free(alt_mode_str);
+ i += 4;
+ }
+
+ free (url);
+}
+
+static void dump_billboard_alt_mode_capability_desc(libusb_device_handle *dev, unsigned char *buf)
+{
+ if (buf[0] != 8) {
+ fprintf(stderr, " Bad Billboard Alternate Mode Capability descriptor.\n");
+ return;
+ }
+
+ printf(" Billboard Alternate Mode Capability:\n"
+ " bLength %5u\n"
+ " bDescriptorType %5u\n"
+ " bDevCapabilityType %5u\n"
+ " bIndex %5u\n"
+ " dwAlternateModeVdo 0x%02X%02X%02X%02X\n",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+}
+
static void dump_bos_descriptor(libusb_device_handle *fd)
{
- /* Total for all known BOS descriptors is 43 bytes:
- * 6 bytes for Wireless USB, 7 bytes for USB 2.0 extension,
- * 10 bytes for SuperSpeed, 20 bytes for Container ID.
+ /* Total length of BOS descriptors varies.
+ * Read first static 5 bytes which include the total length before
+ * allocating and reading the full BOS
*/
- unsigned char bos_desc[43];
+
+ unsigned char bos_desc_static[5];
+ unsigned char *bos_desc;
unsigned int bos_desc_size;
int size, ret;
unsigned char *buf;
LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE,
LIBUSB_REQUEST_GET_DESCRIPTOR,
USB_DT_BOS << 8, 0,
- bos_desc, 5, CTRL_TIMEOUT);
+ bos_desc_static, 5, CTRL_TIMEOUT);
if (ret <= 0)
return;
- else if (bos_desc[0] != 5 || bos_desc[1] != USB_DT_BOS)
+ else if (bos_desc_static[0] != 5 || bos_desc_static[1] != USB_DT_BOS)
return;
- bos_desc_size = bos_desc[2] + (bos_desc[3] << 8);
+ bos_desc_size = bos_desc_static[2] + (bos_desc_static[3] << 8);
printf("Binary Object Store Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
- " wTotalLength %5u\n"
+ " wTotalLength 0x%04x\n"
" bNumDeviceCaps %5u\n",
- bos_desc[0], bos_desc[1],
- bos_desc_size, bos_desc[4]);
+ bos_desc_static[0], bos_desc_static[1],
+ bos_desc_size, bos_desc_static[4]);
if (bos_desc_size <= 5) {
- if (bos_desc[4] > 0)
+ if (bos_desc_static[4] > 0)
fprintf(stderr, "Couldn't get "
"device capability descriptors\n");
return;
}
- if (bos_desc_size > sizeof bos_desc) {
- fprintf(stderr, "FIXME: alloc bigger buffer for "
- "device capability descriptors\n");
+ bos_desc = malloc(bos_desc_size);
+ if (!bos_desc)
return;
- }
+ memset(bos_desc, 0, bos_desc_size);
ret = usb_control_msg(fd,
LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE,
bos_desc, bos_desc_size, CTRL_TIMEOUT);
if (ret < 0) {
fprintf(stderr, "Couldn't get device capability descriptors\n");
- return;
+ goto out;
}
size = bos_desc_size - 5;
while (size >= 3) {
if (buf[0] < 3) {
printf("buf[0] = %u\n", buf[0]);
- return;
+ goto out;
}
switch (buf[2]) {
case USB_DC_WIRELESS_USB:
case USB_DC_SUPERSPEED:
dump_ss_device_capability_desc(buf);
break;
+ case USB_DC_SUPERSPEEDPLUS:
+ dump_ssp_device_capability_desc(buf);
+ break;
case USB_DC_CONTAINER_ID:
dump_container_id_device_capability_desc(buf);
break;
+ case USB_DC_PLATFORM:
+ dump_platform_device_capability_desc(fd, buf);
+ break;
+ case USB_DC_BILLBOARD:
+ dump_billboard_device_capability_desc(fd, buf);
+ break;
+ case USB_DC_BILLBOARD_ALT_MODE:
+ dump_billboard_alt_mode_capability_desc(fd, buf);
+ break;
+ case USB_DC_CONFIGURATION_SUMMARY:
+ printf(" Configuration Summary Device Capability:\n");
+ desc_dump(fd, desc_usb3_dc_configuration_summary,
+ buf, DESC_BUF_LEN_FROM_BUF, 2);
+ break;
default:
printf(" ** UNRECOGNIZED: ");
dump_bytes(buf, buf[0]);
size -= buf[0];
buf += buf[0];
}
+out:
+ free(bos_desc);
}
static void dumpdev(libusb_device *dev)
}
libusb_get_device_descriptor(dev, &desc);
- dump_device(udev, &desc);
+ dump_device(dev, &desc);
if (desc.bcdUSB == 0x0250)
wireless = do_wireless(udev);
if (desc.bNumConfigurations) {
"descriptor %d, some information will "
"be missing\n", i);
} else {
- dump_config(udev, config);
+ dump_config(udev, config, desc.bcdUSB);
libusb_free_config_descriptor(config);
}
}
/* ---------------------------------------------------------------------- */
+/*
+ * Attempt to get friendly vendor and product names from the udev hwdb. If
+ * either or both are not present, instead populate those from the device's
+ * own string descriptors.
+ */
+static void get_vendor_product_with_fallback(char *vendor, int vendor_len,
+ char *product, int product_len,
+ libusb_device *dev)
+{
+ struct libusb_device_descriptor desc;
+ char sysfs_name[PATH_MAX];
+ bool have_vendor, have_product;
+
+ libusb_get_device_descriptor(dev, &desc);
+
+ have_vendor = !!get_vendor_string(vendor, vendor_len, desc.idVendor);
+ have_product = !!get_product_string(product, product_len,
+ desc.idVendor, desc.idProduct);
+
+ if (have_vendor && have_product)
+ return;
+
+ if (get_sysfs_name(sysfs_name, sizeof(sysfs_name), dev) >= 0) {
+ if (!have_vendor)
+ read_sysfs_prop(vendor, vendor_len, sysfs_name,
+ "manufacturer");
+ if (!have_product)
+ read_sysfs_prop(product, product_len, sysfs_name,
+ "product");
+ }
+}
+
static int dump_one_device(libusb_context *ctx, const char *path)
{
libusb_device *dev;
return 1;
}
libusb_get_device_descriptor(dev, &desc);
- get_vendor_string(vendor, sizeof(vendor), desc.idVendor);
- get_product_string(product, sizeof(product), desc.idVendor, desc.idProduct);
+ get_vendor_product_with_fallback(vendor, sizeof(vendor),
+ product, sizeof(product), dev);
printf("Device: ID %04x:%04x %s %s\n", desc.idVendor,
desc.idProduct,
vendor,
(productid != -1 && productid != desc.idProduct))
continue;
status = 0;
- get_vendor_string(vendor, sizeof(vendor), desc.idVendor);
- get_product_string(product, sizeof(product),
- desc.idVendor, desc.idProduct);
+
+ get_vendor_product_with_fallback(vendor, sizeof(vendor),
+ product, sizeof(product), dev);
+
if (verblevel > 0)
printf("\n");
printf("Bus %03u Device %03u: ID %04x:%04x %s %s\n",
/* by default, print names as well as numbers */
- err = names_init(DATADIR "/usb.ids");
-#ifdef HAVE_LIBZ
- if (err != 0)
- err = names_init(DATADIR "/usb.ids.gz");
-#endif
- if (err != 0)
- fprintf(stderr, "%s: cannot open \"%s\", %s\n",
- argv[0],
- DATADIR "/usb.ids",
- strerror(err));
+ if (names_init() < 0)
+ fprintf(stderr, "unable to initialize usb spec");
+
status = 0;
if (treemode) {
- /* treemode requires at least verblevel 1 */
- verblevel += 1 - VERBLEVEL_DEFAULT;
status = lsusb_t();
names_exit();
return status;