/* "Safely remove a device" */ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct usb_device *udev = to_usb_device(dev); int rc = 0; usb_lock_device(udev); if (udev->state != USB_STATE_NOTATTACHED) { /* To avoid races, first unconfigure and then remove */ usb_set_configuration(udev, -1); rc = usb_remove_device(udev); } if (rc == 0) rc = count; usb_unlock_device(udev); return rc; }
static void usb_hub_port_connect_change(struct usb_device *dev, int port) { struct usb_device *usb; struct usb_port_status portsts; unsigned short portstatus, portchange; /* Check status */ if (usb_get_port_status(dev, port + 1, &portsts) < 0) { dev_dbg(&dev->dev, "get_port_status failed\n"); return; } portstatus = le16_to_cpu(portsts.wPortStatus); portchange = le16_to_cpu(portsts.wPortChange); dev_dbg(&dev->dev, "portstatus %x, change %x, %s\n", portstatus, portchange, portspeed(portstatus)); /* Clear the connection change status */ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION); /* Disconnect any existing devices under this port */ if (dev->children[port] && !(portstatus & USB_PORT_STAT_CONNECTION)) { dev_dbg(&dev->dev, "disconnect detected on port %d\n", port + 1); usb_remove_device(dev->children[port]); if (!dev->parent && dev->host->usbphy) usb_phy_notify_disconnect(dev->host->usbphy, dev->speed); return; } /* Remove disabled but connected devices */ if (dev->children[port] && !(portstatus & USB_PORT_STAT_ENABLE)) usb_remove_device(dev->children[port]); mdelay(200); /* Reset the port */ if (hub_port_reset(dev, port, &portstatus) < 0) { dev_warn(&dev->dev, "cannot reset port %i!?\n", port + 1); return; } mdelay(200); /* Allocate a new device struct for it */ usb = usb_alloc_new_device(); usb->dev.parent = &dev->dev; usb->host = dev->host; if (portstatus & USB_PORT_STAT_HIGH_SPEED) usb->speed = USB_SPEED_HIGH; else if (portstatus & USB_PORT_STAT_LOW_SPEED) usb->speed = USB_SPEED_LOW; else usb->speed = USB_SPEED_FULL; dev->children[port] = usb; usb->parent = dev; usb->portnr = port + 1; /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */ dev_dbg(&dev->dev, "hub: disabling port %d\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); usb_free_device(usb); return; } if (!dev->parent && dev->host->usbphy) usb_phy_notify_connect(dev->host->usbphy, usb->speed); device_detect(&usb->dev); }