libusb interrupt transfer
Asked Answered
B

2

6

I need to reverse engineer a driver for custom made HID USB device (some buttons and leds on an control panel). The driver is only available on Windows and we need a *nix implementation.

The device apparently is a HID device although not of a particular class. It provides two interfaces each with a single interrupt endpoint.

My setup currently involves a VirtualBox running Windows on a Ubuntu host to capture the USB traffic via Wireshark. The protocol is rather simple and I already gained a rather good understanding.

I am using libusb-1.0 in a simple C++ console program for prototyping. I already managed to toggle LEDs by issuing a SET_REPORT control transfer but struggle in receiving button presses via interrupt in transfers.

In fact the following call blocks forever:

unsigned char bytes[8] = { 0 };
int len = 0;
int ret = libusb_interrupt_transfer(handle, 0x81, bytes, 8, &len, 0); 

When inspecting the resulting URB in Wireshark it looks exactly like the equivalent captured at the Windows session. Still I never get a reply from the device.

I fell I am missing some setting. Note that the device is properly opened and both interfaces provided by the device have been sucessfully claimed. Input reports by means of control transfers are coming trough, even in my linux application.

Thanks for any pointer! Arne

Addendum I: I am wondering how am I supposed to specify which report id I want to receive when using libusb_interrupt_transfer()?

Addendum II: When comparing the requests made by the windows driver to the one generated by the above code in Wireshark I don't see any difference (same values in URB). But still, only when issued by the Windows driver the interrupt transfer returns.

When inspecting the Windows driver communication in Wireshark I dont see any control transfers other than various GET_DESCRIPTOR(...). Most important: no SET_INTERFACE or SET_CONFIGURATION Thus I suspect the problem is related to the library or how I use it and is not related to the device.

Bascule answered 25/6, 2011 at 0:15 Comment(2)
@david: I can't post the descriptor right now because the device resides in my office. Anyway there definitely are two endpoints in the descriptor - one on each of the two interfaces. Both interfaces provide at least one output report containing the button states of the device. At least those reports define Usage Buttons.Bascule
I thought myself that libusb_interrupt_transfer were blocking forever, even though I had set a timeout for 500ms. But when my simple driver hung up after I commented out that line; So I inserted some debug-prints here and there and found out that libusb_open locks up forever, no matter which device I issued it on. Dammit, should it really need to be this hard to get int x,y,pressure,button_state; from a digital pen tablet? Seriously, that's overkill :)Trussing
C
3

I had the same issue, libusb_interrupt_transfer() blocks forever for read endpoint (bEndpoinntAddress: 0x81 EP 1 IN (output of lsusb -v)), but solved.

In my case, I have written like this.

#define ENDPOINT_IN 0x81
unsigned char buffer[8];
int len = 0;
int ret = libusb_interrupt_transfer(handle, ENDPOINT_IN, buffer, sizeof(buffer), &len, 0);

But, my device requires some code sent before reading data,
and requires sizeof 64 buffer although lsusb -v's output bLength is 7.

#define ENDPOINT_OUT 0x01
#define ENDPOINT_IN 0x81
unsigned char buffer[64] = {0x20, 0x01, 0x03, 0x02, 0x07};
int len = 0;
int send_ret = libusb_interrupt_transfer(handle, ENDPOINT_OUT, buffer, sizeof(buffer), &len, 0);
int recv_ret = libusb_interrupt_transfer(handle, ENDPOINT_IN, buffer, sizeof(buffer), &len, 0);

the buffer[64] = {0x20, 0x01, 0x03, 0x02, 0x07} depends on the device specification.

Hope this helps.

Chaves answered 25/5, 2019 at 5:46 Comment(0)
N
2

There is a problem with the code you posted. The syntax you wrote for defining bytes will not result in an 8-byte array, but you are requesting that libusb write 8 bytes in to that address so you might get an error or memory corruption. Try this instead:

unsigned char buffer[8];
int len = 0;
int ret = libusb_interrupt_transfer(handle, 0x81, buffer, sizeof(buffer), &len, 0);

Each HID report has its own endpoint, so you specify which report you want to receive by specifying the correct endpoint. You specified Endpoint 1 IN (0x81). Are you sure that endpoint is defined in the device's descriptors? Maybe you should get the descriptors (with lsusb -v in Ubuntu) and post them here so we can check them.

Novelia answered 25/6, 2011 at 6:20 Comment(1)
the missing brackets are a typo. The actual code reads unsigned char buffer[8]. Thanks for the hint, anyway.Bascule

© 2022 - 2024 — McMap. All rights reserved.