From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KWFp1-0003w0-8t for qemu-devel@nongnu.org; Thu, 21 Aug 2008 15:27:51 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KWFp0-0003vo-MD for qemu-devel@nongnu.org; Thu, 21 Aug 2008 15:27:50 -0400 Received: from [199.232.76.173] (port=41418 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KWFp0-0003vl-G7 for qemu-devel@nongnu.org; Thu, 21 Aug 2008 15:27:50 -0400 Received: from savannah.gnu.org ([199.232.41.3]:51570 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1KWFp0-0005zU-Jw for qemu-devel@nongnu.org; Thu, 21 Aug 2008 15:27:50 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1KWFoz-0004vl-BH for qemu-devel@nongnu.org; Thu, 21 Aug 2008 19:27:49 +0000 Received: from aliguori by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1KWFoy-0004va-U9 for qemu-devel@nongnu.org; Thu, 21 Aug 2008 19:27:49 +0000 MIME-Version: 1.0 Errors-To: aliguori Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Anthony Liguori Message-Id: Date: Thu, 21 Aug 2008 19:27:48 +0000 Subject: [Qemu-devel] [5047] husb: support for USB host device auto disconnect (Max Krasnyansky) Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 5047 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=5047 Author: aliguori Date: 2008-08-21 19:27:48 +0000 (Thu, 21 Aug 2008) Log Message: ----------- 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 Signed-off-by: Anthony Liguori Modified Paths: -------------- trunk/hw/usb.h trunk/usb-linux.c trunk/vl.c Modified: trunk/hw/usb.h =================================================================== --- trunk/hw/usb.h 2008-08-21 19:25:45 UTC (rev 5046) +++ trunk/hw/usb.h 2008-08-21 19:27:48 UTC (rev 5047) @@ -197,6 +197,7 @@ p->cancel_cb(p, p->cancel_opaque); } +int usb_device_del_addr(int bus_num, int addr); void usb_attach(USBPort *port, USBDevice *dev); int usb_generic_handle_packet(USBDevice *s, USBPacket *p); int set_usb_string(uint8_t *buf, const char *str); Modified: trunk/usb-linux.c =================================================================== --- trunk/usb-linux.c 2008-08-21 19:25:45 UTC (rev 5046) +++ trunk/usb-linux.c 2008-08-21 19:27:48 UTC (rev 5047) @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" +#include "qemu-timer.h" #include "hw/usb.h" #include "console.h" @@ -77,6 +78,7 @@ uint8_t descr[1024]; int descr_len; int urbs_ready; + QEMUTimer *timer; } USBHostDevice; typedef struct PendingURB { @@ -165,7 +167,11 @@ } config_descr_len = dev->descr[i]; - if (configuration == dev->descr[i + 5]) +#ifdef DEBUG + printf("config #%d need %d\n", dev->descr[i + 5], configuration); +#endif + + if (configuration < 0 || configuration == dev->descr[i + 5]) break; i += config_descr_len; @@ -230,8 +236,11 @@ { USBHostDevice *s = (USBHostDevice *)dev; + qemu_del_timer(s->timer); + if (s->fd >= 0) close(s->fd); + qemu_free(s); } @@ -594,6 +603,22 @@ return 0; } +static void usb_host_device_check(void *priv) +{ + USBHostDevice *s = priv; + struct usbdevfs_connectinfo ci; + int err; + + err = ioctl(s->fd, USBDEVFS_CONNECTINFO, &ci); + if (err < 0) { + printf("usb device %d.%d disconnected\n", 0, s->dev.addr); + usb_device_del_addr(0, s->dev.addr); + return; + } + + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000); +} + /* XXX: exclude high speed devices or implement EHCI */ USBDevice *usb_host_device_open(const char *devname) { @@ -604,24 +629,30 @@ int bus_num, addr; char product_name[PRODUCT_NAME_SZ]; + if (usb_host_find_device(&bus_num, &addr, + product_name, sizeof(product_name), + devname) < 0) + return NULL; + + dev = qemu_mallocz(sizeof(USBHostDevice)); if (!dev) goto fail; -#ifdef DEBUG_ISOCH + dev->timer = qemu_new_timer(rt_clock, usb_host_device_check, (void *) dev); + if (!dev->timer) + goto fail; + +#ifdef DEBUG printf("usb_host_device_open %s\n", devname); #endif - if (usb_host_find_device(&bus_num, &addr, - product_name, sizeof(product_name), - devname) < 0) - return NULL; snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", bus_num, addr); fd = open(buf, O_RDWR | O_NONBLOCK); if (fd < 0) { perror(buf); - return NULL; + goto fail; } /* read the device description */ @@ -645,7 +676,7 @@ dev->configuration = 1; /* XXX - do something about initial configuration */ - if (!usb_host_update_interfaces(dev, 1)) + if (!usb_host_update_interfaces(dev, -1)) goto fail; ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci); @@ -700,11 +731,18 @@ fcntl(dev->pipe_fds[1], F_SETFL, O_NONBLOCK); qemu_set_fd_handler(dev->pipe_fds[0], urb_completion_pipe_read, NULL, dev); #endif + + /* Start the timer to detect disconnect */ + qemu_mod_timer(dev->timer, qemu_get_clock(rt_clock) + 1000); + dev->urbs_ready = 0; return (USBDevice *)dev; fail: - if (dev) + if (dev) { + if (dev->timer) + qemu_del_timer(dev->timer); qemu_free(dev); + } close(fd); return NULL; } Modified: trunk/vl.c =================================================================== --- trunk/vl.c 2008-08-21 19:25:45 UTC (rev 5046) +++ trunk/vl.c 2008-08-21 19:27:48 UTC (rev 5047) @@ -5809,22 +5809,15 @@ return 0; } -static int usb_device_del(const char *devname) +int usb_device_del_addr(int bus_num, int addr) { USBPort *port; USBPort **lastp; USBDevice *dev; - int bus_num, addr; - const char *p; if (!used_usb_ports) return -1; - p = strchr(devname, '.'); - if (!p) - return -1; - bus_num = strtoul(devname, NULL, 0); - addr = strtoul(p + 1, NULL, 0); if (bus_num != 0) return -1; @@ -5847,6 +5840,23 @@ return 0; } +static int usb_device_del(const char *devname) +{ + int bus_num, addr; + const char *p; + + if (!used_usb_ports) + return -1; + + p = strchr(devname, '.'); + if (!p) + return -1; + bus_num = strtoul(devname, NULL, 0); + addr = strtoul(p + 1, NULL, 0); + + return usb_device_del_addr(bus_num, addr); +} + void do_usb_add(const char *devname) { int ret;