Commit 1f3870ab242018b724b845957f7f928a2d7c1f5b

Authored by aliguori
1 parent cd01b4a3

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

I got really annoyed by the fact that you have to manually do
usb_del in the monitor when host device is unplugged and decided
to fix it :)

Basically we now automatically remove guest USB device
when the actual host device is disconnected.

At first I've extended set_fd_handlerX() stuff to support checking
for exceptions on fds. But unfortunately usbfs code does not wake up
user-space process when device is removed, which means we need a
timer to periodically check if device is still there. So I removed
fd exception stuff and implemented it with the timer.

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@5047 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 3 changed files with 66 additions and 17 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_del_addr(int bus_num, int addr);
200 void usb_attach(USBPort *port, USBDevice *dev); 201 void usb_attach(USBPort *port, USBDevice *dev);
201 int usb_generic_handle_packet(USBDevice *s, USBPacket *p); 202 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
202 int set_usb_string(uint8_t *buf, const char *str); 203 int set_usb_string(uint8_t *buf, const char *str);
usb-linux.c
@@ -22,6 +22,7 @@ @@ -22,6 +22,7 @@
22 * THE SOFTWARE. 22 * THE SOFTWARE.
23 */ 23 */
24 #include "qemu-common.h" 24 #include "qemu-common.h"
  25 +#include "qemu-timer.h"
25 #include "hw/usb.h" 26 #include "hw/usb.h"
26 #include "console.h" 27 #include "console.h"
27 28
@@ -77,6 +78,7 @@ typedef struct USBHostDevice { @@ -77,6 +78,7 @@ typedef struct USBHostDevice {
77 uint8_t descr[1024]; 78 uint8_t descr[1024];
78 int descr_len; 79 int descr_len;
79 int urbs_ready; 80 int urbs_ready;
  81 + QEMUTimer *timer;
80 } USBHostDevice; 82 } USBHostDevice;
81 83
82 typedef struct PendingURB { 84 typedef struct PendingURB {
@@ -165,7 +167,11 @@ static int usb_host_update_interfaces(USBHostDevice *dev, int configuration) @@ -165,7 +167,11 @@ static int usb_host_update_interfaces(USBHostDevice *dev, int configuration)
165 } 167 }
166 config_descr_len = dev->descr[i]; 168 config_descr_len = dev->descr[i];
167 169
168 - if (configuration == dev->descr[i + 5]) 170 +#ifdef DEBUG
  171 + printf("config #%d need %d\n", dev->descr[i + 5], configuration);
  172 +#endif
  173 +
  174 + if (configuration < 0 || configuration == dev->descr[i + 5])
169 break; 175 break;
170 176
171 i += config_descr_len; 177 i += config_descr_len;
@@ -230,8 +236,11 @@ static void usb_host_handle_destroy(USBDevice *dev) @@ -230,8 +236,11 @@ static void usb_host_handle_destroy(USBDevice *dev)
230 { 236 {
231 USBHostDevice *s = (USBHostDevice *)dev; 237 USBHostDevice *s = (USBHostDevice *)dev;
232 238
  239 + qemu_del_timer(s->timer);
  240 +
233 if (s->fd >= 0) 241 if (s->fd >= 0)
234 close(s->fd); 242 close(s->fd);
  243 +
235 qemu_free(s); 244 qemu_free(s);
236 } 245 }
237 246
@@ -594,6 +603,22 @@ static int usb_linux_update_endp_table(USBHostDevice *s) @@ -594,6 +603,22 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
594 return 0; 603 return 0;
595 } 604 }
596 605
  606 +static void usb_host_device_check(void *priv)
  607 +{
  608 + USBHostDevice *s = priv;
  609 + struct usbdevfs_connectinfo ci;
  610 + int err;
  611 +
  612 + err = ioctl(s->fd, USBDEVFS_CONNECTINFO, &ci);
  613 + if (err < 0) {
  614 + printf("usb device %d.%d disconnected\n", 0, s->dev.addr);
  615 + usb_device_del_addr(0, s->dev.addr);
  616 + return;
  617 + }
  618 +
  619 + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
  620 +}
  621 +
