rust-embedded-community / usb-device

Experimental device-side USB framework for microcontrollers in Rust.
MIT License
437 stars 75 forks source link

Mass Storage Class broken (on macOS?) #93

Closed reitermarkus closed 7 months ago

reitermarkus commented 2 years ago

After almost two days of debugging, I finally figured out why MSC (using https://github.com/cs2dsb/stm32-usb.rs) is not working.

Not working specifically means the setup process stops before the SET_CONFIGURATION request is received.

I had a functioning version to compare implemented using the STM32L4 C HAL, so I tried to recreate it exactly in Rust like so:

let vid_pid = UsbVidPid(1155, 22314);
let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, vid_pid)
    .manufacturer("STMicroelectronics")
    .product("STM32 Mass Storage")
    .serial_number("00000000001A")
    .self_powered(true)
    .device_class(USB_CLASS_MSC)
    .device_sub_class(InterfaceSubclass::ScsiTransparentCommandSet.to_primitive())
    .device_protocol(InterfaceProtocol::BulkOnlyTransport.to_primitive())
    .max_packet_size_0(64)
    .device_release(0x0200)
    .build();

The above results in the device descriptor having these (among other) fields:

0x08, // bDeviceClass
0x06, // bDeviceSubClass
0x50, // bDeviceProtocol

The STM32L4 HAL on the other hand, hardcodes these to CDC values, even for MSC:

0x02, // bDeviceClass
0x02, // bDeviceSubClass
0x00, // bDeviceProtocol

I then tried changing the working C version to use 0x08 for the device class. After this change, the setup stops before the SET_CONFIGURATION request is received. Vice-versa, hard-coding the device class to 0x00 in Rust makes the setup go past the SET_CONFIGURATION request.

I also found the composite_with_iads also makes it work, so it seems to only be an issue when the device class is set to 0x08.

Maybe I am supposed to used composite_with_iads for MSC? Or is this definitely a bug (in macOS, I suppose)?

Not sure what the proper fix is here. Setting all values to 0x00 seems to work since then the class information of the interface is used.

ianrrees commented 2 years ago

It's pretty hard to say where the bug is with this sort of thing, especially without the descriptors in question or more info about what MacOS uses to handle them. In practice, I've found there is a certain amount of guess-and-check required, to make USB devices that work across different OSs - it's not as "Universal" as one might assume :).

It seems strange to me that the C HAL would hardcode a CDC device descriptor, and that the result would work as a MSC - does the interface descriptor at least have correct-looking descriptors in that case?

Just based on what you've posted, it looks to me like usb-device is doing the right thing here by providing the class/subclass/protocol from usbd-mass-storage - so that would be a good place to ask. Since that project looks pretty quiet though, it might also be worth trying https://matrix.to/#/#usb-rs:matrix.org .

ryan-summers commented 7 months ago

I'm going to close this issue because it isn't clear to me that this is an issue with usb-device. If you feel otherwise, please post/update this issue :)