USB Descriptor Viewer Workflow for HID and CDC

Use a USB descriptor viewer workflow to validate raw device, configuration, interface, endpoint, HID, CDC, string, BOS, and class-request evidence.

USB descriptor viewer, USB descriptors, HID, CDC, descriptor debugging, firmware

A USB descriptor viewer is useful only when it preserves the exact bytes the host received and connects them to enumeration, class requests, and endpoint traffic. A pretty tree can reveal obvious fields, but it can also hide a malformed length, stale descriptor revision, missing interface, or request that returned different bytes on the failing host.

Direct answer: capture the device from connection, inspect the decoded descriptor hierarchy, and validate each decoded field against raw bytes and the request that retrieved it. Check lengths and boundaries before interpreting class meaning. Then compare HID report layouts or CDC functional relationships with the class requests and endpoint transfers that follow configuration.

Bus Scope is designed to keep descriptor context, raw packet bytes, transfer status, filters, and saved .bscope sessions together. It can show USB evidence. It cannot prove how an operating system ranked an INF or how an application transformed a valid HID or serial event, so pair the trace with host logs when the bus contract is already correct.

What a USB descriptor viewer must show

The useful view is a hierarchy tied to original capture evidence:

Descriptor layer Fields that anchor diagnosis Failure it can expose
Device USB version, class tuple, EP0 size, VID, PID, bcdDevice, string indexes wrong identity or control assumptions
Configuration total length, interface count, attributes, power truncated or malformed tree
IAD first interface, count, function class incorrect composite grouping
Interface number, alternate setting, endpoint count, class tuple wrong driver identity
Class-specific HID, CDC, audio, video, DFU fields broken class contract
Endpoint address, direction, type, packet size, interval unusable transfer path
String language ID, index, UTF-16 data identity or retrieval inconsistency
BOS/capability capability type, platform UUID, nested length discovery or WinUSB/WebUSB mismatch

The viewer should let an engineer jump from a decoded field to raw bytes and then to the control transfer that returned the block. If those three views disagree, raw capture bytes and the request context are the diagnostic ground truth.

Start with the control request, not the label

Most descriptors are retrieved with a standard GET_DESCRIPTOR control request. Decode:

  • direction, request type, and recipient from bmRequestType;
  • GET_DESCRIPTOR in bRequest;
  • descriptor type and index in wValue;
  • language ID or interface context in wIndex, depending on descriptor type;
  • maximum requested length in wLength.

The response may legitimately be shorter than wLength. During enumeration, a host can request a small prefix first, learn a length, and request the full descriptor later. Do not flag every short response as truncation. Instead ask:

  1. How many bytes did the device declare?
  2. How many did the host request?
  3. How many were returned?
  4. Did the data stage complete normally?
  5. Did the host retry with a different length?

That sequence separates normal enumeration probes from firmware that ends a descriptor block early or stalls a valid request.

Validate descriptor boundaries before values

Every standard descriptor begins with bLength and bDescriptorType. For a configuration block, walk from offset zero by each descriptor's bLength:

next offset = current offset + bLength

The walk should remain inside the returned data and end at the declared configuration wTotalLength. Check that:

  • no bLength is zero;
  • every descriptor fits in the captured block;
  • known descriptor types have at least their required base length;
  • the final offset matches the expected boundary;
  • interface and endpoint counts agree with the parsed structure.

A wrong bLength can make every later field appear corrupt even if firmware source arrays look correct. A wrong wTotalLength can omit trailing interfaces or cause a host to request bytes that firmware does not provide. Fix the first boundary error before debating class-specific fields.

Read the device descriptor as identity and capability

The device descriptor establishes the identity used for later driver and cache behavior:

Field Diagnostic use
bcdUSB USB specification level claimed by the device
bDeviceClass/SubClass/Protocol device-level class or per-interface delegation
bMaxPacketSize0 default control endpoint packet size
idVendor / idProduct device identity
bcdDevice firmware or device release identity
string indexes references for manufacturer, product, and serial
bNumConfigurations number of configurations advertised

