Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emscripten: MAX_CTRL_BUFFER_LENGTH too big for some devices #1493

Open
srcejon opened this issue May 7, 2024 · 8 comments
Open

Emscripten: MAX_CTRL_BUFFER_LENGTH too big for some devices #1493

srcejon opened this issue May 7, 2024 · 8 comments

Comments

@srcejon
Copy link
Contributor

srcejon commented May 7, 2024

I’m trying to use libusb in a Qt WebAssembly app via the Emscripten port. The first call to libusb_get_device_list() is failing on Windows 11 using Chrome, Edge and Opera, with the console message:

DOMException: Failed to execute 'controlTransferIn' on 'USBDevice': A transfer error has occurred.

Tracing through the code, I see that the first call to controlTransferIn works successfully (where wLength is 0x12), however the second controlTransferIn call fails where wLength is 0x1000).

I believe the problem relates to the following code in emscripten_webusb.cpp:

		// Note: requesting more than (platform-specific limit) bytes
		// here will cause the transfer to fail, see
		// https://crbug.com/1489414. Use the most common limit of 4096
		// bytes for now.
		constexpr uint16_t MAX_CTRL_BUFFER_LENGTH = 4096;

If I change this max buffer size to 255, then the second transfer works.

I was able to reproduce the same behavior using pure Javascript, as can be seen in the attached example: js.zip - so does indeed look like a browser/platform specific limit.

@tormodvolden
Copy link
Contributor

tormodvolden commented May 7, 2024

Shouldn't the code instead do like "everybody else"? First request a small part of the configuration (actually the configuration descriptor itself without all other descriptors) into a small buffer, in order to read the total length from the header, then request the exact total length. @RReverser

@RReverser
Copy link
Contributor

We could do that - at the cost of extra round-trip cost for each configuration descriptor, which is somewhat unfortunate - but I'm surprised as neither in official docs of different operating systems nor in real-world usage I haven't encountered any OS which wouldn't accept even 4K packets.

And I do use Windows 11, where apps using this backend worked just fine so far, so I'm really curious what the difference / why this example only accepts up to 256 bytes.

Is it some kind of special USB device / some old protocol / anything else that might be relevant?

@tormodvolden
Copy link
Contributor

It is not so much about the OS but the device, I suppose. See also the last paragraph here: https://blog.numist.net/post/3646027757/usb-deviceiocontrol-overlapped-io-and-you-and

And I agree, we need to know what kind of device this is. An lsusb -v dump is always nice.

@srcejon srcejon changed the title Emscripten: MAX_CTRL_BUFFER_LENGTH too big on Windows Emscripten: MAX_CTRL_BUFFER_LENGTH too big for some devices May 8, 2024
@srcejon
Copy link
Contributor Author

srcejon commented May 8, 2024

Yes, looks to be device specific rather than OS. I tried other devices on Windows and they were fine with 4096. Also, I tried this device (an RTL SDR) on Chrome/Linux and it has the same problem when length greater than 255.

lsusb output:

Bus 002 Device 007: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0bda Realtek Semiconductor Corp.
idProduct 0x2838 RTL2838 DVB-T
bcdDevice 1.00
iManufacturer 1 Realtek
iProduct 2 RTL2838UHIDIR
iSerial 3 00000001
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0022
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 4 USB2.0-Bulk&Iso
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 5 Bulk-In, Interface
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 5 Bulk-In, Interface
Device Qualifier (for other device speed):
bLength 10
bDescriptorType 6
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
bNumConfigurations 2
Device Status: 0x0000
(Bus Powered)

@RReverser
Copy link
Contributor

wMaxPacketSize 0x0200 1x 512 bytes

I wonder if this is the actual limit - as in, 512 bytes would also work.

If we can use wMaxPacketSize, then we don't really need to pay for 2x requests to read length and the actual descriptor for each config separately - we could just always use this limit instead.

@srcejon
Copy link
Contributor Author

srcejon commented May 8, 2024

256 doesn't work, unfortunately.

@tormodvolden
Copy link
Contributor

This is only per device enumeration so I wouldn't worry too much about an extra request. It is the way all host stacks do it, and as mentioned in my link above, many devices expect it do be done this way. I don't know if the standard says something specific about it. The whole concept here is very inefficient anyway. Somewhere down this convoluted stack the whole configuration has been cached already so any device request shouldn't have been needed.

@RReverser
Copy link
Contributor

256 doesn't work, unfortunately.

Huh, fascinating. Okay, if there is no way around it, let's do 2 requests. I'm not near a computer right now, so could do this later, but if you want to open a PR, I'd be happy to review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants