Commit 4b096fc9ec486590ca71dc78eaa58ecbd622a938

Authored by aliguori
1 parent 1f3870ab

husb: support for USB host device auto connect (Max Krasnyansky)

QEMU can now automatically grab host USB devices that match the filter.
For now I just extended 'host:X.Y' and 'host:VID:PID' syntax to handle
wildcards. So for example if you do something like
   usb_add host:5.*
QEMU will automatically grab any non-hub device with host address 5.*.

Same with the 'host:PID:*', we grab any device that matches PID.

Filtering itself is very generic so we can probably add more elaborate
syntax like 'host:BUS.ADDR:VID:PID'. So that we can do 'host:5.*:6000:*'.

Anyway, it's implemented using a periodic timer that scans host devices
and grabs those that match the filter. Timer is started when the first
filter is added.

We now keep the list of all host devices that we grabbed to make sure that
we do not grab the same device twice.

btw It's currently possible to grab the same host device more than once.
ie You can just do "usb_add host:1.1" more than once, which of course does
not work. So this patch fixes that issue too.

Along with auto disconnect patch that I send a minute ago the setup is very
seamless now. You can just allocate some usb ports to the VMs and plug/unplug
devices at any time.

Signed-off-by: Max Krasnyansky <maxk@kernel.org>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5048 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 3 changed files with 225 additions and 42 deletions
hw/usb.h
@@ -197,6 +197,7 @@ static inline void usb_cancel_packet(USBPacket * p) @@ -197,6 +197,7 @@ static inline void usb_cancel_packet(USBPacket * p)
197 p->cancel_cb(p, p->cancel_opaque); 197 p->cancel_cb(p, p->cancel_opaque);
198 } 198 }
199 199
  200 +int usb_device_add_dev(USBDevice *dev);
200 int usb_device_del_addr(int bus_num, int addr); 201 int usb_device_del_addr(int bus_num, int addr);
201 void usb_attach(USBPort *port, USBDevice *dev); 202 void usb_attach(USBPort *port, USBDevice *dev);
202 int usb_generic_handle_packet(USBDevice *s, USBPacket *p); 203 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
usb-linux.c
@@ -3,6 +3,9 @@ @@ -3,6 +3,9 @@
3 * 3 *
4 * Copyright (c) 2005 Fabrice Bellard 4 * Copyright (c) 2005 Fabrice Bellard
5 * 5 *
  6 + * Support for host device auto connect & disconnect
  7 + * Copyright (c) 2008 Max Krasnyansky
  8 + *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal 10 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights 11 * in the Software without restriction, including without limitation the rights
@@ -67,6 +70,8 @@ struct endp_data { @@ -67,6 +70,8 @@ struct endp_data {
67 uint8_t type; 70 uint8_t type;
68 }; 71 };
69 72
  73 +
  74 +
