summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-12-03 13:59:43 +0100
committerHans de Goede <hdegoede@redhat.com>2012-12-05 00:39:09 +0100
commit6246e17fe58271d9126c46211aa844ee3a258ac4 (patch)
tree6882a84e2f5ca78f1e225e38c5542009e5def9e7
parentb7388d9a26837d94041b798c4a98825cc0448ea7 (diff)
usbredirhost: Use multiple transfers for interrupt receiving
To ensure we don't loose any date when we suffer some latency in completion processing. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--ChangeLog2
-rw-r--r--usbredirhost/usbredirhost.c169
2 files changed, 35 insertions, 136 deletions
diff --git a/ChangeLog b/ChangeLog
index 3e680ce..7f9a2bc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,8 @@ usbredir-0.6 28 November 2012
-add support for buffered bulk input
-usbredirparser:
-add support for buffered bulk input
+-usbredirhost:
+ -queue multiple transfers for interrupt receiving
usbredir-0.5.3 7 October 2012
------------------------------
diff --git a/usbredirhost/usbredirhost.c b/usbredirhost/usbredirhost.c
index 9664b75..26e7e0b 100644
--- a/usbredirhost/usbredirhost.c
+++ b/usbredirhost/usbredirhost.c
@@ -38,6 +38,7 @@
#define MAX_TRANSFER_COUNT 16
#define MAX_PACKETS_PER_TRANSFER 32
+#define INTERRUPT_TRANSFER_COUNT 5
/* Special packet_idx value indicating a submitted transfer */
#define SUBMITTED_IDX -1
@@ -92,7 +93,6 @@ struct usbredirhost_ep {
int drop_packets;
int max_packetsize;
struct usbredirtransfer *transfer[MAX_TRANSFER_COUNT];
- struct usbredirtransfer *interrupt_in_transfer;
};
struct usbredirhost {
@@ -198,8 +198,8 @@ static void usbredirhost_interrupt_packet(void *priv, uint64_t id,
static void LIBUSB_CALL usbredirhost_iso_packet_complete(
struct libusb_transfer *libusb_transfer);
-static void usbredirhost_cancel_interrupt_in_transfer_unlocked(
- struct usbredirhost *host, uint8_t ep);
+static void LIBUSB_CALL usbredirhost_interrupt_packet_complete(
+ struct libusb_transfer *libusb_transfer);
static int usbredirhost_cancel_pending_urbs(struct usbredirhost *host);
static void usbredirhost_clear_device(struct usbredirhost *host);
@@ -983,6 +983,12 @@ static int usbredirhost_alloc_stream_unlocked(struct usbredirhost *host,
host->endpoint[EP2I(ep)].transfer[i]->transfer,
host->endpoint[EP2I(ep)].max_packetsize);
break;
+ case usb_redir_type_interrupt:
+ libusb_fill_interrupt_transfer(
+ host->endpoint[EP2I(ep)].transfer[i]->transfer, host->handle,
+ ep, buffer, buf_size, usbredirhost_interrupt_packet_complete,
+ host->endpoint[EP2I(ep)].transfer[i], INTERRUPT_TIMEOUT);
+ break;
}
}
host->endpoint[EP2I(ep)].out_idx = 0;
@@ -1029,16 +1035,7 @@ static int usbredirhost_cancel_pending_urbs(struct usbredirhost *host)
LOCK(host);
for (i = 0; i < MAX_ENDPOINTS; i++) {
- switch (host->endpoint[i].type) {
- case usb_redir_type_iso:
- usbredirhost_cancel_stream_unlocked(host, I2EP(i));
- break;
- case usb_redir_type_interrupt:
- if (i & 0x10)
- usbredirhost_cancel_interrupt_in_transfer_unlocked(host,
- I2EP(i));
- break;
- }
+ usbredirhost_cancel_stream_unlocked(host, I2EP(i));
}
wait = host->cancels_pending;
@@ -1064,15 +1061,7 @@ static void usbredirhost_cancel_pending_urbs_on_interface(
for (i = 0; i < intf_desc->bNumEndpoints; i++) {
uint8_t ep = intf_desc->endpoint[i].bEndpointAddress;
- switch (host->endpoint[EP2I(ep)].type) {
- case usb_redir_type_iso:
- usbredirhost_cancel_stream_unlocked(host, ep);
- break;
- case usb_redir_type_interrupt:
- if (ep & LIBUSB_ENDPOINT_IN)
- usbredirhost_cancel_interrupt_in_transfer_unlocked(host, ep);
- break;
- }
+ usbredirhost_cancel_stream_unlocked(host, ep);
for (t = host->transfers_head.next; t; t = t->next) {
if (t->transfer->endpoint == ep)
@@ -1309,7 +1298,7 @@ unlock:
/**************************************************************************/
-static void usbredirhost_send_interrupt_recv_status(struct usbredirhost *host,
+static void usbredirhost_send_int_status(struct usbredirhost *host,
uint64_t id, uint8_t endpoint, uint8_t status)
{
struct usb_redir_interrupt_receiving_status_header interrupt_status;
@@ -1320,24 +1309,6 @@ static void usbredirhost_send_interrupt_recv_status(struct usbredirhost *host,
&interrupt_status);
}
-static int usbredirhost_submit_interrupt_in_transfer(struct usbredirhost *host,
- uint8_t ep)
-{
- int r;
- struct usbredirtransfer *transfer;
-
- transfer = host->endpoint[EP2I(ep)].interrupt_in_transfer;
- r = libusb_submit_transfer(transfer->transfer);
- if (r < 0) {
- ERROR("error submitting interrupt transfer on ep %02X: %s", ep,
- libusb_error_name(r));
- usbredirhost_free_transfer(transfer);
- host->endpoint[EP2I(ep)].interrupt_in_transfer = NULL;
- return usb_redir_stall;
- }
- return usb_redir_success;
-}
-
static void LIBUSB_CALL usbredirhost_interrupt_packet_complete(
struct libusb_transfer *libusb_transfer)
{
@@ -1345,6 +1316,7 @@ static void LIBUSB_CALL usbredirhost_interrupt_packet_complete(
uint8_t ep = libusb_transfer->endpoint;
struct usb_redir_interrupt_packet_header interrupt_packet;
struct usbredirhost *host = transfer->host;
+ uint64_t id = transfer->id;
int len, status, r;
status = libusb_status_or_error_to_redir_status(host,
@@ -1374,6 +1346,9 @@ static void LIBUSB_CALL usbredirhost_interrupt_packet_complete(
goto unlock;
}
+ /* Mark transfer completed (iow not submitted) */
+ transfer->packet_idx = 0;
+
usbredirhost_log_data(host, "interrupt data in:",
libusb_transfer->buffer, len);
r = libusb_transfer->status;
@@ -1382,21 +1357,21 @@ static void LIBUSB_CALL usbredirhost_interrupt_packet_complete(
break;
case LIBUSB_TRANSFER_STALL:
WARNING("interrupt endpoint %02X stalled, clearing stall", ep);
+ usbredirhost_cancel_stream_unlocked(host, ep);
r = libusb_clear_halt(host->handle, ep);
if (r < 0) {
- /* Failed to clear stall, stop receiving */
- usbredirhost_send_interrupt_recv_status(host, transfer->id, ep,
- usb_redir_stall);
- usbredirhost_free_transfer(transfer);
- host->endpoint[EP2I(ep)].interrupt_in_transfer = NULL;
+ usbredirhost_send_int_status(host, id, ep, usb_redir_stall);
goto unlock;
}
- transfer->id = 0;
- goto resubmit;
+ status = usbredirhost_alloc_stream_unlocked(host, ep,
+ usb_redir_type_interrupt,
+ 1, INTERRUPT_TRANSFER_COUNT);
+ if (status != usb_redir_success) {
+ usbredirhost_send_int_status(host, id, ep, status);
+ }
+ goto unlock;
case LIBUSB_TRANSFER_NO_DEVICE:
usbredirhost_handle_disconnect(host);
- usbredirhost_free_transfer(transfer);
- host->endpoint[EP2I(ep)].interrupt_in_transfer = NULL;
goto unlock;
default:
ERROR("interrupt in error on endpoint %02X: %d", ep, r);
@@ -1408,71 +1383,17 @@ static void LIBUSB_CALL usbredirhost_interrupt_packet_complete(
interrupt_packet.length = len;
usbredirparser_send_interrupt_packet(host->parser, transfer->id,
&interrupt_packet, transfer->transfer->buffer, len);
- transfer->id++;
+ transfer->id += host->endpoint[EP2I(ep)].transfer_count;
-resubmit:
- status = usbredirhost_submit_interrupt_in_transfer(host, ep);
+ status = usbredirhost_submit_stream_transfer_unlocked(host, transfer);
if (status != usb_redir_success) {
- usbredirhost_send_interrupt_recv_status(host, transfer->id, ep,
- status);
+ usbredirhost_send_int_status(host, id, ep, usb_redir_stall);
}
unlock:
UNLOCK(host);
FLUSH(host);
}
-static int usbredirhost_alloc_interrupt_in_transfer(struct usbredirhost *host,
- uint8_t ep)
-{
- int buf_size;
- unsigned char *buffer;
- struct usbredirtransfer *transfer;
-
- if (host->endpoint[EP2I(ep)].type != usb_redir_type_interrupt) {
- ERROR("error received start interrupt packet for non interrupt ep %02X", ep);
- return usb_redir_inval;
- }
-
- if (!(ep & LIBUSB_ENDPOINT_IN)) {
- ERROR("error received start interrupt packet for non input ep %02X", ep);
- return usb_redir_inval;
- }
-
- transfer = usbredirhost_alloc_transfer(host, 0);
- if (!transfer) {
- return usb_redir_ioerror;
- }
-
- buf_size = host->endpoint[EP2I(ep)].max_packetsize;
- buffer = malloc(buf_size);
- if (!buffer) {
- ERROR("out of memory allocating interrupt buffer");
- usbredirhost_free_transfer(transfer);
- return usb_redir_ioerror;
- }
-
- libusb_fill_interrupt_transfer(transfer->transfer, host->handle, ep,
- buffer, buf_size, usbredirhost_interrupt_packet_complete, transfer,
- INTERRUPT_TIMEOUT);
- host->endpoint[EP2I(ep)].interrupt_in_transfer = transfer;
- return usb_redir_success;
-}
-
-static void usbredirhost_cancel_interrupt_in_transfer_unlocked(
- struct usbredirhost *host, uint8_t ep)
-{
- struct usbredirtransfer *transfer;
-
- transfer = host->endpoint[EP2I(ep)].interrupt_in_transfer;
- if (!transfer)
- return; /* Already stopped */
-
- libusb_cancel_transfer(transfer->transfer);
- transfer->cancelled = 1;
- host->cancels_pending++;
- host->endpoint[EP2I(ep)].interrupt_in_transfer = NULL;
-}
-
/**************************************************************************/
static void usbredirhost_hello(void *priv, struct usb_redir_hello_header *h)
@@ -1697,31 +1618,9 @@ static void usbredirhost_start_interrupt_receiving(void *priv, uint64_t id,
uint8_t ep = start_interrupt_receiving->endpoint;
int status;
- LOCK(host);
-
- if (host->disconnected) {
- status = usb_redir_ioerror;
- goto leave;
- }
-
- if (host->endpoint[EP2I(ep)].interrupt_in_transfer) {
- ERROR("error received interrupt start for already active ep %02X", ep);
- status = usb_redir_inval;
- goto leave;
- }
-
- status = usbredirhost_alloc_interrupt_in_transfer(host, ep);
- if (status != usb_redir_success) {
- status = usb_redir_stall;
- goto leave;
- }
-
- host->reset = 0;
-
- status = usbredirhost_submit_interrupt_in_transfer(host, ep);
-leave:
- UNLOCK(host);
- usbredirhost_send_interrupt_recv_status(host, id, ep, status);
+ status = usbredirhost_alloc_stream(host, ep, usb_redir_type_interrupt,
+ 1, INTERRUPT_TRANSFER_COUNT);
+ usbredirhost_send_int_status(host, id, ep, status);
FLUSH(host);
}
@@ -1737,12 +1636,10 @@ static void usbredirhost_stop_interrupt_receiving(void *priv, uint64_t id,
goto exit;
}
- LOCK(host);
- usbredirhost_cancel_interrupt_in_transfer_unlocked(host, ep);
- UNLOCK(host);
+ usbredirhost_cancel_stream(host, ep);
exit:
- usbredirhost_send_interrupt_recv_status(host, id, ep, status);
+ usbredirhost_send_int_status(host, id, ep, status);
FLUSH(host);
}