597 /* XXX: exclude high speed devices or implement EHCI */ 622 /* XXX: exclude high speed devices or implement EHCI */
598 USBDevice *usb_host_device_open(const char *devname) 623 USBDevice *usb_host_device_open(const char *devname)
599 { 624 {
@@ -604,24 +629,30 @@ USBDevice *usb_host_device_open(const char *devname) @@ -604,24 +629,30 @@ USBDevice *usb_host_device_open(const char *devname)
604 int bus_num, addr; 629 int bus_num, addr;
605 char product_name[PRODUCT_NAME_SZ]; 630 char product_name[PRODUCT_NAME_SZ];
606 631
  632 + if (usb_host_find_device(&bus_num, &addr,
  633 + product_name, sizeof(product_name),
  634 + devname) < 0)
  635 + return NULL;
  636 +
  637 +
607 dev = qemu_mallocz(sizeof(USBHostDevice)); 638 dev = qemu_mallocz(sizeof(USBHostDevice));
608 if (!dev) 639 if (!dev)
609 goto fail; 640 goto fail;
610 641
611 -#ifdef DEBUG_ISOCH 642 + dev->timer = qemu_new_timer(rt_clock, usb_host_device_check, (void *) dev);
  643 + if (!dev->timer)
  644 + goto fail;
  645 +
  646 +#ifdef DEBUG
612 printf("usb_host_device_open %s\n", devname); 647 printf("usb_host_device_open %s\n", devname);
613 #endif 648 #endif
614 - if (usb_host_find_device(&bus_num, &addr,  
615 - product_name, sizeof(product_name),  
616 - devname) < 0)  
617 - return NULL;  
618 649
619 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 650 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
620 bus_num, addr); 651 bus_num, addr);
621 fd = open(buf, O_RDWR | O_NONBLOCK); 652 fd = open(buf, O_RDWR | O_NONBLOCK);
622 if (fd < 0) { 653 if (fd < 0) {
623 perror(buf); 654 perror(buf);
624 - return NULL; 655 + goto fail;
625 } 656 }
626 657
627 /* read the device description */ 658 /* read the device description */
@@ -645,7 +676,7 @@ USBDevice *usb_host_device_open(const char *devname) @@ -645,7 +676,7 @@ USBDevice *usb_host_device_open(const char *devname)
645 dev->configuration = 1; 676 dev->configuration = 1;
646 677
647 /* XXX - do something about initial configuration */ 678 /* XXX - do something about initial configuration */
648 - if (!usb_host_update_interfaces(dev, 1)) 679 + if (!usb_host_update_interfaces(dev, -1))
649 goto fail; 680 goto fail;
650 681
651 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); 682 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
@@ -700,11 +731,18 @@ USBDevice *usb_host_device_open(const char *devname) @@ -700,11 +731,18 @@ USBDevice *usb_host_device_open(const char *devname)
700 fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK); 731 fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK);
701 qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev); 732 qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev);
702 #endif 733 #endif
  734 +
  735 + /* Start the timer to detect disconnect */
  736 + qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000);
  737 +
703 dev->urbs_ready = 0; 738 dev->urbs_ready = 0;
704 return (USBDevice *)dev; 739 return (USBDevice *)dev;
705 fail: 740 fail:
706 - if (dev) 741 + if (dev) {
  742 + if (dev->timer)
  743 + qemu_del_timer(dev->timer);
707 qemu_free(dev); 744 qemu_free(dev);
  745 + }
708 close(fd); 746 close(fd);
709 return NULL; 747 return NULL;
710 } 748 }
@@ -5809,22 +5809,15 @@ static int usb_device_add(const char *devname) @@ -5809,22 +5809,15 @@ static int usb_device_add(const char *devname)
5809 return 0; 5809 return 0;
5810 } 5810 }
5811 5811
5812 -static int usb_device_del(const char *devname) 5812 +int usb_device_del_addr(int bus_num, int addr)
5813 { 5813 {
5814 USBPort *port; 5814 USBPort *port;
5815 USBPort **lastp; 5815 USBPort **lastp;
5816 USBDevice *dev; 5816 USBDevice *dev;
5817 - int bus_num, addr;  
5818 - const char *p;  
5819 5817
5820 if (!used_usb_ports) 5818 if (!used_usb_ports)
5821 return -1; 5819 return -1;
5822 5820
5823 - p = strchr(devname, '.');  
5824 - if (!p)  
5825 - return -1;  
5826 - bus_num = strtoul(devname, NULL, 0);  
5827 - addr = strtoul(p + 1, NULL, 0);  
5828 if (bus_num != 0) 5821 if (bus_num != 0)
5829 return -1; 5822 return -1;
5830 5823
@@ -5847,6 +5840,23 @@ static int usb_device_del(const char *devname) @@ -5847,6 +5840,23 @@ static int usb_device_del(const char *devname)
5847 return 0; 5840 return 0;
5848 } 5841 }
5849 5842
  5843 +static int usb_device_del(const char *devname)
  5844 +{
  5845 + int bus_num, addr;
  5846 + const char *p;
  5847 +
  5848 + if (!used_usb_ports)
  5849 + return -1;
  5850 +
  5851 + p = strchr(devname, '.');
  5852 + if (!p)
  5853 + return -1;
  5854 + bus_num = strtoul(devname, NULL, 0);
  5855 + addr = strtoul(p + 1, NULL, 0);
  5856 +
  5857 + return usb_device_del_addr(bus_num, addr);
  5858 +}
  5859 +
5850 void do_usb_add(const char *devname) 5860 void do_usb_add(const char *devname)
5851 { 5861 {
5852 int ret; 5862 int ret;