70 /* FIXME: move USBPacket to PendingURB */ 75 /* FIXME: move USBPacket to PendingURB */
71 typedef struct USBHostDevice { 76 typedef struct USBHostDevice {
72 USBDevice dev; 77 USBDevice dev;
@@ -78,9 +83,51 @@ typedef struct USBHostDevice { @@ -78,9 +83,51 @@ typedef struct USBHostDevice {
78 uint8_t descr[1024]; 83 uint8_t descr[1024];
79 int descr_len; 84 int descr_len;
80 int urbs_ready; 85 int urbs_ready;
  86 +
81 QEMUTimer *timer; 87 QEMUTimer *timer;
  88 +
  89 + /* Host side address */
  90 + int bus_num;
  91 + int addr;
  92 +
  93 + struct USBHostDevice *next;
82 } USBHostDevice; 94 } USBHostDevice;
83 95
  96 +static USBHostDevice *hostdev_list;
  97 +
  98 +static void hostdev_link(USBHostDevice *dev)
  99 +{
  100 + dev->next = hostdev_list;
  101 + hostdev_list = dev;
  102 +}
  103 +
  104 +static void hostdev_unlink(USBHostDevice *dev)
  105 +{
  106 + USBHostDevice *pdev = hostdev_list;
  107 + USBHostDevice **prev = &hostdev_list;
  108 +
  109 + while (pdev) {
  110 + if (pdev == dev) {
  111 + *prev = dev->next;
  112 + return;
  113 + }
  114 +
  115 + prev = &pdev->next;
  116 + pdev = pdev->next;
  117 + }
  118 +}
  119 +
  120 +static USBHostDevice *hostdev_find(int bus_num, int addr)
  121 +{
  122 + USBHostDevice *s = hostdev_list;
  123 + while (s) {
  124 + if (s->bus_num == bus_num && s->addr == addr)
  125 + return s;
  126 + s = s->next;
  127 + }
  128 + return NULL;
  129 +}
  130 +
84 typedef struct PendingURB { 131 typedef struct PendingURB {
85 struct usbdevfs_urb *urb; 132 struct usbdevfs_urb *urb;
86 int status; 133 int status;
@@ -238,6 +285,8 @@ static void usb_host_handle_destroy(USBDevice *dev) @@ -238,6 +285,8 @@ static void usb_host_handle_destroy(USBDevice *dev)
238 285
239 qemu_del_timer(s->timer); 286 qemu_del_timer(s->timer);
240 287
  288 + hostdev_unlink(s);
  289 +
241 if (s->fd >= 0) 290 if (s->fd >= 0)
242 close(s->fd); 291 close(s->fd);
243 292
@@ -619,32 +668,26 @@ static void usb_host_device_check(void *priv) @@ -619,32 +668,26 @@ static void usb_host_device_check(void *priv)
619 qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000); 668 qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
620 } 669 }
621 670
622 -/* XXX: exclude high speed devices or implement EHCI */  
623 -USBDevice *usb_host_device_open(const char *devname) 671 +static USBDevice *usb_host_device_open_addr(int bus_num, int addr, const char *prod_name)
624 { 672 {
625 int fd = -1, ret; 673 int fd = -1, ret;
626 USBHostDevice *dev = NULL; 674 USBHostDevice *dev = NULL;
627 struct usbdevfs_connectinfo ci; 675 struct usbdevfs_connectinfo ci;
628 char buf[1024]; 676 char buf[1024];
629 - int bus_num, addr;  
630 - char product_name[PRODUCT_NAME_SZ];  
631 -  
632 - if (usb_host_find_device(&bus_num, &addr,  
633 - product_name, sizeof(product_name),  
634 - devname) < 0)  
635 - return NULL;  
636 -  
637 677
638 dev = qemu_mallocz(sizeof(USBHostDevice)); 678 dev = qemu_mallocz(sizeof(USBHostDevice));
639 if (!dev) 679 if (!dev)
640 goto fail; 680 goto fail;
641 681
  682 + dev->bus_num = bus_num;
  683 + dev->addr = addr;
  684 +
642 dev->timer = qemu_new_timer(rt_clock, usb_host_device_check, (void *) dev); 685 dev->timer = qemu_new_timer(rt_clock, usb_host_device_check, (void *) dev);
643 if (!dev->timer) 686 if (!dev->timer)
644 goto fail; 687 goto fail;
645 688
646 #ifdef DEBUG 689 #ifdef DEBUG
647 - printf("usb_host_device_open %s\n", devname); 690 + printf("usb_host_device_open %d.%d\n", bus_num, addr);
648 #endif 691 #endif
649 692
650 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 693 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
@@ -704,12 +747,12 @@ USBDevice *usb_host_device_open(const char *devname) @@ -704,12 +747,12 @@ USBDevice *usb_host_device_open(const char *devname)
704 dev->dev.handle_data = usb_host_handle_data; 747 dev->dev.handle_data = usb_host_handle_data;
705 dev->dev.handle_destroy = usb_host_handle_destroy; 748 dev->dev.handle_destroy = usb_host_handle_destroy;
706 749
707 - if (product_name[0] == '\0') 750 + if (!prod_name || prod_name[0] == '\0')
708 snprintf(dev->dev.devname, sizeof(dev->dev.devname), 751 snprintf(dev->dev.devname, sizeof(dev->dev.devname),
709 - "host:%s", devname); 752 + "host:%d.%d", bus_num, addr);
710 else 753 else
711 pstrcpy(dev->dev.devname, sizeof(dev->dev.devname), 754 pstrcpy(dev->dev.devname, sizeof(dev->dev.devname),
712 - product_name); 755 + prod_name);
713 756
714 #ifdef USE_ASYNCIO 757 #ifdef USE_ASYNCIO
715 /* set up the signal handlers */ 758 /* set up the signal handlers */
@@ -735,8 +778,11 @@ USBDevice *usb_host_device_open(const char *devname) @@ -735,8 +778,11 @@ USBDevice *usb_host_device_open(const char *devname)
735 /* Start the timer to detect disconnect */ 778 /* Start the timer to detect disconnect */
736 qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000); 779 qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000);
737 780
  781 + hostdev_link(dev);
  782 +
738 dev->urbs_ready = 0; 783 dev->urbs_ready = 0;
739 return (USBDevice *)dev; 784 return (USBDevice *)dev;
  785 +
740 fail: 786 fail:
741 if (dev) { 787 if (dev) {
742 if (dev->timer) 788 if (dev->timer)
@@ -747,6 +793,24 @@ fail: @@ -747,6 +793,24 @@ fail:
747 return NULL; 793 return NULL;
748 } 794 }
749 795
  796 +USBDevice *usb_host_device_open(const char *devname)
  797 +{
  798 + int bus_num, addr;
  799 + char product_name[PRODUCT_NAME_SZ];
  800 +
  801 + if (usb_host_find_device(&bus_num, &addr,
  802 + product_name, sizeof(product_name),
  803 + devname) < 0)
  804 + return NULL;
  805 +
  806 + if (hostdev_find(bus_num, addr)) {
  807 + printf("host usb device %d.%d is already open\n", bus_num, addr);
  808 + return NULL;
  809 + }
  810 +
  811 + return usb_host_device_open_addr(bus_num, addr, product_name);
  812 +}
  813 +
750 static int get_tag_value(char *buf, int buf_size, 814 static int get_tag_value(char *buf, int buf_size,
751 const char *str, const char *tag, 815 const char *str, const char *tag,
752 const char *stopchars) 816 const char *stopchars)
@@ -846,6 +910,108 @@ static int usb_host_scan(void *opaque, USBScanFunc *func) @@ -846,6 +910,108 @@ static int usb_host_scan(void *opaque, USBScanFunc *func)
846 return ret; 910 return ret;
847 } 911 }
848 912
  913 +struct USBAutoFilter {
  914 + struct USBAutoFilter *next;
  915 + int bus_num;
  916 + int addr;
  917 + int vendor_id;
  918 + int product_id;
  919 +};
  920 +
  921 +static QEMUTimer *usb_auto_timer;
  922 +static struct USBAutoFilter *usb_auto_filter;
  923 +
  924 +static int usb_host_auto_scan(void *opaque, int bus_num, int addr,
  925 + int class_id, int vendor_id, int product_id,
  926 + const char *product_name, int speed)
  927 +{
  928 + struct USBAutoFilter *f;
  929 + struct USBDevice *dev;
  930 +
  931 + /* Ignore hubs */
  932 + if (class_id == 9)
  933 + return 0;
  934 +
  935 + for (f = usb_auto_filter; f; f = f->next) {
  936 + // printf("Auto match: bus_num %d addr %d vid %d pid %d\n",
  937 + // bus_num, addr, vendor_id, product_id);
  938 +
  939 + if (f->bus_num >= 0 && f->bus_num != bus_num)
  940 + continue;
  941 +
  942 + if (f->addr >= 0 && f->addr != addr)
  943 + continue;
  944 +
  945 + if (f->vendor_id >= 0 && f->vendor_id != vendor_id)
  946 + continue;
  947 +
  948 + if (f->product_id >= 0 && f->product_id != product_id)
  949 + continue;
  950 +
  951 + /* We got a match */
  952 +
  953 + /* Allredy attached ? */
  954 + if (hostdev_find(bus_num, addr))
  955 + return 0;
  956 +
  957 + printf("Auto open: bus_num %d addr %d\n", bus_num, addr);
  958 +
  959 + dev = usb_host_device_open_addr(bus_num, addr, product_name);
  960 + if (dev)
  961 + usb_device_add_dev(dev);
  962 + }
  963 +
  964 + return 0;
  965 +}
  966 +
  967 +static void usb_host_auto_timer(void *unused)
  968 +{
  969 + usb_host_scan(NULL, usb_host_auto_scan);
  970 + qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
  971 +}
  972 +
  973 +/*
  974 + * Add autoconnect filter
  975 + * -1 means 'any' (device, vendor, etc)
  976 + */
  977 +static void usb_host_auto_add(int bus_num, int addr, int vendor_id, int product_id)
  978 +{
  979 + struct USBAutoFilter *f = qemu_mallocz(sizeof(*f));
  980 + if (!f) {
  981 + printf("Failed to allocate auto filter\n");
  982 + return;
  983 + }
  984 +
  985 + f->bus_num = bus_num;
  986 + f->addr = addr;
  987 + f->vendor_id = vendor_id;
  988 + f->product_id = product_id;
  989 +
  990 + if (!usb_auto_filter) {
  991 + /*
  992 + * First entry. Init and start the monitor.
  993 + * Right now we're using timer to check for new devices.
  994 + * If this turns out to be too expensive we can move that into a
  995 + * separate thread.
  996 + */
  997 + usb_auto_timer = qemu_new_timer(rt_clock, usb_host_auto_timer, NULL);
  998 + if (!usb_auto_timer) {
  999 + printf("Failed to allocate timer\n");
  1000 + qemu_free(f);
  1001 + return;
  1002 + }
  1003 +
  1004 + /* Check for new devices every two seconds */
  1005 + qemu_mod_timer(usb_auto_timer, qemu_get_clock(rt_clock) + 2000);
  1006 + }
  1007 +
  1008 + printf("Auto filter: bus_num %d addr %d vid %d pid %d\n",
  1009 + bus_num, addr, vendor_id, product_id);
  1010 +
  1011 + f->next = usb_auto_filter;
  1012 + usb_auto_filter = f;
  1013 +}
  1014 +
