summaryrefslogtreecommitdiff
path: root/usbredirhost/usbredirhost.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-03-31 16:09:55 +0200
committerHans de Goede <hdegoede@redhat.com>2012-03-31 16:52:31 +0200
commit0c6cea986b1cf6a5d20778842043475042e1716d (patch)
tree7efbdf16aaab7dcb06bca8a73613f8545b65e1b0 /usbredirhost/usbredirhost.c
parentd81f0ff7053915bb0e5f599af35e071c2751f90d (diff)
usbredirhost: Speed up reset handling
In some cases a usb-guest does multiple resets in a row, these are instant from the guest pov but they are synchronously handled by us. So if a usb-guest does 4 resets in a row (seabios does this) then we can accumulate quite a bit of latency, sometimes so much that guests cancel a submitted transfer because they think it has timed out while we simply have not gotten around to handling it. This patch fixes this issue by speeding up resets in a number of ways: 1) Keep track of a reset state, if the device was reset and no requests were send to it since, this is true. In this case further resets are treated as a no-op. 2) Since the first thing most guests do is a reset, do one as soon as we open the device. 3) Remove the sleep we had in our reset code, as it is not necessary, actually the kernel already fires multiple commands to the device before the libusb_reset_device call returns... Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'usbredirhost/usbredirhost.c')
-rw-r--r--usbredirhost/usbredirhost.c34
1 files changed, 29 insertions, 5 deletions
diff --git a/usbredirhost/usbredirhost.c b/usbredirhost/usbredirhost.c
index d54bac3..1dfaee1 100644
--- a/usbredirhost/usbredirhost.c
+++ b/usbredirhost/usbredirhost.c
@@ -112,6 +112,7 @@ struct usbredirhost {
struct libusb_config_descriptor *config;
int restore_config;
int claimed;
+ int reset;
int disconnected;
int read_status;
int cancels_pending;
@@ -372,7 +373,7 @@ static void usbredirhost_send_device_connect(struct usbredirhost *host)
usbredirhost_send_interface_n_ep_info(host);
usbredirparser_send_device_connect(host->parser, &device_connect);
host->connect_pending = 0;
- host->disconnected = 0; /* The guest know may use the device */
+ host->disconnected = 0; /* The guest may now use the device */
FLUSH(host);
}
@@ -681,7 +682,7 @@ void usbredirhost_close(struct usbredirhost *host)
int usbredirhost_set_device(struct usbredirhost *host,
libusb_device_handle *usb_dev_handle)
{
- int status;
+ int r, status;
usbredirhost_clear_device(host);
@@ -697,6 +698,15 @@ int usbredirhost_set_device(struct usbredirhost *host,
return status;
}
+ /* The first thing almost any usb-guest does is a (slow) device-reset
+ so lets do that before hand */
+ r = libusb_reset_device(host->handle);
+ if (r != 0) {
+ usbredirhost_clear_device(host);
+ return libusb_status_or_error_to_redir_status(host, r);
+ }
+ host->reset = 1;
+
usbredirhost_send_device_connect(host);
return usb_redir_success;
@@ -1405,14 +1415,13 @@ static void usbredirhost_reset(void *priv)
struct usbredirhost *host = priv;
int r;
- if (host->disconnected) {
+ if (host->disconnected || host->reset) {
return;
}
r = libusb_reset_device(host->handle);
if (r == 0) {
- /* Some devices need some time to settle before firing more cmds */
- usleep(100000);
+ host->reset = 1;
} else {
ERROR("resetting device: %d", r);
usbredirhost_clear_device(host);
@@ -1439,6 +1448,8 @@ static void usbredirhost_set_configuration(void *priv, uint32_t id,
goto exit;
}
+ host->reset = 0;
+
usbredirhost_cancel_pending_urbs(host);
usbredirhost_release(host, 0);
@@ -1502,6 +1513,8 @@ static void usbredirhost_set_alt_setting(void *priv, uint32_t id,
goto exit_unknown_interface;
}
+ host->reset = 0;
+
usbredirhost_cancel_pending_urbs_on_interface(host, i);
r = libusb_set_interface_alt_setting(host->handle,
@@ -1592,6 +1605,8 @@ static void usbredirhost_start_iso_stream(void *priv, uint32_t id,
goto leave;
}
+ host->reset = 0;
+
/* For input endpoints submit the transfers now */
if (start_iso_stream->endpoint & LIBUSB_ENDPOINT_IN) {
for (i = 0; i < host->endpoint[EP2I(ep)].iso_transfer_count; i++) {
@@ -1656,6 +1671,9 @@ static void usbredirhost_start_interrupt_receiving(void *priv, uint32_t id,
status = usb_redir_stall;
goto leave;
}
+
+ host->reset = 0;
+
status = usbredirhost_submit_interrupt_in_transfer(host, ep);
leave:
UNLOCK(host);
@@ -1843,6 +1861,8 @@ static void usbredirhost_control_packet(void *priv, uint32_t id,
return;
}
+ host->reset = 0;
+
/* If it is a clear stall, we need to do an actual clear stall, rather then
just forward the control packet, so that the usbhost usbstack knows
the stall is cleared */
@@ -1987,6 +2007,8 @@ static void usbredirhost_bulk_packet(void *priv, uint32_t id,
return;
}
+ host->reset = 0;
+
libusb_fill_bulk_transfer(transfer->transfer, host->handle, ep,
data, bulk_packet->length,
usbredirhost_bulk_packet_complete,
@@ -2172,6 +2194,8 @@ static void usbredirhost_interrupt_packet(void *priv, uint32_t id,
return;
}
+ host->reset = 0;
+
libusb_fill_interrupt_transfer(transfer->transfer, host->handle, ep,
data, data_len, usbredirhost_interrupt_packet_complete,
transfer, INTERRUPT_TIMEOUT);