Record all of them in known-good and failing captures. A changed PID, serial, or release number may create a different OS device instance. A changed class tuple can alter compatible IDs and binding. Those are meaningful experimental differences, not metadata noise.

If the host cannot complete the device descriptor stage, use the broader USB enumeration failure guide before debugging HID or CDC.

Inspect configuration, interfaces, and alternate settings as one graph

An interface number identifies a function path; alternate settings provide mutually selectable endpoint layouts for that interface. bNumInterfaces counts interface numbers, not every alternate descriptor.

Build a map:

Interface Alternate Class Endpoints Intended function
0 0 HID interrupt IN 0x81 controls
1 0 CDC control interrupt IN 0x82 serial notifications
2 0 CDC data bulk OUT 0x03, bulk IN 0x83 serial data
3 0 vendor bulk OUT 0x04, bulk IN 0x84 diagnostics

Then verify endpoint addresses, directions, transfer types, maximum packet sizes, and intervals. Check class-specific descriptors in the correct interface context. If the same endpoint address appears in simultaneously active interfaces, or an interface declares two endpoints but only one descriptor exists, the host's later behavior may be a consequence of the malformed map.

For streaming devices with multiple alternate settings, continue with the USB alternate-setting bandwidth guide.

HID descriptor viewing requires the report descriptor too

The HID descriptor inside the configuration tree identifies HID class descriptors and advertises the report-descriptor length. The report descriptor itself is retrieved separately for the target interface. Validate:

  • the HID descriptor is located after the intended HID interface;
  • the advertised report length equals the complete returned report descriptor;
  • wIndex addresses the correct interface;
  • Report IDs, sizes, counts, usages, and logical ranges form valid layouts;
  • actual interrupt and control reports match those layouts.

A generic tree that stops at "HID descriptor: report length 73" has not finished the job. The report item stream and actual report bytes are the behavioral contract. The dedicated HID report descriptor guide shows how to build a bit-offset table.

CDC viewing means checking relationships

CDC ACM usually spans a communication interface and a data interface. Relevant descriptors may include:

  • CDC Header Functional Descriptor;
  • Call Management Functional Descriptor;
  • Abstract Control Management Functional Descriptor;
  • Union Functional Descriptor;
  • notification interrupt endpoint;
  • data-interface bulk IN and OUT endpoints.

The union descriptor's master and subordinate interface numbers must refer to the intended interfaces. If an IAD is present, its range should agree with the function layout. After descriptors, inspect class requests such as SET_LINE_CODING and SET_CONTROL_LINE_STATE, then data transfers.

Use a decision table:

Observation Next likely layer
CDC child never appears descriptor grouping or driver identity
child appears, class request stalls firmware request handler or interface routing
class setup succeeds, no bulk traffic application open state, DTR/RTS policy, endpoint queue
bulk OUT succeeds, no bulk IN firmware receive/response path
device resets after port open control-line-triggered reset or power/firmware fault

The USB serial COM port guide covers resets and bootloader identity changes after the port opens.

Decode endpoint fields in speed context

An endpoint descriptor does not stand alone. Interpret its maximum packet size and interval using the negotiated speed and transfer type. Bulk, interrupt, and isochronous endpoints have different scheduling and retry behavior.

For every endpoint, record:

  • endpoint address and direction;
  • transfer type from bmAttributes;
  • maximum packet size and any speed-specific transaction fields;
  • bInterval;
  • owning interface and alternate setting;
  • first successful and first failed transfer.

A viewer that lists wMaxPacketSize = 512 without speed and endpoint type omits the context needed for diagnosis. If descriptors look correct but a bulk path times out, use the USB endpoint STALL and timeout guide.

String descriptors can change identity

String descriptor index zero returns supported language IDs. Other indexes are requested in a language context. Validate:

  1. string index zero completes and lists intended language IDs;
  2. nonzero indexes are valid for the requested language;
  3. descriptor length is even and matches returned UTF-16 data;
  4. serial number is stable when firmware promises a stable identity;
  5. the host does not receive different values across resets.