849 typedef struct FindDeviceState { 1015 typedef struct FindDeviceState {
850 int vendor_id; 1016 int vendor_id;
851 int product_id; 1017 int product_id;
@@ -887,6 +1053,12 @@ static int usb_host_find_device(int *pbus_num, int *paddr, @@ -887,6 +1053,12 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
887 p = strchr(devname, '.'); 1053 p = strchr(devname, '.');
888 if (p) { 1054 if (p) {
889 *pbus_num = strtoul(devname, NULL, 0); 1055 *pbus_num = strtoul(devname, NULL, 0);
  1056 +
  1057 + if (*(p + 1) == '*') {
  1058 + usb_host_auto_add(*pbus_num, -1, -1, -1);
  1059 + return -1;
  1060 + }
  1061 +
890 *paddr = strtoul(p + 1, NULL, 0); 1062 *paddr = strtoul(p + 1, NULL, 0);
891 fs.bus_num = *pbus_num; 1063 fs.bus_num = *pbus_num;
892 fs.addr = *paddr; 1064 fs.addr = *paddr;
@@ -898,6 +1070,12 @@ static int usb_host_find_device(int *pbus_num, int *paddr, @@ -898,6 +1070,12 @@ static int usb_host_find_device(int *pbus_num, int *paddr,
898 p = strchr(devname, ':'); 1070 p = strchr(devname, ':');
899 if (p) { 1071 if (p) {
900 fs.vendor_id = strtoul(devname, NULL, 16); 1072 fs.vendor_id = strtoul(devname, NULL, 16);
  1073 +
  1074 + if (*(p + 1) == '*') {
  1075 + usb_host_auto_add(-1, -1, fs.vendor_id, -1);
  1076 + return -1;
  1077 + }
  1078 +
901 fs.product_id = strtoul(p + 1, NULL, 16); 1079 fs.product_id = strtoul(p + 1, NULL, 16);
902 ret = usb_host_scan(&fs, usb_host_find_device_scan); 1080 ret = usb_host_scan(&fs, usb_host_find_device_scan);
903 if (ret) { 1081 if (ret) {
@@ -996,6 +1174,9 @@ void usb_host_info(void) @@ -996,6 +1174,9 @@ void usb_host_info(void)
996 usb_host_scan(NULL, usb_host_info_device); 1174 usb_host_scan(NULL, usb_host_info_device);
997 } 1175 }
998 1176
  1177 +
  1178 +
  1179 +
999 #else 1180 #else
1000 1181
1001 void usb_host_info(void) 1182 void usb_host_info(void)
@@ -5747,6 +5747,32 @@ void qemu_register_usb_port(USBPort *port, void *opaque, int index, @@ -5747,6 +5747,32 @@ void qemu_register_usb_port(USBPort *port, void *opaque, int index,
5747 free_usb_ports = port; 5747 free_usb_ports = port;
5748 } 5748 }
5749 5749
  5750 +int usb_device_add_dev(USBDevice *dev)
  5751 +{
  5752 + USBPort *port;
  5753 +
  5754 + /* Find a USB port to add the device to. */
  5755 + port = free_usb_ports;
  5756 + if (!port->next) {
  5757 + USBDevice *hub;
  5758 +
  5759 + /* Create a new hub and chain it on. */
  5760 + free_usb_ports = NULL;
  5761 + port->next = used_usb_ports;
  5762 + used_usb_ports = port;
  5763 +
  5764 + hub = usb_hub_init(VM_USB_HUB_SIZE);
  5765 + usb_attach(port, hub);
  5766 + port = free_usb_ports;
  5767 + }
  5768 +
  5769 + free_usb_ports = port->next;
  5770 + port->next = used_usb_ports;
  5771 + used_usb_ports = port;
  5772 + usb_attach(port, dev);
  5773 + return 0;
  5774 +}
  5775 +
5750 static int usb_device_add(const char *devname) 5776 static int usb_device_add(const char *devname)
5751 { 5777 {
5752 const char *p; 5778 const char *p;
@@ -5787,26 +5813,7 @@ static int usb_device_add(const char *devname) @@ -5787,26 +5813,7 @@ static int usb_device_add(const char *devname)
5787 if (!dev) 5813 if (!dev)
5788 return -1; 5814 return -1;
5789 5815
5790 - /* Find a USB port to add the device to. */  
5791 - port = free_usb_ports;  
5792 - if (!port->next) {  
5793 - USBDevice *hub;  
5794 -  
5795 - /* Create a new hub and chain it on. */  
5796 - free_usb_ports = NULL;  
5797 - port->next = used_usb_ports;  
5798 - used_usb_ports = port;  
5799 -  
5800 - hub = usb_hub_init(VM_USB_HUB_SIZE);  
5801 - usb_attach(port, hub);  
5802 - port = free_usb_ports;  
5803 - }  
5804 -  
5805 - free_usb_ports = port->next;  
5806 - port->next = used_usb_ports;  
5807 - used_usb_ports = port;  
5808 - usb_attach(port, dev);  
5809 - return 0; 5816 + return usb_device_add_dev(dev);
5810 } 5817 }
5811 5818
5812 int usb_device_del_addr(int bus_num, int addr) 5819 int usb_device_del_addr(int bus_num, int addr)
@@ -5859,18 +5866,12 @@ static int usb_device_del(const char *devname) @@ -5859,18 +5866,12 @@ static int usb_device_del(const char *devname)
5859 5866
5860 void do_usb_add(const char *devname) 5867 void do_usb_add(const char *devname)
5861 { 5868 {
5862 - int ret;  
5863 - ret = usb_device_add(devname);  
5864 - if (ret < 0)  
5865 - term_printf("Could not add USB device '%s'\n", devname); 5869 + usb_device_add(devname);
5866 } 5870 }
5867 5871
5868 void do_usb_del(const char *devname) 5872 void do_usb_del(const char *devname)
5869 { 5873 {
5870 - int ret;  
5871 - ret = usb_device_del(devname);  
5872 - if (ret < 0)  
5873 - term_printf("Could not remove USB device '%s'\n", devname); 5874 + usb_device_del(devname);
5874 } 5875 }
5875 5876
5876 void usb_info(void) 5877 void usb_info(void)