Example #1
0
/* "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;
}
Example #2
0
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);
}