aboutsummaryrefslogtreecommitdiff
path: root/usb-redir.c
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-02-29 09:11:00 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2012-02-29 09:11:00 -0600
commit5ca2358ac895139e624881c5b3bf3095d3cc4515 (patch)
tree18e75a6cf6e88a72a972f0a488da42753a2f0f1c /usb-redir.c
parentb55c952aea6de024bf1a06357b49367fba045443 (diff)
parent3741715cf2e54727fe3d9884ea6dcea68c7f7d4b (diff)
Merge remote-tracking branch 'kraxel/usb.39' into staging
* kraxel/usb.39: (21 commits) usb: Resolve warnings about unassigned bus on usb device creation usb-redir: Return USB_RET_NAK when we've no data for an interrupt endpoint usb-redir: Limit return values returned by iso packets usb-redir: Let the usb-host know about our device filtering usb-redir: Always clear device state on filter reject usb-redir: Fix printing of device version ehci: drop old stuff usb-ehci: Handle ISO packets failing with an error other then NAK libcacard: fix reported ATR length usb-ccid: advertise SELF_POWERED libcacard: link with glib for g_strndup usb-desc: fix user trigerrable segfaults (!config) usb-ehci: sanity-check iso xfers usb: add tracepoint for usb packet state changes. usb-xhci: enable packet queuing usb-uhci: implement packet queuing usb-uhci: process uhci_handle_td return code via switch. usb-uhci: add UHCIQueue usb-uhci: cleanup UHCIAsync allocation & initialization. usb-ehci: fix reset ...
Diffstat (limited to 'usb-redir.c')
-rw-r--r--usb-redir.c46
1 files changed, 37 insertions, 9 deletions
diff --git a/usb-redir.c b/usb-redir.c
index a59b347f01..755492f379 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -106,6 +106,7 @@ struct AsyncURB {
QTAILQ_ENTRY(AsyncURB)next;
};
+static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
static void usbredir_device_connect(void *priv,
struct usb_redir_device_connect_header *device_connect);
static void usbredir_device_disconnect(void *priv);
@@ -430,7 +431,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
/* Check iso_error for stream errors, otherwise its an underrun */
status = dev->endpoint[EP2I(ep)].iso_error;
dev->endpoint[EP2I(ep)].iso_error = 0;
- return usbredir_handle_status(dev, status, 0);
+ return status ? USB_RET_NAK : 0;
}
DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
@@ -438,7 +439,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
status = isop->status;
if (status != usb_redir_success) {
bufp_free(dev, isop, ep);
- return usbredir_handle_status(dev, status, 0);
+ return USB_RET_NAK;
}
len = isop->len;
@@ -547,7 +548,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
/* Check interrupt_error for stream errors */
status = dev->endpoint[EP2I(ep)].interrupt_error;
dev->endpoint[EP2I(ep)].interrupt_error = 0;
- return usbredir_handle_status(dev, status, 0);
+ if (status) {
+ return usbredir_handle_status(dev, status, 0);
+ }
+ return USB_RET_NAK;
}
DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
intp->status, intp->len);
@@ -802,6 +806,7 @@ static void usbredir_open_close_bh(void *opaque)
dev->parser->log_func = usbredir_log;
dev->parser->read_func = usbredir_read;
dev->parser->write_func = usbredir_write;
+ dev->parser->hello_func = usbredir_hello;
dev->parser->device_connect_func = usbredir_device_connect;
dev->parser->device_disconnect_func = usbredir_device_disconnect;
dev->parser->interface_info_func = usbredir_interface_info;
@@ -820,6 +825,7 @@ static void usbredir_open_close_bh(void *opaque)
dev->read_buf_size = 0;
usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
+ usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
usbredirparser_do_write(dev->parser);
}
@@ -958,7 +964,7 @@ static int usbredir_check_filter(USBRedirDevice *dev)
{
if (dev->interface_info.interface_count == 0) {
ERROR("No interface info for device\n");
- return -1;
+ goto error;
}
if (dev->filter_rules) {
@@ -966,7 +972,7 @@ static int usbredir_check_filter(USBRedirDevice *dev)
usb_redir_cap_connect_device_version)) {
ERROR("Device filter specified and peer does not have the "
"connect_device_version capability\n");
- return -1;
+ goto error;
}
if (usbredirfilter_check(
@@ -983,11 +989,19 @@ static int usbredir_check_filter(USBRedirDevice *dev)
dev->device_info.product_id,
dev->device_info.device_version_bcd,
0) != 0) {
- return -1;
+ goto error;
}
}
return 0;
+
+error:
+ usbredir_device_disconnect(dev);
+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
+ usbredirparser_send_filter_reject(dev->parser);
+ usbredirparser_do_write(dev->parser);
+ }
+ return -1;
}
/*
@@ -1012,6 +1026,19 @@ static int usbredir_handle_status(USBRedirDevice *dev,
}
}
+static void usbredir_hello(void *priv, struct usb_redir_hello_header *h)
+{
+ USBRedirDevice *dev = priv;
+
+ /* Try to send the filter info now that we've the usb-host's caps */
+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) &&
+ dev->filter_rules) {
+ usbredirparser_send_filter_filter(dev->parser, dev->filter_rules,
+ dev->filter_rules_count);
+ usbredirparser_do_write(dev->parser);
+ }
+}
+
static void usbredir_device_connect(void *priv,
struct usb_redir_device_connect_header *device_connect)
{
@@ -1049,8 +1076,10 @@ static void usbredir_device_connect(void *priv,
usb_redir_cap_connect_device_version)) {
INFO("attaching %s device %04x:%04x version %d.%d class %02x\n",
speed, device_connect->vendor_id, device_connect->product_id,
- device_connect->device_version_bcd >> 8,
- device_connect->device_version_bcd & 0xff,
+ ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 +
+ ((device_connect->device_version_bcd & 0x0f00) >> 8),
+ ((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 +
+ ((device_connect->device_version_bcd & 0x000f) >> 0),
device_connect->device_class);
} else {
INFO("attaching %s device %04x:%04x class %02x\n", speed,
@@ -1111,7 +1140,6 @@ static void usbredir_interface_info(void *priv,
if (usbredir_check_filter(dev)) {
ERROR("Device no longer matches filter after interface info "
"change, disconnecting!\n");
- usbredir_device_disconnect(dev);
}
}
}