usb-host: properly release port on unplug & exit
Factor out port release into a separate function. Call release function in exit notifier too. Add explicit call the USBDEVFS_RELEASE_PORT ioctl, just closing the hub file handle seems not to be enougth. Make sure we release the port before resetting the device, otherwise host drivers will not re-attach. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
		
							parent
							
								
									24a5bbe1c8
								
							
						
					
					
						commit
						c75fead66e
					
				
							
								
								
									
										28
									
								
								usb-linux.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								usb-linux.c
									
									
									
									
									
								
							@ -116,6 +116,7 @@ typedef struct USBHostDevice {
 | 
				
			|||||||
    USBDevice dev;
 | 
					    USBDevice dev;
 | 
				
			||||||
    int       fd;
 | 
					    int       fd;
 | 
				
			||||||
    int       hub_fd;
 | 
					    int       hub_fd;
 | 
				
			||||||
 | 
					    int       hub_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t   descr[8192];
 | 
					    uint8_t   descr[8192];
 | 
				
			||||||
    int       descr_len;
 | 
					    int       descr_len;
 | 
				
			||||||
@ -434,7 +435,7 @@ static int usb_host_claim_port(USBHostDevice *s)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
#ifdef USBDEVFS_CLAIM_PORT
 | 
					#ifdef USBDEVFS_CLAIM_PORT
 | 
				
			||||||
    char *h, hub_name[64], line[1024];
 | 
					    char *h, hub_name[64], line[1024];
 | 
				
			||||||
    int hub_addr, portnr, ret;
 | 
					    int hub_addr, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    snprintf(hub_name, sizeof(hub_name), "%d-%s",
 | 
					    snprintf(hub_name, sizeof(hub_name), "%d-%s",
 | 
				
			||||||
             s->match.bus_num, s->match.port);
 | 
					             s->match.bus_num, s->match.port);
 | 
				
			||||||
@ -442,13 +443,13 @@ static int usb_host_claim_port(USBHostDevice *s)
 | 
				
			|||||||
    /* try strip off last ".$portnr" to get hub */
 | 
					    /* try strip off last ".$portnr" to get hub */
 | 
				
			||||||
    h = strrchr(hub_name, '.');
 | 
					    h = strrchr(hub_name, '.');
 | 
				
			||||||
    if (h != NULL) {
 | 
					    if (h != NULL) {
 | 
				
			||||||
        portnr = atoi(h+1);
 | 
					        s->hub_port = atoi(h+1);
 | 
				
			||||||
        *h = '\0';
 | 
					        *h = '\0';
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        /* no dot in there -> it is the root hub */
 | 
					        /* no dot in there -> it is the root hub */
 | 
				
			||||||
        snprintf(hub_name, sizeof(hub_name), "usb%d",
 | 
					        snprintf(hub_name, sizeof(hub_name), "usb%d",
 | 
				
			||||||
                 s->match.bus_num);
 | 
					                 s->match.bus_num);
 | 
				
			||||||
        portnr = atoi(s->match.port);
 | 
					        s->hub_port = atoi(s->match.port);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!usb_host_read_file(line, sizeof(line), "devnum",
 | 
					    if (!usb_host_read_file(line, sizeof(line), "devnum",
 | 
				
			||||||
@ -469,20 +470,32 @@ static int usb_host_claim_port(USBHostDevice *s)
 | 
				
			|||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &portnr);
 | 
					    ret = ioctl(s->hub_fd, USBDEVFS_CLAIM_PORT, &s->hub_port);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        close(s->hub_fd);
 | 
					        close(s->hub_fd);
 | 
				
			||||||
        s->hub_fd = -1;
 | 
					        s->hub_fd = -1;
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    trace_usb_host_claim_port(s->match.bus_num, hub_addr, portnr);
 | 
					    trace_usb_host_claim_port(s->match.bus_num, hub_addr, s->hub_port);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usb_host_release_port(USBHostDevice *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (s->hub_fd == -1) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#ifdef USBDEVFS_RELEASE_PORT
 | 
				
			||||||
 | 
					    ioctl(s->hub_fd, USBDEVFS_RELEASE_PORT, &s->hub_port);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    close(s->hub_fd);
 | 
				
			||||||
 | 
					    s->hub_fd = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
 | 
					static int usb_host_disconnect_ifaces(USBHostDevice *dev, int nb_interfaces)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* earlier Linux 2.4 do not support that */
 | 
					    /* earlier Linux 2.4 do not support that */
 | 
				
			||||||
@ -635,10 +648,8 @@ static void usb_host_handle_destroy(USBDevice *dev)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    USBHostDevice *s = (USBHostDevice *)dev;
 | 
					    USBHostDevice *s = (USBHostDevice *)dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usb_host_release_port(s);
 | 
				
			||||||
    usb_host_close(s);
 | 
					    usb_host_close(s);
 | 
				
			||||||
    if (s->hub_fd != -1) {
 | 
					 | 
				
			||||||
        close(s->hub_fd);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    QTAILQ_REMOVE(&hostdevs, s, next);
 | 
					    QTAILQ_REMOVE(&hostdevs, s, next);
 | 
				
			||||||
    qemu_remove_exit_notifier(&s->exit);
 | 
					    qemu_remove_exit_notifier(&s->exit);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1402,6 +1413,7 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    USBHostDevice *s = container_of(n, USBHostDevice, exit);
 | 
					    USBHostDevice *s = container_of(n, USBHostDevice, exit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usb_host_release_port(s);
 | 
				
			||||||
    if (s->fd != -1) {
 | 
					    if (s->fd != -1) {
 | 
				
			||||||
        usb_host_do_reset(s);;
 | 
					        usb_host_do_reset(s);;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user