HID descriptor output on Windows is wrong using rusb/libusb

Hi,

I'm playing around with USB HID and trying to read the HID Descriptor from a device and print it out.
I'm using the rusb crate and it works great on Linux and macOS, but on Windows the output is a lot shorter.

You can find and try the program in my usb-hid-descriptor-parser-cli repository, where there is also a link in the readme to the library with the actual code.

I'm testing with a Jabra dongle for a wireless headset.
The output on Ubuntu 20.04 and macOS 12 is the same and looks like this:

USB HID report descriptor bytes:
0x05 0x0B 0x09 0x05 0xA1 0x01 0x85 0x02 0x05 0x0B 0x15 0x00 0x25 0x01 0x09 0x20 0x09 0x97 0x09 0x2A 0x75 0x01 0x95 0x03 0x81 0x23 0x09 0x2F 0x09 0x21 0x09 0x24 0x09 0x50 0x75 0x01 0x95 0x04 0x81 0x07 0x09 0x06 0xA1 0x02 0x19 0xB0 0x29 0xBB 0x15 0x00 0x25 0x0C 0x75 0x04 0x95 0x01 0x81 0x40 0xC0 0x09 0x07 0x15 0x00 0x25 0x01 0x05 0x09 0x75 0x01 0x95 0x01 0x81 0x02 0x75 0x01 0x95 0x04 0x81 0x01 0x05 0x08 0x15 0x00 0x25 0x01 0x09 0x17 0x09 0x1E 0x09 0x09 0x09 0x18 0x09 0x20 0x09 0x21 0x09 0x2A 0x75 0x01 0x95 0x07 0x91 0x22 0x05 0x0B 0x15 0x00 0x25 0x01 0x09 0x9E 0x75 0x01 0x95 0x01 0x91 0x22 0x75 0x01 0x95 0x08 0x91 0x01 0xC0 0x06 0x00 0xFF 0x09 0x01 0xA1 0x01 0x85 0x05 0x09 0x01 0x15 0x00 0x26 0xFF 0x00 0x75 0x08 0x95 0x3E 0x92 0x02 0x01 0x09 0x01 0x15 0x00 0x26 0xFF 0x00 0x75 0x08 0x95 0x3E 0x82 0x02 0x01 0x85 0x04 0x06 0x30 0xFF 0x15 0x00 0x25 0x01 0x09 0x20 0x0A 0xFB 0xFF 0x09 0x97 0x09 0x2A 0x75 0x01 0x95 0x04 0x81 0x23 0x09 0x2F 0x09 0x21 0x09 0x24 0x0A 0xFD 0xFF 0x09 0x50 0x75 0x01 0x95 0x05 0x81 0x07 0x09 0x06 0xA1 0x02 0x19 0xB0 0x29 0xBB 0x15 0x00 0x25 0x0C 0x75 0x04 0x95 0x01 0x81 0x40 0xC0 0x0A 0xFC 0xFF 0x15 0x00 0x25 0x01 0x75 0x01 0x95 0x01 0x81 0x23 0x75 0x01 0x95 0x02 0x81 0x01 0x06 0x40 0xFF 0x15 0x00 0x25 0x01 0x09 0x17 0x0A 0xFB 0xFF 0x09 0x09 0x09 0x18 0x09 0x20 0x09 0x21 0x09 0x2A 0x75 0x01 0x95 0x07 0x91 0x22 0x06 0x30 0xFF 0x15 0x00 0x25 0x01 0x09 0x9E 0x75 0x01 0x95 0x01 0x91 0x22 0x75 0x01 0x95 0x08 0x91 0x01 0x0A 0xFF 0xFF 0x15 0x00 0x25 0x01 0x75 0x01 0x95 0x01 0xB1 0x22 0x75 0x01 0x95 0x07 0xB1 0x01 0xC0 0x05 0x0C 0x09 0x01 0xA1 0x01 0x85 0x01 0x05 0x0C 0x15 0x00 0x25 0x01 0x09 0xEA 0x09 0xE9 0x09 0xE2 0x09 0xCD 0x09 0xB7 0x09 0xB5 0x09 0xB6 0x09 0xB3 0x09 0xB4 0x75 0x01 0x95 0x09 0x81 0x02 0x09 0xB1 0x09 0xB0 0x75 0x01 0x95 0x02 0x81 0x07 0x75 0x01 0x95 0x05 0x81 0x01 0xC0 0x06 0x99 0xFF 0x09 0x01 0xA1 0x01 0x09 0x03 0x85 0x9A 0x15 0x00 0x26 0xFF 0x00 0x75 0x08 0x95 0x3E 0xB2 0x02 0x01 0x09 0x04 0x85 0x9B 0x15 0x00 0x25 0x01 0x75 0x01 0x95 0x01 0x81 0x02 0x75 0x01 0x95 0x0F 0x81 0x01 0xC0 

