qemu-usb: fix device endpoint update

First, the endpoint update has to comply with the current alternate
settings of all interface, which are stored in USBDevice::altsetting[]
(one value per interface). Second, a SET_INTERFACE control request via
Packet_type::ALT_SETTING must update USBDevice::altsetting for the
interface.

Now, USB devices with multi-setting interface like the Joulescope JS110
with mixed bulk/isochronous endpoints are supported.
This commit is contained in:
Christian Helmuth 2022-03-11 15:05:49 +01:00
parent 49efff1fef
commit bde3be787e

View File

@ -27,7 +27,7 @@ static bool const verbose_host = false;
static bool const verbose_warnings = false; static bool const verbose_warnings = false;
Mutex _mutex; Mutex _mutex;
static void update_ep(USBDevice *); static void update_ep(USBDevice *, uint8_t, uint8_t);
static bool claim_interfaces(USBDevice *dev); static bool claim_interfaces(USBDevice *dev);
using Packet_alloc_failed = Usb::Session::Tx::Source::Packet_alloc_failed; using Packet_alloc_failed = Usb::Session::Tx::Source::Packet_alloc_failed;
@ -183,7 +183,7 @@ struct Completion : Usb::Completion
if (!claim_interfaces(dev)) if (!claim_interfaces(dev))
p->status = USB_RET_IOERROR; p->status = USB_RET_IOERROR;
case Packet_type::ALT_SETTING: case Packet_type::ALT_SETTING:
update_ep(dev); update_ep(dev, packet.interface.number, packet.interface.alt_setting);
case Packet_type::CTRL: case Packet_type::CTRL:
usb_generic_async_ctrl_complete(dev, p); usb_generic_async_ctrl_complete(dev, p);
break; break;
@ -687,16 +687,12 @@ struct Usb_host_device : List<Usb_host_device>::Element
catch (Usb::Session::Device_not_found) { return; } catch (Usb::Session::Device_not_found) { return; }
for (unsigned i = 0; i < cdescr.num_interfaces; i++) { for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
udev->altsetting[i] = usb_raw.alt_settings(i);
}
for (unsigned i = 0; i < cdescr.num_interfaces; i++) {
for (int j = 0; j < udev->altsetting[i]; j++) {
Usb::Interface_descriptor iface; Usb::Interface_descriptor iface;
usb_raw.interface_descriptor(i, j, &iface); uint8_t const altsetting = udev->altsetting[i];
usb_raw.interface_descriptor(i, altsetting, &iface);
for (unsigned k = 0; k < iface.num_endpoints; k++) { for (unsigned k = 0; k < iface.num_endpoints; k++) {
Usb::Endpoint_descriptor endp; Usb::Endpoint_descriptor endp;
usb_raw.endpoint_descriptor(i, j, k, &endp); usb_raw.endpoint_descriptor(i, altsetting, k, &endp);
int const pid = (endp.address & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT; int const pid = (endp.address & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
int const ep = (endp.address & 0xf); int const ep = (endp.address & 0xf);
@ -709,7 +705,6 @@ struct Usb_host_device : List<Usb_host_device>::Element
} }
} }
} }
}
}; };
@ -723,11 +718,12 @@ struct Usb_host_device : List<Usb_host_device>::Element
OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE) OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)
static void update_ep(USBDevice *udev) static void update_ep(USBDevice *udev, uint8_t interface, uint8_t altsetting)
{ {
USBHostDevice *d = USB_HOST_DEVICE(udev); USBHostDevice *d = USB_HOST_DEVICE(udev);
Usb_host_device *dev = (Usb_host_device *)d->data; Usb_host_device *dev = (Usb_host_device *)d->data;
udev->altsetting[interface] = altsetting;
dev->update_ep(udev); dev->update_ep(udev);
} }