Skip to main content

usb-kernel-debug

Use when the Linux end of a USB link must explain itself — enumeration failures, "device descriptor read error", control STALLs, missing or short transfers, ISO dropouts, port-reset storms, xHCI errors. usbmon URB capture to pcapng, kernel dynamic debug on host or gadget.

Informações da origem

Repositório
hathach/agentrc
Última atividade na origem
7 de outubro de 2026 às 06:09
Idioma detectado do SKILL.md
inglês
Estrelas
1
Forks
2

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
3 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
usb-kernel-debug
description
Use when the Linux end of a USB link must explain itself — enumeration failures, "device descriptor read error", control STALLs, missing or short transfers, ISO dropouts, port-reset storms, xHCI errors. usbmon URB capture to pcapng, kernel dynamic debug on host or gadget.
# usb-kernel-debug — what the Linux side of the link saw Two kernel facilities, by the role Linux plays in the link: | Linux is the … | usbmon URB capture (`usbcap.py`) | dynamic debug (`usb_dyndbg.sh`) | |----------------|----------------------------------|------------------------------------------| | PC host | yes — what the host exchanged | yes — why the host driver acted | | gadget peer | no — a UDC has no usbmon | yes — `dwc2`/`dwc3` + `udc_core` + `libcomposite` | Neither sees inside the device's firmware or the wire itself: pair this with a wire sniffer (the `usb-sniffer` skill, if installed) and target-side debugging (GDB on the MCU) for those. ## usbmon — capture (host role) `usbmon` records host-side **URBs** — control / bulk / interrupt / isochronous transfers, descriptors, class requests, STALLs, short packets — i.e. exactly what the host exchanged with a device. Requires `usbmon` loaded and `/dev/usbmon*` readable by your user (`wireshark` group); the script says so when `tshark` cannot open the interface — a fresh group membership needs a new login or `sg wireshark -c '...'`. Never `sudo` it: the script refuses root, whose `dumpcap` drops its capabilities and then cannot write an outfile under a mode-0700 home. Reading a finished `.pcapng` needs no group. ```bash S=<skill dir>/scripts $S/usbcap.py 1a86:55d4 10 # the bus of that plugged-in device, 10 s; --help for selectors and defaults $S/usbcap.py 3 10 cap.pcapng --snaplen 64 # bus 3, URB headers only ``` Capture the device's own bus. A selector matching devices on several buses (`1a86:` with two adapters plugged in) is refused with the matches listed: pass the bus, or `auto` when you really want every bus. Full payloads by default; `--snaplen 64` keeps only the 64-byte usbmon record (URB type, endpoint, status, lengths) for long or high-throughput captures, and `128` adds the first 64 bytes of payload, enough for setup packets and descriptor heads. An existing output file is refused, never overwritten. A capture with no packets exits 1 and keeps the file: wrong bus, or nothing happened. To catch enumeration, start the capture, then replug or reset the device. ## usbmon — analyze ```bash tshark -r cap.pcapng # one line per URB tshark -r cap.pcapng -V | less # full dissection (descriptors decoded) tshark -r cap.pcapng -Y 'usb.device_address==26' # filter to one device ``` ### Filter (`-Y '<expr>'`) | Goal | Expression | |--------------------------------------------------|-------------------------------------------------------------| | One device / endpoint | `usb.device_address==26` / `usb.endpoint_address==0x81` | | IN (to host) / OUT (from host) | `usb.endpoint_address.direction==1` / `==0` | | Submit / Complete event | `usb.urb_type=='S'` / `=='C'` (char literal: single quotes) | | Control / bulk / interrupt / iso | `usb.transfer_type==2` / `3` / `1` / `0` | | Only transfers carrying data | `usb.data_len>0` | | GET_DESCRIPTOR / SET_ADDRESS / SET_CONFIGURATION | `usb.setup.bRequest==6` / `5` / `9` | | SET_INTERFACE / CLEAR_FEATURE (clear-halt) | `usb.setup.bRequest==11` / `1` | | Descriptor type DEVICE/CONFIG/STRING/HID-report | `usb.bDescriptorType==1` / `2` / `3` / `0x22` | | Class / vendor requests | `usb.bmRequestType.type!=0` | | STALLs / errors | `usb.urb_status!=0 && usb.urb_status!=-115` | Combine with `&&` — e.g. one endpoint's data: `usb.endpoint_address==0x02 && usb.data_len>0`. **`usb.urb_status` codes** (errno): `0` success · `-115` `-EINPROGRESS` (every Submit) · `-71` `-EPROTO` (transaction error — device answered wrong or didn't service in time, after the HC's retries) · `-32` `-EPIPE` (STALL) · `-110` `-ETIMEDOUT` · `-75` `-EOVERFLOW` (babble). A **control** transfer completing `-71` ≠ a STALL: the device mis-/under-served it (e.g. EP0 starved under load), not a deliberate STALL from its control handler. **Decoding class requests:** the plain `-e usb.setup.bRequest` field is often blank for class requests (CDC `SET_LINE_CODING` 0x20 / `SET_CONTROL_LINE_STATE` 0x22, `bmRequestType==0x21`) — Wireshark routes them to class fields. Use `-V` on the Submit frame to get the request name + `wValue` (for `SET_CONTROL_LINE_STATE`, `wValue` bit0=DTR, bit1=RTS). **Hard limit — usbmon is URB-level, not wire-level.** It cannot show data toggle (DATA0/DATA1) or NAKs. A device-side stall and a toggle desync both look identical: Submits on an endpoint with no Completes. To tell them apart, pair usbmon with a wire sniffer, or with GDB on the device: read the endpoint control register (response/toggle bits) and the device stack's endpoint state at the moment of the hang. ## Dynamic debug (either role) Kernel **dynamic debug** shows the Linux side's *reasoning* that capture can't: port resets and their causes, enumeration retries, address (re)assignment, EP halts, xHCI ring/command errors. `scripts/usb_dyndbg.sh` (`--help` lists the allowlisted modules; run with `sudo`) flips the print flag for those USB modules only: ```bash sudo $S/usb_dyndbg.sh on usbcore xhci_hcd # then reproduce while following `sudo dmesg -w` sudo $S/usb_dyndbg.sh status # what is switched on right now sudo $S/usb_dyndbg.sh off usbcore xhci_hcd # ALWAYS: left on, it floods the log and skews timing ``` `on`/`off` read the flags back and say how many of the module's print sites took (`N of N sites print`); a module that is not loaded, or built without dynamic debug, is an error rather than a quiet success. Module choice by role: on a host, `usbcore` for enumeration/hub logic plus the controller driver `lsusb -t` shows for the bus; on a gadget peer, `dwc2` (or `dwc3`) + `udc_core` + `libcomposite`, run on the peer itself (the script is self-contained, copy it over). Best for **re-enumerates / enumeration stalls / port-reset storms**, where usbmon shows the resets but not the host's reason. ## Reading a capture Candidate causes and the check that tells them apart, not verdicts: - **Not recognized / re-enumerates:** is `GET DESCRIPTOR (DEVICE)` answered, `bMaxPacketSize0` sane? Repeated SET_ADDRESS or resets: a device too slow to respond is one candidate, a marginal link or power another; dynamic debug on `usbcore` and the controller driver gives the host's own reset reason. - **Enumeration stalls:** find the last good control transfer; the next request, often CONFIG, a string, or the first class request, is the first suspect: compare the device's answer to it (`-V`) with what it should return, or look at the wire when there is no answer at all. - **Control STALL:** a control URB completing `-32` (`-EPIPE`) is a STALL from the device's control handler, usually an unhandled `bRequest` (decode it with `-V`). `-71` is not a STALL, see the errno list. - **Bulk / interrupt missing or short:** on the endpoint, do Submits get Completes? An unexpected short (`usb.data_len < wMaxPacketSize`) suggests a length bug; no completions can be the device never writing, a stalled endpoint or a toggle desync, which usbmon cannot separate. - **A CDC read hangs with the IN endpoint idle:** check EP0 first. Did `SET_CONTROL_LINE_STATE` complete `0` or fail `-71`? If it failed, the device never saw DTR and may stop sourcing data by design. - **ISO / audio dropouts:** ISO URB cadence (~1/ms at full speed) and payload lengths; zero-length frames are consistent with the device starving the endpoint; confirm on the target (what the class fed, and when) before blaming it. - **Wrong descriptors:** `-V` decodes them; check `bLength` / `wTotalLength` against what the device is meant to return.
Ver no GitHub