USB HID report descriptor:
0x05, 0x0b,       // Usage Page (Telephony Page) [Global]
0x09, 0x05,       // Usage (Headset) [Local]
0xa1, 0x01,       // Collection (Application) [Main]
0x85, 0x02,       //   Report ID (2) [Global]
0x05, 0x0b,       //   Usage Page (Telephony Page) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0x20,       //   Usage (Hook Switch) [Local]
0x09, 0x97,       //   Usage (Line Busy Tone) [Local]
0x09, 0x2a,       //   Usage (Line) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x03,       //   Report Count (3) [Global]
0x81, 0x23,       //   Input (Constant, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Bit Field) [Main]
0x09, 0x2f,       //   Usage (Phone Mute) [Local]
0x09, 0x21,       //   Usage (Flash) [Local]
0x09, 0x24,       //   Usage (Redial) [Local]
0x09, 0x50,       //   Usage (Speed Dial) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x04,       //   Report Count (4) [Global]
0x81, 0x07,       //   Input (Constant, Variable, Relative, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x09, 0x06,       //   Usage (Telephony Key Pad) [Local]
0xa1, 0x02,       //   Collection (Logical) [Main]
0x19, 0xb0,       //     Usage Minimum (176) [Local]
0x29, 0xbb,       //     Usage Maximum (187) [Local]
0x15, 0x00,       //     Logical Minimum (0) [Global]
0x25, 0x0c,       //     Logical Maximum (12) [Global]
0x75, 0x04,       //     Report Size (4) [Global]
0x95, 0x01,       //     Report Count (1) [Global]
0x81, 0x40,       //     Input (Data, Array, Absolute, No Wrap, Linear, Preferred State, Null State, Bit Field) [Main]
0xc0,             //   End Collection [Main]
0x09, 0x07,       //   Usage (Programmable Button) [Local]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x05, 0x09,       //   Usage Page (Button Page) [Global]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x01,       //   Report Count (1) [Global]
0x81, 0x02,       //   Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x04,       //   Report Count (4) [Global]
0x81, 0x01,       //   Input (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x05, 0x08,       //   Usage Page (LED Page) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0x17,       //   Usage (Off-Hook) [Local]
0x09, 0x1e,       //   Usage (Speaker) [Local]
0x09, 0x09,       //   Usage (Mute) [Local]
0x09, 0x18,       //   Usage (Ring) [Local]
0x09, 0x20,       //   Usage (Hold) [Local]
0x09, 0x21,       //   Usage (Microphone) [Local]
0x09, 0x2a,       //   Usage (On-Line) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x07,       //   Report Count (7) [Global]
0x91, 0x22,       //   Output (Data, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0x05, 0x0b,       //   Usage Page (Telephony Page) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0x9e,       //   Usage (Ringer) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x01,       //   Report Count (1) [Global]
0x91, 0x22,       //   Output (Data, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x08,       //   Report Count (8) [Global]
0x91, 0x01,       //   Output (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0xc0,             // End Collection [Main]
0x06, 0x00, 0xff, // Usage Page (Vendor-defined 0xFF00) [Global]
0x09, 0x01,       // Usage (0x01) [Local]
0xa1, 0x01,       // Collection (Application) [Main]
0x85, 0x05,       //   Report ID (5) [Global]
0x09, 0x01,       //   Usage (0x01) [Local]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x26, 0xff, 0x00, //   Logical Maximum (255) [Global]
0x75, 0x08,       //   Report Size (8) [Global]
0x95, 0x3e,       //   Report Count (62) [Global]
0x92, 0x02, 0x01, //   Output (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null State, Non-volatile, BufferedBytes) [Main]
0x09, 0x01,       //   Usage (0x01) [Local]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x26, 0xff, 0x00, //   Logical Maximum (255) [Global]
0x75, 0x08,       //   Report Size (8) [Global]
0x95, 0x3e,       //   Report Count (62) [Global]
0x82, 0x02, 0x01, //   Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null State, BufferedBytes) [Main]
0x85, 0x04,       //   Report ID (4) [Global]
0x06, 0x30, 0xff, //   Usage Page (Vendor-defined 0xFF30) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0x20,       //   Usage (0x20) [Local]
0x0a, 0xfb, 0xff, //   Usage (0xFFFB) [Local]
0x09, 0x97,       //   Usage (0x97) [Local]
0x09, 0x2a,       //   Usage (0x2A) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x04,       //   Report Count (4) [Global]
0x81, 0x23,       //   Input (Constant, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Bit Field) [Main]
0x09, 0x2f,       //   Usage (0x2F) [Local]
0x09, 0x21,       //   Usage (0x21) [Local]
0x09, 0x24,       //   Usage (0x24) [Local]
0x0a, 0xfd, 0xff, //   Usage (0xFFFD) [Local]
0x09, 0x50,       //   Usage (0x50) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x05,       //   Report Count (5) [Global]
0x81, 0x07,       //   Input (Constant, Variable, Relative, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x09, 0x06,       //   Usage (0x06) [Local]
0xa1, 0x02,       //   Collection (Logical) [Main]
0x19, 0xb0,       //     Usage Minimum (176) [Local]
0x29, 0xbb,       //     Usage Maximum (187) [Local]
0x15, 0x00,       //     Logical Minimum (0) [Global]
0x25, 0x0c,       //     Logical Maximum (12) [Global]
0x75, 0x04,       //     Report Size (4) [Global]
0x95, 0x01,       //     Report Count (1) [Global]
0x81, 0x40,       //     Input (Data, Array, Absolute, No Wrap, Linear, Preferred State, Null State, Bit Field) [Main]
0xc0,             //   End Collection [Main]
0x0a, 0xfc, 0xff, //   Usage (0xFFFC) [Local]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x01,       //   Report Count (1) [Global]
0x81, 0x23,       //   Input (Constant, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x02,       //   Report Count (2) [Global]
0x81, 0x01,       //   Input (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x06, 0x40, 0xff, //   Usage Page (Vendor-defined 0xFF40) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0x17,       //   Usage (0x17) [Local]
0x0a, 0xfb, 0xff, //   Usage (0xFFFB) [Local]
0x09, 0x09,       //   Usage (0x09) [Local]
0x09, 0x18,       //   Usage (0x18) [Local]
0x09, 0x20,       //   Usage (0x20) [Local]
0x09, 0x21,       //   Usage (0x21) [Local]
0x09, 0x2a,       //   Usage (0x2A) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x07,       //   Report Count (7) [Global]
0x91, 0x22,       //   Output (Data, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0x06, 0x30, 0xff, //   Usage Page (Vendor-defined 0xFF30) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0x9e,       //   Usage (0x9E) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x01,       //   Report Count (1) [Global]
0x91, 0x22,       //   Output (Data, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x08,       //   Report Count (8) [Global]
0x91, 0x01,       //   Output (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0x0a, 0xff, 0xff, //   Usage (0xFFFF) [Local]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x01,       //   Report Count (1) [Global]
0xb1, 0x22,       //   Feature (Data, Variable, Absolute, No Wrap, Linear, No Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x07,       //   Report Count (7) [Global]
0xb1, 0x01,       //   Feature (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Non-volatile, Bit Field) [Main]
0xc0,             // End Collection [Main]
0x05, 0x0c,       // Usage Page (Consumer Page) [Global]
0x09, 0x01,       // Usage (Consumer Control) [Local]
0xa1, 0x01,       // Collection (Application) [Main]
0x85, 0x01,       //   Report ID (1) [Global]
0x05, 0x0c,       //   Usage Page (Consumer Page) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x09, 0xea,       //   Usage (Volume Decrement) [Local]
0x09, 0xe9,       //   Usage (Volume Increment) [Local]
0x09, 0xe2,       //   Usage (Mute) [Local]
0x09, 0xcd,       //   Usage (Play/Pause) [Local]
0x09, 0xb7,       //   Usage (Stop) [Local]
0x09, 0xb5,       //   Usage (Scan Next Track) [Local]
0x09, 0xb6,       //   Usage (Scan Previous Track) [Local]
0x09, 0xb3,       //   Usage (Fast Forward) [Local]
0x09, 0xb4,       //   Usage (Rewind) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x09,       //   Report Count (9) [Global]
0x81, 0x02,       //   Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x09, 0xb1,       //   Usage (Pause) [Local]
0x09, 0xb0,       //   Usage (Play) [Local]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x02,       //   Report Count (2) [Global]
0x81, 0x07,       //   Input (Constant, Variable, Relative, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x05,       //   Report Count (5) [Global]
0x81, 0x01,       //   Input (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0xc0,             // End Collection [Main]
0x06, 0x99, 0xff, // Usage Page (Vendor-defined 0xFF99) [Global]
0x09, 0x01,       // Usage (0x01) [Local]
0xa1, 0x01,       // Collection (Application) [Main]
0x09, 0x03,       //   Usage (0x03) [Local]
0x85, 0x9a,       //   Report ID (154) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x26, 0xff, 0x00, //   Logical Maximum (255) [Global]
0x75, 0x08,       //   Report Size (8) [Global]
0x95, 0x3e,       //   Report Count (62) [Global]
0xb2, 0x02, 0x01, //   Feature (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null State, Non-volatile, BufferedBytes) [Main]
0x09, 0x04,       //   Usage (0x04) [Local]
0x85, 0x9b,       //   Report ID (155) [Global]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0x01,       //   Logical Maximum (1) [Global]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x01,       //   Report Count (1) [Global]
0x81, 0x02,       //   Input (Data, Variable, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0x75, 0x01,       //   Report Size (1) [Global]
0x95, 0x0f,       //   Report Count (15) [Global]
0x81, 0x01,       //   Input (Constant, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0xc0,             // End Collection [Main]

But on Windows 10 and 11 the output is a lot shorter, like this:

USB HID report descriptor bytes:
0x06 0x0C 0x00 0x09 0x01 0xA1 0x01 0x09 0x01 0x15 0x00 0x25 0xFF 0x75 0x08 0x95 0x02 0x81 0x00 0xC0

USB HID report descriptor:
0x06, 0x0c, 0x00, // Usage Page (Consumer Page) [Global]
0x09, 0x01,       // Usage (Consumer Control) [Local]
0xa1, 0x01,       // Collection (Application) [Main]
0x09, 0x01,       //   Usage (0x01) [Local]
0x15, 0x00,       //   Logical Minimum (0) [Global]
0x25, 0xff,       //   Logical Maximum (255) [Global]
0x75, 0x08,       //   Report Size (8) [Global]
0x95, 0x02,       //   Report Count (2) [Global]
0x81, 0x00,       //   Input (Data, Array, Absolute, No Wrap, Linear, Preferred State, No Null State, Bit Field) [Main]
0xc0,             // End Collection [Main]

Any input on this problem, my code and structure in general, or suggestions for alternative approaches are appreciated.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.