A bad string can produce a warning, different device-instance behavior, or confusing support logs even when basic configuration succeeds. The USB string descriptor guide covers that path.

BOS and platform capabilities are nested structures

USB 2.01 and later capability discovery can involve a Binary Object Store (BOS) descriptor containing one or more device-capability descriptors. Validate outer and nested lengths before decoding platform UUIDs or vendor payloads.

For Microsoft OS 2.0 or WebUSB discovery, preserve:

  • BOS request and complete response;
  • capability type and UUID;
  • vendor code;
  • descriptor-set length or landing-page index where applicable;
  • subsequent vendor request;
  • complete returned descriptor set.

The BOS and Microsoft OS descriptor guide explains how those layers affect WinUSB discovery without confusing a bus result with final OS policy.

Compare raw bytes before and after a firmware change

Use the same host, port, cable, and test sequence when possible. Compare:

  • exact request order;
  • every descriptor response length;
  • raw device and configuration blocks;
  • HID report descriptor;
  • CDC functional descriptors;
  • BOS/platform descriptors;
  • selected configuration and alternate settings;
  • first class request and transfer that differs.

Do not use screenshots as the primary comparison artifact. Save raw sessions so reviewers can verify offsets and decode new fields later. A screenshot can illustrate the conclusion, but it cannot replace the evidence.

A repeatable USB descriptor viewer workflow

  1. Record host, controller path, device speed, firmware, VID, PID, and serial.
  2. Start capture before connection or reset.
  3. Follow endpoint-zero requests in chronological order.
  4. Validate device-descriptor identity and EP0 size.
  5. Validate configuration total length and descriptor boundaries.
  6. Map IADs, interface numbers, alternate settings, and endpoints.
  7. Decode class-specific descriptors in interface context.
  8. Retrieve and parse the complete HID report descriptor where applicable.
  9. Validate CDC functional relationships where applicable.
  10. Inspect BOS, string, and Microsoft OS descriptors when exposed.
  11. Follow the first class requests after configuration.
  12. Compare endpoint traffic with the declared map.
  13. Save a bounded .bscope session and a concise evidence table.

Use Bus Scope platform capture before interpreting an empty trace. USBPcap controller choice and Linux usbmon bus choice must match the physical device path.

QA questions

What should a USB descriptor viewer show besides decoded fields?

It should preserve raw bytes, original control-request context, transfer status, descriptor offsets, hierarchy, interface ownership, and the endpoint traffic that follows. A decoded tree alone is not enough for malformed-length or stale-revision cases.

Why does the host request a descriptor twice with different lengths?

Hosts often request a short prefix to learn a descriptor's size, then request the full block. Compare declared, requested, and returned lengths before calling the first short response a failure.

Is a valid configuration descriptor enough to prove HID or CDC works?

No. HID depends on the separately retrieved report descriptor and matching reports. CDC depends on coherent functional descriptors, class requests, control-line state, and bulk endpoint behavior.

Can the USB descriptor viewer prove Windows chose the wrong INF?

It can prove identity descriptors, interface classes, Microsoft OS descriptor traffic, and USB request results. Windows setup and device logs are still needed to prove INF ranking and binding policy.

Why keep both decoded and raw views?

Decoded fields accelerate review; raw bytes settle length, offset, endianness, and decoder disagreements. A reliable diagnosis uses both and ties them to the exact transfer.

Final diagnosis

A USB descriptor viewer should turn an opaque driver error into a verifiable contract: exact bytes, valid boundaries, coherent class relationships, and matching requests and endpoint traffic. Validate structure first, class meaning second, and host policy last. That order prevents a malformed descriptor from being disguised as a driver problem and prevents a valid bus contract from being blamed for an application-layer failure.

<!-- multilingual-related-reading:start -->

Related guides

Continue with the same-language pages below. They cover adjacent stages without changing the canonical owner of this topic:

<!-- multilingual-related-reading:end -->