diff options
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/Kconfig | 36 | ||||
| -rw-r--r-- | drivers/usb/core/devio.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/driver.c | 25 | ||||
| -rw-r--r-- | drivers/usb/core/generic.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/hcd-pci.c | 214 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 10 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 136 | ||||
| -rw-r--r-- | drivers/usb/core/port.c | 5 | ||||
| -rw-r--r-- | drivers/usb/core/quirks.c | 16 | ||||
| -rw-r--r-- | drivers/usb/core/sysfs.c | 4 | ||||
| -rw-r--r-- | drivers/usb/core/urb.c | 5 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 7 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 2 | 
13 files changed, 253 insertions, 211 deletions
| diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index f70c1a1694ad..8772b3659296 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -3,7 +3,6 @@  #  config USB_DEBUG  	bool "USB verbose debug messages" -	depends on USB  	help  	  Say Y here if you want the USB core & hub drivers to produce a bunch  	  of debug messages to the system log. Select this if you are having a @@ -11,7 +10,6 @@ config USB_DEBUG  config USB_ANNOUNCE_NEW_DEVICES  	bool "USB announce new devices" -	depends on USB  	default N  	help  	  Say Y here if you want the USB core to always announce the @@ -25,11 +23,24 @@ config USB_ANNOUNCE_NEW_DEVICES  	  log, or have any doubts about this, say N here.  comment "Miscellaneous USB options" -	depends on USB + +config USB_DEFAULT_PERSIST +	bool "Enable USB persist by default" +	default y +	help +	  Say N here if you don't want USB power session persistance +	  enabled by default.  If you say N it will make suspended USB +	  devices that lose power get reenumerated as if they had been +	  unplugged, causing any mounted filesystems to be lost.  The +	  persist feature can still be enabled for individual devices +	  through the power/persist sysfs node. See +	  Documentation/usb/persist.txt for more info. + +	  If you have any questions about this, say Y here, only say N +	  if you know exactly what you are doing.  config USB_DYNAMIC_MINORS  	bool "Dynamic USB minor allocation" -	depends on USB  	help  	  If you say Y here, the USB subsystem will use dynamic minor  	  allocation for any device that uses the USB major number. @@ -38,25 +49,8 @@ config USB_DYNAMIC_MINORS  	  If you are unsure about this, say N here. -config USB_SUSPEND -	bool "USB runtime power management (autosuspend) and wakeup" -	depends on USB && PM_RUNTIME -	help -	  If you say Y here, you can use driver calls or the sysfs -	  "power/control" file to enable or disable autosuspend for -	  individual USB peripherals (see -	  Documentation/usb/power-management.txt for more details). - -	  Also, USB "remote wakeup" signaling is supported, whereby some -	  USB devices (like keyboards and network adapters) can wake up -	  their parent hub.  That wakeup cascades up the USB tree, and -	  could wake the system from states like suspend-to-RAM. - -	  If you are unsure about this, say N here. -  config USB_OTG  	bool "OTG support" -	depends on USB  	depends on USB_SUSPEND  	default n  	help diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8823e98989fe..caefc800f298 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -739,6 +739,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,  	index &= 0xff;  	switch (requesttype & USB_RECIP_MASK) {  	case USB_RECIP_ENDPOINT: +		if ((index & ~USB_DIR_IN) == 0) +			return 0;  		ret = findintfep(ps->dev, index);  		if (ret >= 0)  			ret = checkintf(ps, ret); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d938b2b99e31..6eab440e1542 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1196,9 +1196,14 @@ done:   *   * This is the central routine for suspending USB devices.  It calls the   * suspend methods for all the interface drivers in @udev and then calls - * the suspend method for @udev itself.  If an error occurs at any stage, - * all the interfaces which were suspended are resumed so that they remain - * in the same state as the device. + * the suspend method for @udev itself.  When the routine is called in + * autosuspend, if an error occurs at any stage, all the interfaces + * which were suspended are resumed so that they remain in the same + * state as the device, but when called from system sleep, all error + * from suspend methods of interfaces and the non-root-hub device itself + * are simply ignored, so all suspended interfaces are only resumed + * to the device's state when @udev is root-hub and its suspend method + * returns failure.   *   * Autosuspend requests originating from a child device or an interface   * driver may be made without the protection of @udev's device lock, but @@ -1248,10 +1253,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)  	/* If the suspend failed, resume interfaces that did get suspended */  	if (status != 0) { -		msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); -		while (++i < n) { -			intf = udev->actconfig->interface[i]; -			usb_resume_interface(udev, intf, msg, 0); +		if (udev->actconfig) { +			msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); +			while (++i < n) { +				intf = udev->actconfig->interface[i]; +				usb_resume_interface(udev, intf, msg, 0); +			}  		}  	/* If the suspend succeeded then prevent any more URB submissions @@ -1407,7 +1414,7 @@ int usb_resume(struct device *dev, pm_message_t msg)  #endif /* CONFIG_PM */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  /**   * usb_enable_autosuspend - allow a USB device to be autosuspended @@ -1775,7 +1782,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)  	return ret;  } -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */  struct bus_type usb_bus_type = {  	.name =		"usb", diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 271e761f563e..acbfeb0a0119 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev)  		c = usb_choose_configuration(udev);  		if (c >= 0) {  			err = usb_set_configuration(udev, c); -			if (err) { +			if (err && err != -ENODEV) {  				dev_err(&udev->dev, "can't set config #%d, error %d\n",  					c, err);  				/* This need not be fatal.  The user can try to diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 2b487d4797bd..caeb8d6d39fb 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -37,119 +37,123 @@  /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ -#ifdef CONFIG_PM_SLEEP - -/* Coordinate handoffs between EHCI and companion controllers - * during system resume +/* + * Coordinate handoffs between EHCI and companion controllers + * during EHCI probing and system resume.   */ -static DEFINE_MUTEX(companions_mutex); +static DECLARE_RWSEM(companions_rwsem);  #define CL_UHCI		PCI_CLASS_SERIAL_USB_UHCI  #define CL_OHCI		PCI_CLASS_SERIAL_USB_OHCI  #define CL_EHCI		PCI_CLASS_SERIAL_USB_EHCI -enum companion_action { -	SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS -}; +static inline int is_ohci_or_uhci(struct pci_dev *pdev) +{ +	return pdev->class == CL_OHCI || pdev->class == CL_UHCI; +} + +typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd); -static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, -		enum companion_action action) +/* Iterate over PCI devices in the same slot as pdev and call fn for each */ +static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, +		companion_fn fn)  {  	struct pci_dev		*companion;  	struct usb_hcd		*companion_hcd;  	unsigned int		slot = PCI_SLOT(pdev->devfn); -	/* Iterate through other PCI functions in the same slot. -	 * If pdev is OHCI or UHCI then we are looking for EHCI, and -	 * vice versa. +	/* +	 * Iterate through other PCI functions in the same slot. +	 * If the function's drvdata isn't set then it isn't bound to +	 * a USB host controller driver, so skip it.  	 */  	companion = NULL;  	for_each_pci_dev(companion) {  		if (companion->bus != pdev->bus ||  				PCI_SLOT(companion->devfn) != slot)  			continue; -  		companion_hcd = pci_get_drvdata(companion);  		if (!companion_hcd)  			continue; - -		/* For SET_HS_COMPANION, store a pointer to the EHCI bus in -		 * the OHCI/UHCI companion bus structure. -		 * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus -		 * in the OHCI/UHCI companion bus structure. -		 * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI -		 * companion controllers have fully resumed. -		 */ - -		if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) && -				companion->class == CL_EHCI) { -			/* action must be SET_HS_COMPANION */ -			dev_dbg(&companion->dev, "HS companion for %s\n", -					dev_name(&pdev->dev)); -			hcd->self.hs_companion = &companion_hcd->self; - -		} else if (pdev->class == CL_EHCI && -				(companion->class == CL_OHCI || -				companion->class == CL_UHCI)) { -			switch (action) { -			case SET_HS_COMPANION: -				dev_dbg(&pdev->dev, "HS companion for %s\n", -						dev_name(&companion->dev)); -				companion_hcd->self.hs_companion = &hcd->self; -				break; -			case CLEAR_HS_COMPANION: -				companion_hcd->self.hs_companion = NULL; -				break; -			case WAIT_FOR_COMPANIONS: -				device_pm_wait_for_dev(&pdev->dev, -						&companion->dev); -				break; -			} -		} +		fn(pdev, hcd, companion, companion_hcd);  	}  } -static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) +/* + * We're about to add an EHCI controller, which will unceremoniously grab + * all the port connections away from its companions.  To prevent annoying + * error messages, lock the companion's root hub and gracefully unconfigure + * it beforehand.  Leave it locked until the EHCI controller is all set. + */ +static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd)  { -	mutex_lock(&companions_mutex); -	dev_set_drvdata(&pdev->dev, hcd); -	companion_common(pdev, hcd, SET_HS_COMPANION); -	mutex_unlock(&companions_mutex); +	struct usb_device *udev; + +	if (is_ohci_or_uhci(companion)) { +		udev = companion_hcd->self.root_hub; +		usb_lock_device(udev); +		usb_set_configuration(udev, 0); +	}  } -static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) +/* + * Adding the EHCI controller has either succeeded or failed.  Set the + * companion pointer accordingly, and in either case, reconfigure and + * unlock the root hub. + */ +static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd)  { -	mutex_lock(&companions_mutex); -	dev_set_drvdata(&pdev->dev, NULL); +	struct usb_device *udev; -	/* If pdev is OHCI or UHCI, just clear its hs_companion pointer */ -	if (pdev->class == CL_OHCI || pdev->class == CL_UHCI) -		hcd->self.hs_companion = NULL; +	if (is_ohci_or_uhci(companion)) { +		if (dev_get_drvdata(&pdev->dev)) {	/* Succeeded */ +			dev_dbg(&pdev->dev, "HS companion for %s\n", +					dev_name(&companion->dev)); +			companion_hcd->self.hs_companion = &hcd->self; +		} +		udev = companion_hcd->self.root_hub; +		usb_set_configuration(udev, 1); +		usb_unlock_device(udev); +	} +} -	/* Otherwise search for companion buses and clear their pointers */ -	else -		companion_common(pdev, hcd, CLEAR_HS_COMPANION); -	mutex_unlock(&companions_mutex); +/* + * We just added a non-EHCI controller.  Find the EHCI controller to + * which it is a companion, and store a pointer to the bus structure. + */ +static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd) +{ +	if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) { +		dev_dbg(&pdev->dev, "FS/LS companion for %s\n", +				dev_name(&companion->dev)); +		hcd->self.hs_companion = &companion_hcd->self; +	}  } -static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) +/* We are removing an EHCI controller.  Clear the companions' pointers. */ +static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd)  { -	/* Only EHCI controllers need to wait. -	 * No locking is needed because a controller cannot be resumed -	 * while one of its companions is getting unbound. -	 */ -	if (pdev->class == CL_EHCI) -		companion_common(pdev, hcd, WAIT_FOR_COMPANIONS); +	if (is_ohci_or_uhci(companion)) +		companion_hcd->self.hs_companion = NULL;  } -#else /* !CONFIG_PM_SLEEP */ +#ifdef	CONFIG_PM -static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {} +/* An EHCI controller must wait for its companions before resuming. */ +static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd) +{ +	if (is_ohci_or_uhci(companion)) +		device_pm_wait_for_dev(&pdev->dev, &companion->dev); +} -#endif /* !CONFIG_PM_SLEEP */ +#endif	/* CONFIG_PM */  /*-------------------------------------------------------------------------*/ @@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  				driver->description)) {  			dev_dbg(&dev->dev, "controller already in use\n");  			retval = -EBUSY; -			goto clear_companion; +			goto put_hcd;  		}  		hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);  		if (hcd->regs == NULL) { @@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  		if (region == PCI_ROM_RESOURCE) {  			dev_dbg(&dev->dev, "no i/o regions available\n");  			retval = -EBUSY; -			goto clear_companion; +			goto put_hcd;  		}  	}  	pci_set_master(dev); -	retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); +	/* Note: dev_set_drvdata must be called while holding the rwsem */ +	if (dev->class == CL_EHCI) { +		down_write(&companions_rwsem); +		dev_set_drvdata(&dev->dev, hcd); +		for_each_companion(dev, hcd, ehci_pre_add); +		retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); +		if (retval != 0) +			dev_set_drvdata(&dev->dev, NULL); +		for_each_companion(dev, hcd, ehci_post_add); +		up_write(&companions_rwsem); +	} else { +		down_read(&companions_rwsem); +		dev_set_drvdata(&dev->dev, hcd); +		retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); +		if (retval != 0) +			dev_set_drvdata(&dev->dev, NULL); +		else +			for_each_companion(dev, hcd, non_ehci_add); +		up_read(&companions_rwsem); +	} +  	if (retval != 0)  		goto unmap_registers; -	set_hs_companion(dev, hcd);  	if (pci_dev_run_wake(dev))  		pm_runtime_put_noidle(&dev->dev); @@ -266,8 +289,7 @@ release_mem_region:  		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	} else  		release_region(hcd->rsrc_start, hcd->rsrc_len); -clear_companion: -	clear_hs_companion(dev, hcd); +put_hcd:  	usb_put_hcd(hcd);  disable_pci:  	pci_disable_device(dev); @@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev)  	usb_hcd_irq(0, hcd);  	local_irq_enable(); -	usb_remove_hcd(hcd); +	/* Note: dev_set_drvdata must be called while holding the rwsem */ +	if (dev->class == CL_EHCI) { +		down_write(&companions_rwsem); +		for_each_companion(dev, hcd, ehci_remove); +		usb_remove_hcd(hcd); +		dev_set_drvdata(&dev->dev, NULL); +		up_write(&companions_rwsem); +	} else { +		/* Not EHCI; just clear the companion pointer */ +		down_read(&companions_rwsem); +		hcd->self.hs_companion = NULL; +		usb_remove_hcd(hcd); +		dev_set_drvdata(&dev->dev, NULL); +		up_read(&companions_rwsem); +	} +  	if (hcd->driver->flags & HCD_MEMORY) {  		iounmap(hcd->regs);  		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	} else {  		release_region(hcd->rsrc_start, hcd->rsrc_len);  	} -	clear_hs_companion(dev, hcd); +  	usb_put_hcd(hcd);  	pci_disable_device(dev);  } @@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event)  	pci_set_master(pci_dev);  	if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { -		if (event != PM_EVENT_AUTO_RESUME) -			wait_for_companions(pci_dev, hcd); + +		/* +		 * Only EHCI controllers have to wait for their companions. +		 * No locking is needed because PCI controller drivers do not +		 * get unbound during system resume. +		 */ +		if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME) +			for_each_companion(pci_dev, hcd, +					ehci_wait_for_companions);  		retval = hcd->driver->pci_resume(hcd,  				event == PM_EVENT_RESTORE); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f9ec44cbb82f..d53547d2e4c7 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)  #endif	/* CONFIG_PM */ -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM_RUNTIME  /* Workqueue routine for root-hub remote wakeup */  static void hcd_resume_work(struct work_struct *work) @@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)  }  EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); -#endif	/* CONFIG_USB_SUSPEND */ +#endif	/* CONFIG_PM_RUNTIME */  /*-------------------------------------------------------------------------*/ @@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,  	init_timer(&hcd->rh_timer);  	hcd->rh_timer.function = rh_timer_func;  	hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);  #endif @@ -2590,7 +2590,7 @@ error_create_attr_group:  	hcd->rh_registered = 0;  	spin_unlock_irq(&hcd_root_hub_lock); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	cancel_work_sync(&hcd->wakeup_work);  #endif  	mutex_lock(&usb_bus_list_lock); @@ -2645,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)  	hcd->rh_registered = 0;  	spin_unlock_irq (&hcd_root_hub_lock); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	cancel_work_sync(&hcd->wakeup_work);  #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5480352f984d..feef9351463d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1,  	mutex_lock(&hub->status_mutex);  	ret = get_port_status(hub->hdev, port1, &hub->status->port);  	if (ret < 4) { -		dev_err(hub->intfdev, -			"%s failed (err = %d)\n", __func__, ret); +		if (ret != -ENODEV) +			dev_err(hub->intfdev, +				"%s failed (err = %d)\n", __func__, ret);  		if (ret >= 0)  			ret = -EIO;  	} else { @@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work)  		/* drop lock so HCD can concurrently report other TT errors */  		spin_unlock_irqrestore (&hub->tt.lock, flags);  		status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); -		if (status) +		if (status && status != -ENODEV)  			dev_err (&hdev->dev,  				"clear tt %d (%04x) error %d\n",  				clear->tt, clear->devinfo, status); @@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub,  	mutex_lock(&hub->status_mutex);  	ret = get_hub_status(hub->hdev, &hub->status->hub); -	if (ret < 0) -		dev_err (hub->intfdev, -			"%s failed (err = %d)\n", __func__, ret); -	else { +	if (ret < 0) { +		if (ret != -ENODEV) +			dev_err(hub->intfdev, +				"%s failed (err = %d)\n", __func__, ret); +	} else {  		*status = le16_to_cpu(hub->status->hub.wHubStatus);  		*change = le16_to_cpu(hub->status->hub.wHubChange);   		ret = 0; @@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)  		return -EINVAL;  	ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); -	if (ret) { -		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", -				port1, ret); +	if (ret)  		return ret; -	}  	/* Wait for the link to enter the disabled state. */  	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { @@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)  			ret = usb_clear_port_feature(hdev, port1,  					USB_PORT_FEAT_ENABLE);  	} -	if (ret) +	if (ret && ret != -ENODEV)  		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",  				port1, ret);  	return ret; @@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub,  		message = "hub has too many ports!";  		ret = -ENODEV;  		goto fail; +	} else if (hub->descriptor->bNbrPorts == 0) { +		message = "hub doesn't have any ports!"; +		ret = -ENODEV; +		goto fail;  	}  	hdev->maxchild = hub->descriptor->bNbrPorts; @@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev)  	if (udev->config == NULL) {  		err = usb_get_configuration(udev);  		if (err < 0) { -			dev_err(&udev->dev, "can't read configurations, error %d\n", -				err); +			if (err != -ENODEV) +				dev_err(&udev->dev, "can't read configurations, error %d\n", +						err);  			return err;  		}  	} @@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  		status = set_port_feature(hub->hdev, port1, (warm ?  					USB_PORT_FEAT_BH_PORT_RESET :  					USB_PORT_FEAT_RESET)); -		if (status) { +		if (status == -ENODEV) { +			;	/* The hub is gone */ +		} else if (status) {  			dev_err(hub->intfdev,  					"cannot %sreset port %d (err = %d)\n",  					warm ? "warm " : "", port1, status);  		} else {  			status = hub_port_wait_reset(hub, port1, udev, delay,  								warm); -			if (status && status != -ENOTCONN) +			if (status && status != -ENOTCONN && status != -ENODEV)  				dev_dbg(hub->intfdev,  						"port_wait_reset: err = %d\n",  						status); @@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev)  }  EXPORT_SYMBOL_GPL(usb_enable_ltm); -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM  /*   * usb_disable_function_remotewakeup - disable usb3.0   * device's function remote wakeup @@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)   * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd   * timer, no SRP, no requests through sysfs.   * - * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when - * the root hub for their bus goes into global suspend ... so we don't - * (falsely) update the device power state to say it suspended. + * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get + * suspended only when their bus goes into global suspend (i.e., the root + * hub is suspended).  Nevertheless, we change @udev->state to + * USB_STATE_SUSPENDED as this is the device's "logical" state.  The actual + * upstream port setting is stored in @udev->port_is_suspended.   *   * Returns 0 on success, else negative errno.   */ @@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	enum pm_qos_flags_status pm_qos_stat;  	int		port1 = udev->portnum;  	int		status; +	bool		really_suspend = true;  	/* enable remote wakeup when appropriate; this lets the device  	 * wake up the upstream hub (including maybe the root hub). @@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	/* see 7.1.7.6 */  	if (hub_is_superspeed(hub->hdev))  		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3); -	else +	else if (PMSG_IS_AUTO(msg))  		status = set_port_feature(hub->hdev, port1,  						USB_PORT_FEAT_SUSPEND); +	/* +	 * For system suspend, we do not need to enable the suspend feature +	 * on individual USB-2 ports.  The devices will automatically go +	 * into suspend a few ms after the root hub stops sending packets. +	 * The USB 2.0 spec calls this "global suspend". +	 */ +	else { +		really_suspend = false; +		status = 0; +	}  	if (status) {  		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",  				port1, status); @@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  				(PMSG_IS_AUTO(msg) ? "auto-" : ""),  				udev->do_remote_wakeup);  		usb_set_device_state(udev, USB_STATE_SUSPENDED); -		udev->port_is_suspended = 1; -		msleep(10); +		if (really_suspend) { +			udev->port_is_suspended = 1; +			msleep(10); +		}  	}  	/* @@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	return status;  } +#endif	/* CONFIG_PM */ + +#ifdef	CONFIG_PM_RUNTIME +  /* caller has locked udev */  int usb_remote_wakeup(struct usb_device *udev)  { @@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev)  	return status;  } -#else	/* CONFIG_USB_SUSPEND */ - -/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ - -int usb_port_suspend(struct usb_device *udev, pm_message_t msg) -{ -	return 0; -} - -/* However we may need to do a reset-resume */ - -int usb_port_resume(struct usb_device *udev, pm_message_t msg) -{ -	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent); -	int		port1 = udev->portnum; -	int		status; -	u16		portchange, portstatus; - -	status = hub_port_status(hub, port1, &portstatus, &portchange); -	status = check_port_resume_type(udev, -			hub, port1, status, portchange, portstatus); - -	if (status) { -		dev_dbg(&udev->dev, "can't resume, status %d\n", status); -		hub_port_logical_disconnect(hub, port1); -	} else if (udev->reset_resume) { -		dev_dbg(&udev->dev, "reset-resume\n"); -		status = usb_reset_and_verify_device(udev); -	} -	return status; -} -  #endif  static int check_ports_changed(struct usb_hub *hub) @@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  				goto fail;  			}  			if (r) { -				dev_err(&udev->dev, -					"device descriptor read/64, error %d\n", -					r); +				if (r != -ENODEV) +					dev_err(&udev->dev, "device descriptor read/64, error %d\n", +							r);  				retval = -EMSGSIZE;  				continue;  			} @@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  				msleep(200);  			}  			if (retval < 0) { -				dev_err(&udev->dev, -					"device not accepting address %d, error %d\n", -					devnum, retval); +				if (retval != -ENODEV) +					dev_err(&udev->dev, "device not accepting address %d, error %d\n", +							devnum, retval);  				goto fail;  			}  			if (udev->speed == USB_SPEED_SUPER) { @@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		retval = usb_get_device_descriptor(udev, 8);  		if (retval < 8) { -			dev_err(&udev->dev, +			if (retval != -ENODEV) +				dev_err(&udev->dev,  					"device descriptor read/8, error %d\n",  					retval);  			if (retval >= 0) @@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);  	if (retval < (signed)sizeof(udev->descriptor)) { -		dev_err(&udev->dev, "device descriptor read/all, error %d\n", -			retval); +		if (retval != -ENODEV) +			dev_err(&udev->dev, "device descriptor read/all, error %d\n", +					retval);  		if (retval >= 0)  			retval = -ENOMSG;  		goto fail; @@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		if (portstatus & USB_PORT_STAT_ENABLE) {  			status = 0;		/* Nothing to do */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  		} else if (udev->state == USB_STATE_SUSPENDED &&  				udev->persist_enabled) {  			/* For a suspended device, treat this as a @@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  				USB_PORT_STAT_C_ENABLE)) {  		status = hub_port_debounce_be_stable(hub, port1);  		if (status < 0) { -			if (printk_ratelimit()) +			if (status != -ENODEV && printk_ratelimit())  				dev_err(hub_dev, "connect-debounce failed, "  						"port %d disabled\n", port1);  			portstatus &= ~USB_PORT_STAT_CONNECTION; @@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  	else  		unit_load = 100; +	status = 0;  	for (i = 0; i < SET_CONFIG_TRIES; i++) {  		/* reallocate for each attempt, since references @@ -4526,9 +4522,11 @@ loop:  	}  	if (hub->hdev->parent ||  			!hcd->driver->port_handed_over || -			!(hcd->driver->port_handed_over)(hcd, port1)) -		dev_err(hub_dev, "unable to enumerate USB device on port %d\n", -				port1); +			!(hcd->driver->port_handed_over)(hcd, port1)) { +		if (status != -ENOTCONN && status != -ENODEV) +			dev_err(hub_dev, "unable to enumerate USB device on port %d\n", +					port1); +	}  done:  	hub_port_disable(hub, port1, 1); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 797f9d514732..b8bad294eeb8 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -67,11 +67,10 @@ static void usb_port_device_release(struct device *dev)  {  	struct usb_port *port_dev = to_usb_port(dev); -	dev_pm_qos_hide_flags(dev);  	kfree(port_dev);  } -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  static int usb_port_runtime_resume(struct device *dev)  {  	struct usb_port *port_dev = to_usb_port(dev); @@ -139,7 +138,7 @@ static int usb_port_runtime_suspend(struct device *dev)  #endif  static const struct dev_pm_ops usb_port_pm_ops = { -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	.runtime_suspend =	usb_port_runtime_suspend,  	.runtime_resume =	usb_port_runtime_resume,  	.runtime_idle =		pm_generic_runtime_idle, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 3113c1d71442..ab5638d9c707 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev)  		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",  			udev->quirks); -	/* For the present, all devices default to USB-PERSIST enabled */ -#if 0		/* was: #ifdef CONFIG_PM */ -	/* Hubs are automatically enabled for USB-PERSIST */ -	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) +#ifdef CONFIG_USB_DEFAULT_PERSIST +	if (!(udev->quirks & USB_QUIRK_RESET))  		udev->persist_enabled = 1; -  #else -	/* In the absence of PM, we can safely enable USB-PERSIST -	 * for all devices.  It will affect things like hub resets -	 * and EMF-related port disables. -	 */ -	if (!(udev->quirks & USB_QUIRK_RESET)) +	/* Hubs are automatically enabled for USB-PERSIST */ +	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)  		udev->persist_enabled = 1; -#endif	/* CONFIG_PM */ +#endif	/* CONFIG_USB_DEFAULT_PERSIST */  }  void usb_detect_interface_quirks(struct usb_device *udev) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 3f81a3dc6867..aa38db44818a 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev)  #endif	/* CONFIG_PM */ -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM_RUNTIME  static ssize_t  show_connected_duration(struct device *dev, struct device_attribute *attr, @@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev)  #define add_power_attributes(dev)	0  #define remove_power_attributes(dev)	do {} while (0) -#endif	/* CONFIG_USB_SUSPEND */ +#endif	/* CONFIG_PM_RUNTIME */  /* Descriptor fields */ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index e0d9d948218c..16927fa88fbd 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);  void usb_poison_urb(struct urb *urb)  {  	might_sleep(); -	if (!(urb && urb->dev && urb->ep)) +	if (!urb)  		return;  	atomic_inc(&urb->reject); +	if (!urb->dev || !urb->ep) +		return; +  	usb_hcd_unlink_urb(urb, -ENOENT);  	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);  } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f81b92572735..b10da720f2b4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";  static bool nousb;	/* Disable USB when built into kernel image */ -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM_RUNTIME  static int usb_autosuspend_delay = 2;		/* Default delay value,  						 * in seconds */  module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); @@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {  	.thaw =		usb_dev_thaw,  	.poweroff =	usb_dev_poweroff,  	.restore =	usb_dev_restore, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	.runtime_suspend =	usb_runtime_suspend,  	.runtime_resume =	usb_runtime_resume,  	.runtime_idle =		usb_runtime_idle, @@ -317,7 +317,8 @@ static const struct dev_pm_ops usb_device_pm_ops = {  #endif	/* CONFIG_PM */ -static char *usb_devnode(struct device *dev, umode_t *mode) +static char *usb_devnode(struct device *dev, +			 umode_t *mode, kuid_t *uid, kgid_t *gid)  {  	struct usb_device *usb_dev; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index a7f20bde0e5e..823857767a16 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)  #endif -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  extern void usb_autosuspend_device(struct usb_device *udev);  extern int usb_autoresume_device(struct usb_device *udev); | 
