libusb: retry configuration-descriptor retrieval

Some USB devices (e.g., webcams) fail to deliver their configuration
descriptor early after power-up. Testing revealed that retrying the
requests usually succeeds on second or third attempt.

Fixes #4739
This commit is contained in:
Christian Helmuth 2023-01-23 12:07:23 +01:00
parent da673cfad7
commit 9de81369a7
2 changed files with 30 additions and 18 deletions

View File

@ -138,7 +138,7 @@ append config {
<default-policy domain=""/> <default-policy domain=""/>
</config> </config>
<route> <route>
<service name="Report"> <child name="acpi_report_rom"/> </service> <service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child /> </any-service> <any-service> <parent/> <any-child /> </any-service>
</route> </route>
</start> </start>

View File

@ -67,17 +67,9 @@ struct Usb_device
Usb::Config_descriptor config_descriptor; Usb::Config_descriptor config_descriptor;
char *raw_config_descriptor = nullptr; char *raw_config_descriptor = nullptr;
Usb_device(Usb::Connection *usb) bool _retrieve_raw_config_descriptor()
: usb_connection(usb)
{ {
Genode::log("libusb: waiting until device is plugged..."); Genode::log("libusb: retrieve configuration descriptor");
while (!usb_connection->plugged())
genode_env().ep().wait_and_dispatch_one_io_signal();
Genode::log("libusb: device is plugged");
usb_connection->config_descriptor(&device_descriptor, &config_descriptor);
raw_config_descriptor = (char*)malloc(config_descriptor.total_length);
Usb::Packet_descriptor p = Usb::Packet_descriptor p =
usb_connection->alloc_packet(config_descriptor.total_length); usb_connection->alloc_packet(config_descriptor.total_length);
@ -95,19 +87,39 @@ struct Usb_device
p = usb_connection->source()->get_acked_packet(); p = usb_connection->source()->get_acked_packet();
if (!p.succeded) bool ret = false;
if (!p.succeded) {
Genode::error(__PRETTY_FUNCTION__, Genode::error(__PRETTY_FUNCTION__,
": could not read raw configuration descriptor"); ": could not read raw configuration descriptor");
} else if (p.control.actual_size != config_descriptor.total_length) {
if (p.control.actual_size != config_descriptor.total_length)
Genode::error(__PRETTY_FUNCTION__, Genode::error(__PRETTY_FUNCTION__,
": received configuration descriptor of unexpected size"); ": received configuration descriptor of unexpected size");
} else {
char *packet_content = usb_connection->source()->packet_content(p); char *packet_content = usb_connection->source()->packet_content(p);
Genode::memcpy(raw_config_descriptor, packet_content, Genode::memcpy(raw_config_descriptor, packet_content,
config_descriptor.total_length); config_descriptor.total_length);
ret = true;
}
usb_connection->source()->release_packet(p); usb_connection->source()->release_packet(p);
return ret;
}
Usb_device(Usb::Connection *usb)
: usb_connection(usb)
{
Genode::log("libusb: waiting until device is plugged...");
while (!usb_connection->plugged())
genode_env().ep().wait_and_dispatch_one_io_signal();
Genode::log("libusb: device is plugged");
usb_connection->config_descriptor(&device_descriptor, &config_descriptor);
raw_config_descriptor = (char*)malloc(config_descriptor.total_length);
for (unsigned attempt = 0; attempt < 10; ++attempt)
if (_retrieve_raw_config_descriptor())
break;
} }
~Usb_device() ~Usb_device()