libusb: don't freeze when device vanishs

Instead of freezing, return corresponding libusb error code if the
USB device got disconnected. Therefore, components using the library
can continue to work otherwise.

Fix genodelabs/genode#5434
This commit is contained in:
Stefan Kalkowski 2025-01-23 13:37:43 +01:00 committed by Christian Helmuth
parent 76aba79e0b
commit e113d37958

View File

@ -17,7 +17,6 @@
#include <base/allocator_avl.h> #include <base/allocator_avl.h>
#include <base/signal.h> #include <base/signal.h>
#include <base/tslab.h> #include <base/tslab.h>
#include <base/sleep.h>
#include <usb_session/device.h> #include <usb_session/device.h>
#include <fcntl.h> #include <fcntl.h>
@ -36,6 +35,8 @@ static int vfs_libusb_fd { -1 };
struct Usb_device struct Usb_device
{ {
struct No_device {};
template <typename URB> template <typename URB>
struct Urb_tpl : URB struct Urb_tpl : URB
{ {
@ -169,10 +170,8 @@ void Usb_device::Interface::handle_events()
/* complete USB request */ /* complete USB request */
[this] (Urb &urb, Usb::Tagged_packet::Return_value v) [this] (Urb &urb, Usb::Tagged_packet::Return_value v)
{ {
if (v == Usb::Tagged_packet::NO_DEVICE) { if (v == Usb::Tagged_packet::NO_DEVICE)
error("USB device has vanished, will freeze!"); throw No_device();
sleep_forever();
}
if (v != Usb::Tagged_packet::OK) if (v != Usb::Tagged_packet::OK)
error("transfer failed, return value ", (int)v); error("transfer failed, return value ", (int)v);
@ -224,10 +223,8 @@ void Usb_device::handle_events()
/* complete USB request */ /* complete USB request */
[this] (Urb &urb, Usb::Tagged_packet::Return_value v) [this] (Urb &urb, Usb::Tagged_packet::Return_value v)
{ {
if (v == Usb::Tagged_packet::NO_DEVICE) { if (v == Usb::Tagged_packet::NO_DEVICE)
error("USB device has vanished, will freeze!"); throw No_device();
sleep_forever();
}
if (v != Usb::Tagged_packet::OK) if (v != Usb::Tagged_packet::OK)
error("control transfer failed, return value ", (int)v); error("control transfer failed, return value ", (int)v);
@ -366,6 +363,7 @@ static int genode_get_device_descriptor(struct libusb_device *,
unsigned char* buffer, unsigned char* buffer,
int *host_endian) int *host_endian)
{ {
try {
Usb_device::Urb urb(buffer, sizeof(libusb_device_descriptor), Usb_device::Urb urb(buffer, sizeof(libusb_device_descriptor),
device()._device, LIBUSB_REQUEST_GET_DESCRIPTOR, device()._device, LIBUSB_REQUEST_GET_DESCRIPTOR,
LIBUSB_ENDPOINT_IN, (LIBUSB_DT_DEVICE << 8) | 0, 0, LIBUSB_ENDPOINT_IN, (LIBUSB_DT_DEVICE << 8) | 0, 0,
@ -373,6 +371,9 @@ static int genode_get_device_descriptor(struct libusb_device *,
device()._wait_for_urb(urb); device()._wait_for_urb(urb);
*host_endian = 0; *host_endian = 0;
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} catch(Usb_device::No_device&) {
return LIBUSB_ERROR_NO_DEVICE;
}
} }
@ -382,6 +383,7 @@ static int genode_get_config_descriptor(struct libusb_device *,
size_t len, size_t len,
int *host_endian) int *host_endian)
{ {
try {
/* read minimal config descriptor */ /* read minimal config descriptor */
genode_usb_config_descriptor desc; genode_usb_config_descriptor desc;
Usb_device::Urb cfg(&desc, sizeof(desc), device()._device, Usb_device::Urb cfg(&desc, sizeof(desc), device()._device,
@ -398,6 +400,9 @@ static int genode_get_config_descriptor(struct libusb_device *,
*host_endian = 0; *host_endian = 0;
return desc.total_length; return desc.total_length;
} catch(Usb_device::No_device&) {
return 0;
}
} }
@ -466,6 +471,7 @@ static int genode_set_interface_altsetting(struct libusb_device_handle* dev_hand
int interface_number, int interface_number,
int altsetting) int altsetting)
{ {
try {
using P = Usb::Device::Packet_descriptor; using P = Usb::Device::Packet_descriptor;
using Rt = P::Request_type; using Rt = P::Request_type;
@ -489,11 +495,15 @@ static int genode_set_interface_altsetting(struct libusb_device_handle* dev_hand
Usb_device::Interface(device(), (uint8_t) interface_number, Usb_device::Interface(device(), (uint8_t) interface_number,
(uint8_t) altsetting); (uint8_t) altsetting);
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} catch(Usb_device::No_device&) {
return LIBUSB_ERROR_NO_DEVICE;
}
} }
static int genode_submit_transfer(struct usbi_transfer * itransfer) static int genode_submit_transfer(struct usbi_transfer * itransfer)
{ {
try {
struct libusb_transfer *transfer = struct libusb_transfer *transfer =
USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
Usb::Interface::Packet_descriptor::Type type = Usb::Interface::Packet_descriptor::Type type =
@ -550,6 +560,9 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
}); });
return found ? LIBUSB_SUCCESS : LIBUSB_ERROR_NOT_FOUND; return found ? LIBUSB_SUCCESS : LIBUSB_ERROR_NOT_FOUND;
} catch (Usb_device::No_device&) {
return LIBUSB_ERROR_NO_DEVICE;
}
} }
@ -565,11 +578,15 @@ static void genode_clear_transfer_priv(struct usbi_transfer * itransfer) { }
static int genode_handle_events(struct libusb_context *, struct pollfd *, static int genode_handle_events(struct libusb_context *, struct pollfd *,
POLL_NFDS_TYPE, int) POLL_NFDS_TYPE, int)
{ {
try {
libusb_genode_backend_signaling = false; libusb_genode_backend_signaling = false;
device().handle_events(); device().handle_events();
device()._interfaces.for_each([&] (Usb_device::Interface &iface) { device()._interfaces.for_each([&] (Usb_device::Interface &iface) {
iface.handle_events(); }); iface.handle_events(); });
return LIBUSB_SUCCESS; return LIBUSB_SUCCESS;
} catch(Usb_device::No_device&) {
return LIBUSB_ERROR_NO_DEVICE;
}
} }