Capture a USB HID Descriptor Safely with usbhid-dump
A keyboard, mouse or game controller sends bytes you cannot see, and usbhid-dump pulls the raw HID report descriptor so you can actually read them. Allow about ten minutes for a first capture. The examples use the usbutils package installed here, version 017, with usbhid-dump reporting version 1.4.
The route
Jump straight to the step you need, or tick off Done means at the end.
Checkpoint
This guide captures a descriptor by default. It does not start a live input stream unless you explicitly add -e stream or -es.
1. Check the installed command
Run the version and help commands as your ordinary user. Neither detaches a kernel driver or reads from a device:
$ usbhid-dump --version
usbhid-dump 1.4
$ usbhid-dump --help
Usage: usbhid-dump [OPTION]...
The exact copyright and help text can vary by build. The checks that matter are the version number and the documented defaults: entity descriptor and a 60,000 millisecond stream timeout.
On this installed build, the package is usbutils 1:017-3build1. Do not silently apply instructions written for a different release if an option or output detail matters to your investigation.
2. Find the device and its bus address
Use lsusb to list devices before selecting one:
$ lsusb
Bus 002 Device 003: ID 054c:0ce6 Example USB device
Write down the bus and device numbers from the line you intend to inspect. The example values above are placeholders, so replace 002:003 with values from your own output. If the device exposes several HID interfaces, you can narrow the capture further in the next step.
Bus and device addresses change after unplugging, replugging or rebooting. Treat an old address as stale evidence and run lsusb again rather than guessing.
3. Capture one report descriptor
Use -a bus:device to select the device and -e descriptor to make the requested entity explicit:
$ sudo usbhid-dump --address=002:003 --entity=descriptor
002:003:000:DESCRIPTOR 1730000000.123456
05 01 09 02 A1 01 09 01 A1 00 ...
Root access is commonly required because the program uses libusb to claim the interface. Omit sudo if your device permissions already grant access. The output is one chunk: a header line, followed by hexadecimal bytes. The interface number in the header is 000 in this illustrative output, not a guarantee about your device.
For a real capture, the descriptor bytes should continue until the whole report descriptor has printed. An empty result usually means the selection matched no HID interface, the device disappeared, or access was denied. Check the command's exit status and repeat lsusb before changing filters.
Checkpoint
You now have a descriptor without opening a live stream. Save a copy only after checking the output really is from the intended bus and device:
$ sudo usbhid-dump -a 002:003 -ed > hid-descriptor.txt
$ sed -n '1,4p' hid-descriptor.txt
002:003:000:DESCRIPTOR 1730000000.123456
05 01 09 02 A1 01 ...
Shell redirection creates or truncates hid-descriptor.txt. Use a new filename if an earlier capture matters. The command does not touch the device's firmware or persistent configuration, but it does temporarily claim the selected interface while it runs.
4. Narrow the selection when several interfaces match
Use --model=vid:pid when you know the vendor and product IDs from lsusb. Both values are hexadecimal:
$ sudo usbhid-dump --model=054c:0ce6 --entity=descriptor
You can also select an interface number with --interface=NUMBER:
$ sudo usbhid-dump -m 054c:0ce6 -i 1 -ed
- Filters combine. The short forms are
-mfor model,-ifor interface and-afor address. - Zero is a wildcard. A zero in an address or model filter matches any value, and interface
255matches any interface, useful for a broad search but a poor choice for repeatable evidence. - Address and interface are not the same thing.
002:003identifies a USB device on bus 002;-i 1selects interface 1 inside that device.
5. Inspect a stream only with a safe boundary
A stream capture is different from a descriptor capture. --entity=stream keeps running until you press Ctrl-C or the timeout expires, and it detaches the kernel driver from the selected interface while active. The default timeout is 60 seconds:
$ sudo usbhid-dump -a 002:003 -es -t 5000
002:003:000:STREAM 1730000000.234567
00 00 00 00 00 00 00 00
The timeout is in milliseconds, so 5000 means five seconds. A zero timeout means infinity. Prefer a short timeout while learning the device, and stop it with Ctrl-C once you have enough data.
Warning
Never start an unrestricted stream dump while the selected device might be the keyboard controlling your terminal. The program can detach that keyboard, leaving you unable to type Ctrl-C. The installed manual's recovery is to stop input and wait for the timeout; the keyboard should then be reattached and control returned. If you set -t 0, there is no automatic timeout at all, so never use that value for a first test from a keyboard-controlled session.
For a visible sign that transfers are arriving, add --stream-feedback: it prints a dot to standard error for each transfer dumped. To start with output paused, use --stream-paused; USR1 and USR2 pause and resume stream output.
6. Read the output and recover from errors
Each output chunk starts with BUS:DEVICE:INTERFACE:ENTITY TIMESTAMP. The timestamp is seconds since the Unix epoch. DESCRIPTOR identifies the complete report descriptor. STREAM identifies an input report, though a report larger than the endpoint packet size can span multiple chunks.
If access fails, retry without changing the device selection first and read the diagnostic carefully. Then check whether your account has permission to access the USB device. Use sudo only for this diagnostic command, not for anything else done with the saved text. If no interface matches, confirm the hexadecimal spelling of the ID and the decimal spelling of the interface number.
If a stream command stops after the timeout, that is expected. If it stops after Ctrl-C, the interface should be released and the kernel driver reattached. Check that the keyboard, mouse or other input device works before starting another capture. If it does not, unplugging and reconnecting the device is a practical recovery step, but it can change its bus address and interrupt any application using it.
Done means
- Version checked. You checked the installed
usbhid-dumpversion and its defaults. - Device confirmed. You selected the intended device from fresh
lsusboutput. - Descriptor captured first. You captured a descriptor with
-edbefore attempting any stream capture. - Addressing understood. You understand that bus, device and interface numbers are different values.
- Stream kept safe. Any stream test used a short timeout and avoided the controlling USB keyboard.
- Recovery understood. You can identify the output header and know when the kernel driver should be available again.