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 197 p->cancel_cb(p, p->cancel_opaque);
198 198 }
199 199  
  200 +int usb_device_del_addr(int bus_num, int addr);
200 201 void usb_attach(USBPort *port, USBDevice *dev);
201 202 int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
202 203 int set_usb_string(uint8_t *buf, const char *str);
... ...
usb-linux.c
... ... @@ -22,6 +22,7 @@
22 22 * THE SOFTWARE.
23 23 */
24 24 #include "qemu-common.h"
  25 +#include "qemu-timer.h"
25 26 #include "hw/usb.h"
26 27 #include "console.h"
27 28  
... ... @@ -77,6 +78,7 @@ typedef struct USBHostDevice {
77 78 uint8_t descr[1024];
78 79 int descr_len;
79 80 int urbs_ready;
  81 + QEMUTimer *timer;
80 82 } USBHostDevice;
81 83  
82 84 typedef struct PendingURB {
... ... @@ -165,7 +167,11 @@ static int usb_host_update_interfaces(USBHostDevice *dev, int configuration)
165 167 }
166 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 175 break;
170 176  
171 177 i += config_descr_len;
... ... @@ -230,8 +236,11 @@ static void usb_host_handle_destroy(USBDevice *dev)
230 236 {
231 237 USBHostDevice *s = (USBHostDevice *)dev;
232 238  
  239 + qemu_del_timer(s->timer);
  240 +
233 241 if (s->fd >= 0)
234 242 close(s->fd);
  243 +
235 244 qemu_free(s);
236 245 }
237 246  
... ... @@ -594,6 +603,22 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
594 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 622 /* XXX: exclude high speed devices or implement EHCI */
598 623 USBDevice *usb_host_device_open(const char *devname)
599 624 {
... ... @@ -604,24 +629,30 @@ USBDevice *usb_host_device_open(const char *devname)
604 629 int bus_num, addr;
605 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 638 dev = qemu_mallocz(sizeof(USBHostDevice));
608 639 if (!dev)
609 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 647 printf("usb_host_device_open %s\n", devname);
613 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 650 snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
620 651 bus_num, addr);
621 652 fd = open(buf, O_RDWR | O_NONBLOCK);
622 653 if (fd < 0) {
623 654 perror(buf);
624   - return NULL;
  655 + goto fail;
625 656 }
626 657  
627 658 /* read the device description */
... ... @@ -645,7 +676,7 @@ USBDevice *usb_host_device_open(const char *devname)
645 676 dev->configuration = 1;
646 677  
647 678 /* XXX - do something about initial configuration */
648   - if (!usb_host_update_interfaces(dev, 1))
  679 + if (!usb_host_update_interfaces(dev, -1))
649 680 goto fail;
650 681  
651 682 ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
... ... @@ -700,11 +731,18 @@ USBDevice *usb_host_device_open(const char *devname)
700 731 fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK);
701 732 qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev);
702 733 #endif
  734 +
  735 + /* Start the timer to detect disconnect */
  736 + qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000);
  737 +
703 738 dev->urbs_ready = 0;
704 739 return (USBDevice *)dev;
705 740 fail:
706   - if (dev)
  741 + if (dev) {
  742 + if (dev->timer)
  743 + qemu_del_timer(dev->timer);
707 744 qemu_free(dev);
  745 + }
708 746 close(fd);
709 747 return NULL;
710 748 }
... ...
... ... @@ -5809,22 +5809,15 @@ static int usb_device_add(const char *devname)
5809 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 5814 USBPort *port;
5815 5815 USBPort **lastp;
5816 5816 USBDevice *dev;
5817   - int bus_num, addr;
5818   - const char *p;
5819 5817  
5820 5818 if (!used_usb_ports)
5821 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 5821 if (bus_num != 0)
5829 5822 return -1;
5830 5823  
... ... @@ -5847,6 +5840,23 @@ static int usb_device_del(const char *devname)
5847 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 5860 void do_usb_add(const char *devname)
5851 5861 {
5852 5862 int ret;
... ...