summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2011-08-24 13:34:17 +0200
committerGerd Hoffmann <kraxel@redhat.com>2011-09-07 09:58:12 +0200
commit9516bb4772815f3bbf94d4779905681a7d254850 (patch)
tree2bb5ab75137086aa7be0f13fc642286f0122f88d
parenteb7700bb999544151d6e4350362b9b6d9d20abe8 (diff)
downloadqemu-9516bb4772815f3bbf94d4779905681a7d254850.tar.gz
usb-host: claim port
When configured to pass through a specific host port (using hostbus and hostport properties), try to claim the port if supported by the kernel. That will avoid any kernel drivers binding to devices plugged into that port. It will not stop any userspace apps (such as usb_modeswitch) access the device via usbfs though. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-rw-r--r--trace-events1
-rw-r--r--usb-linux.c57
2 files changed, 58 insertions, 0 deletions
diff --git a/trace-events b/trace-events
index e473aef829..a6e0cb4c48 100644
--- a/trace-events
+++ b/trace-events
@@ -263,6 +263,7 @@ usb_host_ep_stop_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
usb_host_reset(int bus, int addr) "dev %d:%d"
usb_host_auto_scan_enabled(void)
usb_host_auto_scan_disabled(void)
+usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
# hw/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
diff --git a/usb-linux.c b/usb-linux.c
index a903023847..ce0eaddefb 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -115,6 +115,7 @@ struct USBAutoFilter {
typedef struct USBHostDevice {
USBDevice dev;
int fd;
+ int hub_fd;
uint8_t descr[8192];
int descr_len;
@@ -525,6 +526,9 @@ static void usb_host_handle_destroy(USBDevice *dev)
USBHostDevice *s = (USBHostDevice *)dev;
usb_host_close(s);
+ if (s->hub_fd != -1) {
+ close(s->hub_fd);
+ }
QTAILQ_REMOVE(&hostdevs, s, next);
qemu_remove_exit_notifier(&s->exit);
}
@@ -1266,10 +1270,63 @@ static int usb_host_initfn(USBDevice *dev)
dev->auto_attach = 0;
s->fd = -1;
+ s->hub_fd = -1;
+
QTAILQ_INSERT_TAIL(&hostdevs, s, next);
s->exit.notify = usb_host_exit_notifier;
qemu_add_exit_notifier(&s->exit);
usb_host_auto_check(NULL);
+
+#ifdef USBDEVFS_CLAIM_PORT
+ if (s->match.bus_num != 0 && s->match.port != NULL) {
+ char *h, hub_name[64], line[1024];
+ int hub_addr, portnr, ret;
+
+ snprintf(hub_name, sizeof(hub_name), "%d-%s",
+ s->match.bus_num, s->match.port);
+
+ /* try strip off last ".$portnr" to get hub */
+ h = strrchr(hub_name, '.');
+ if (h != NULL) {
+ portnr = atoi(h+1);
+ *h = '\0';
+ } else {
+ /* no dot in there -> it is the root hub */
+ snprintf(hub_name, sizeof(hub_name), "usb%d",
+ s->match.bus_num);
+ portnr = atoi(s->match.port);
+ }
+
+ if (!usb_host_read_file(line, sizeof(line), "devnum",
+ hub_name)) {
+ goto out;
+ }
+ if (sscanf(line, "%d", &hub_addr) != 1) {
+ goto out;
+ }
+
+ if (!usb_host_device_path) {
+ goto out;
+ }
+ snprintf(line, sizeof(line), "%s/%03d/%03d",
+ usb_host_device_path, s->match.bus_num, hub_addr);
+ s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
+ if (s->hub_fd < 0) {
+ goto out;
+ }
+
+ ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
+ if (ret < 0) {
+ close(s->hub_fd);
+ s->hub_fd = -1;
+ goto out;
+ }
+
+ trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
+ }
+out:
+#endif
+
return 0;
}