Repository navigation
Conversation
WebHID only surfaces interfaces the host recognises as HID, so a device declaring a vendor-specific class is invisible there even though it still speaks the HID protocol on the wire. This reaches those through nusb's WebUSB platform, reusing the native nusb backend's mapping of reports onto control and interrupt transfers. It deliberately does not filter for HID-class interfaces the way the native backend does: Blink refuses claimInterface on the protected classes, HID among them, so those are exactly the ones this cannot have and WebHID already covers. The crate-level docs linked native-only items unconditionally, which broke every wasm doc build; the platform paragraphs are now gated, and the wasm CI job also checks the WebHID-only configuration.
The README, the nusb feature comment and the backend module docs all still described wasm as WebHID-only. Records why the two browser backends are complements rather than alternatives, and notes in the e2e README that WebUSB has no target there and why.
Tests the WebUSB backend the same way linux-nusb tests the native one: dummy_hcd plus a configfs gadget, driven through Chromium/Playwright. The gadget has to be FunctionFS rather than usb_f_hid. Blink refuses claimInterface on the protected classes, so a HID-class interface cannot be claimed at all, and the device this backend exists for is one that declares class 0xFF. FunctionFS is what lets userspace say so, at the price of servicing the interface's control requests by hand. requestDevice() always opens a picker, so the harness reads device_list() instead, which WebUsbAllowDevicesForUrls pre-populates. That needed device_list to hand back openable devices rather than bare DeviceInfo.
The degenerate shapes are the ones with their own code paths, and both were going untested. control-only declares bNumEndpoints 0, which is what the Sinowealth ISP bootloaders look like: write has to fall back to SET_REPORT(Output), read has to refuse rather than hang, and get_input_report stays the way to poll. no-report-descriptor stalls GET_DESCRIPTOR(Report), the usual shape for a vendor-class interface, and report_descriptor has to report Unsupported rather than hand back an empty buffer. run.sh rebuilds the gadget between the three.
|
Closing: the devices this was built for cannot be reached over WebUSB. Tested against a real plugged-in Sinowealth mouse ( Every archived Sinowealth ISP bootloader declares The branch stays if a genuinely vendor-class device ever turns up. What it contained:
One fix here is worth salvaging and is unrelated to WebUSB: the crate-level docs link native-only items ( |
Adds
hidra::webusb, a wasm backend built on nusb's WebUSB platform, for devices the browser will not expose over WebHID.Stacked on #8.
Why
WebHID only surfaces interfaces the host recognises as HID. A device whose interface declares a vendor-specific class never appears there, even though it typically still speaks the HID protocol on the wire.
The split is forced by the platform: Blink refuses
claimInterfaceon the protected classes — HID (0x03), Audio, Video, Mass Storage, Smart Card, Wireless Controller. So the two backends are complementary rather than interchangeable:SecurityErrorThis is why the backend deliberately does not filter for HID-class interfaces the way the native
nusbbackend does: those are precisely the ones it cannot have, and WebHID already covers them.What
src/backend/webusb.rs— the HID-over-USB mapping, mirroring the nativenusbbackend:SET_REPORT/GET_REPORTclass requests for feature and input reports, interrupt OUT for writes (falling back toSET_REPORT(Output)), interrupt IN for reads,GET_DESCRIPTOR(Report)where the interface has one.hidra::webusb::{Hidra, Device, HidDevice, DeviceSelector}— async throughout, since the browser event loop cannot block.request_devicedrives the chooser;openclaims an interface (Nonetakes the first).RefCell: wasm is single-threaded but futures still interleave, so a second in-flight transfer is refused rather than aliasing the endpoint.feature = "nusb"+wasm32, so the WebHID-only build is unchanged.Incidental
The crate-level docs linked native-only items (
Backend,Hidra::builder) unconditionally, so every wasm doc build failed. Pre-existing, and invisible because the docs job only documents the native target. The platform paragraphs are nowcfg_attr-gated, and the wasm CI job additionally checks the--no-default-featuresconfiguration.Testing
fmt,clippy(native, wasm default, wasm no-default),test, MSRV 1.85 and both doc targets pass locally.No e2e leg yet: exercising WebUSB needs either a real vendor-class device or browser-side emulation, so it is not covered by the virtual-device suites. Worth adding once there is a device to point it at.