diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
| -rw-r--r-- | drivers/usb/core/hcd.c | 100 | 
1 files changed, 75 insertions, 25 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 12742f152f4..ced846ac414 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -667,7 +667,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  	unsigned long	flags;  	char		buffer[6];	/* Any root hubs with > 31 ports? */ -	if (unlikely(!hcd->rh_registered)) +	if (unlikely(!hcd->rh_pollable))  		return;  	if (!hcd->uses_new_polling && !hcd->status_urb)  		return; @@ -679,7 +679,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  		spin_lock_irqsave(&hcd_root_hub_lock, flags);  		urb = hcd->status_urb;  		if (urb) { -			hcd->poll_pending = 0; +			clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);  			hcd->status_urb = NULL;  			urb->actual_length = length;  			memcpy(urb->transfer_buffer, buffer, length); @@ -690,7 +690,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  			spin_lock(&hcd_root_hub_lock);  		} else {  			length = 0; -			hcd->poll_pending = 1; +			set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);  		}  		spin_unlock_irqrestore(&hcd_root_hub_lock, flags);  	} @@ -699,7 +699,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  	 * exceed that limit if HZ is 100. The math is more clunky than  	 * maybe expected, this is to make sure that all timers for USB devices  	 * fire at the same time to give the CPU a break inbetween */ -	if (hcd->uses_new_polling ? hcd->poll_rh : +	if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :  			(length == 0 && hcd->status_urb != NULL))  		mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));  } @@ -736,7 +736,7 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)  		mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));  	/* If a status change has already occurred, report it ASAP */ -	else if (hcd->poll_pending) +	else if (HCD_POLL_PENDING(hcd))  		mod_timer(&hcd->rh_timer, jiffies);  	retval = 0;   done: @@ -1150,8 +1150,7 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,  	 * finish unlinking the initial failed usb_set_address()  	 * or device descriptor fetch.  	 */ -	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && -			!is_root_hub(urb->dev)) { +	if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) {  		dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "  			"Controller is probably using the wrong IRQ.\n");  		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); @@ -1219,6 +1218,11 @@ static int hcd_alloc_coherent(struct usb_bus *bus,  {  	unsigned char *vaddr; +	if (*vaddr_handle == NULL) { +		WARN_ON_ONCE(1); +		return -EFAULT; +	} +  	vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),  				 mem_flags, dma_handle);  	if (!vaddr) @@ -1259,10 +1263,8 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,  	*dma_handle = 0;  } -static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +void unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)  { -	enum dma_data_direction dir; -  	if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)  		dma_unmap_single(hcd->self.controller,  				urb->setup_dma, @@ -1275,6 +1277,17 @@ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)  				sizeof(struct usb_ctrlrequest),  				DMA_TO_DEVICE); +	/* Make it safe to call this routine more than once */ +	urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL); +} +EXPORT_SYMBOL_GPL(unmap_urb_setup_for_dma); + +void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ +	enum dma_data_direction dir; + +	unmap_urb_setup_for_dma(hcd, urb); +  	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;  	if (urb->transfer_flags & URB_DMA_MAP_SG)  		dma_unmap_sg(hcd->self.controller, @@ -1299,10 +1312,10 @@ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)  				dir);  	/* Make it safe to call this routine more than once */ -	urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL | -			URB_DMA_MAP_SG | URB_DMA_MAP_PAGE | +	urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |  			URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);  } +EXPORT_SYMBOL_GPL(unmap_urb_for_dma);  static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,  			   gfp_t mem_flags) @@ -1317,6 +1330,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,  	 */  	if (usb_endpoint_xfer_control(&urb->ep->desc)) { +		if (hcd->self.uses_pio_for_control) +			return ret;  		if (hcd->self.uses_dma) {  			urb->setup_dma = dma_map_single(  					hcd->self.controller, @@ -1941,6 +1956,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)  	dev_dbg(&rhdev->dev, "usb %s%s\n",  			(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume"); +	clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);  	if (!hcd->driver->bus_resume)  		return -ENOENT;  	if (hcd->state == HC_STATE_RUNNING) @@ -1994,8 +2010,10 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)  	unsigned long flags;  	spin_lock_irqsave (&hcd_root_hub_lock, flags); -	if (hcd->rh_registered) +	if (hcd->rh_registered) { +		set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);  		queue_work(pm_wq, &hcd->wakeup_work); +	}  	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);  }  EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); @@ -2063,8 +2081,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)  	 */  	local_irq_save(flags); -	if (unlikely(hcd->state == HC_STATE_HALT || -		     !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { +	if (unlikely(hcd->state == HC_STATE_HALT || !HCD_HW_ACCESSIBLE(hcd))) {  		rc = IRQ_NONE;  	} else if (hcd->driver->irq(hcd) == IRQ_NONE) {  		rc = IRQ_NONE; @@ -2079,6 +2096,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)  	local_irq_restore(flags);  	return rc;  } +EXPORT_SYMBOL_GPL(usb_hcd_irq);  /*-------------------------------------------------------------------------*/ @@ -2098,7 +2116,7 @@ void usb_hc_died (struct usb_hcd *hcd)  	spin_lock_irqsave (&hcd_root_hub_lock, flags);  	if (hcd->rh_registered) { -		hcd->poll_rh = 0; +		clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);  		/* make khubd clean up old urbs and devices */  		usb_set_device_state (hcd->self.root_hub, @@ -2217,6 +2235,7 @@ int usb_add_hcd(struct usb_hcd *hcd,  		retval = -ENOMEM;  		goto err_allocate_root_hub;  	} +	hcd->self.root_hub = rhdev;  	switch (hcd->driver->flags & HCD_MASK) {  	case HCD_USB11: @@ -2229,9 +2248,8 @@ int usb_add_hcd(struct usb_hcd *hcd,  		rhdev->speed = USB_SPEED_SUPER;  		break;  	default: -		goto err_allocate_root_hub; +		goto err_set_rh_speed;  	} -	hcd->self.root_hub = rhdev;  	/* wakeup flag init defaults to "everything works" for root hubs,  	 * but drivers can override it in reset() if needed, along with @@ -2246,6 +2264,7 @@ int usb_add_hcd(struct usb_hcd *hcd,  		dev_err(hcd->self.controller, "can't setup\n");  		goto err_hcd_driver_setup;  	} +	hcd->rh_pollable = 1;  	/* NOTE: root hub and controller capabilities may not be the same */  	if (device_can_wakeup(hcd->self.controller) @@ -2300,23 +2319,38 @@ int usb_add_hcd(struct usb_hcd *hcd,  		       retval);  		goto error_create_attr_group;  	} -	if (hcd->uses_new_polling && hcd->poll_rh) +	if (hcd->uses_new_polling && HCD_POLL_RH(hcd))  		usb_hcd_poll_rh_status(hcd);  	return retval;  error_create_attr_group: +	if (HC_IS_RUNNING(hcd->state)) +		hcd->state = HC_STATE_QUIESCING; +	spin_lock_irq(&hcd_root_hub_lock); +	hcd->rh_registered = 0; +	spin_unlock_irq(&hcd_root_hub_lock); + +#ifdef CONFIG_USB_SUSPEND +	cancel_work_sync(&hcd->wakeup_work); +#endif  	mutex_lock(&usb_bus_list_lock); -	usb_disconnect(&hcd->self.root_hub); +	usb_disconnect(&rhdev);		/* Sets rhdev to NULL */  	mutex_unlock(&usb_bus_list_lock);  err_register_root_hub: +	hcd->rh_pollable = 0; +	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +	del_timer_sync(&hcd->rh_timer);  	hcd->driver->stop(hcd); +	hcd->state = HC_STATE_HALT; +	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +	del_timer_sync(&hcd->rh_timer);  err_hcd_driver_start:  	if (hcd->irq >= 0)  		free_irq(irqnum, hcd);  err_request_irq:  err_hcd_driver_setup: -	hcd->self.root_hub = NULL; -	usb_put_dev(rhdev); +err_set_rh_speed: +	usb_put_dev(hcd->self.root_hub);  err_allocate_root_hub:  	usb_deregister_bus(&hcd->self);  err_register_bus: @@ -2335,8 +2369,13 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);   */  void usb_remove_hcd(struct usb_hcd *hcd)  { +	struct usb_device *rhdev = hcd->self.root_hub; +  	dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); +	usb_get_dev(rhdev); +	sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group); +  	if (HC_IS_RUNNING (hcd->state))  		hcd->state = HC_STATE_QUIESCING; @@ -2349,19 +2388,30 @@ void usb_remove_hcd(struct usb_hcd *hcd)  	cancel_work_sync(&hcd->wakeup_work);  #endif -	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);  	mutex_lock(&usb_bus_list_lock); -	usb_disconnect(&hcd->self.root_hub); +	usb_disconnect(&rhdev);		/* Sets rhdev to NULL */  	mutex_unlock(&usb_bus_list_lock); +	/* Prevent any more root-hub status calls from the timer. +	 * The HCD might still restart the timer (if a port status change +	 * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke +	 * the hub_status_data() callback. +	 */ +	hcd->rh_pollable = 0; +	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); +	del_timer_sync(&hcd->rh_timer); +  	hcd->driver->stop(hcd);  	hcd->state = HC_STATE_HALT; -	hcd->poll_rh = 0; +	/* In case the HCD restarted the timer, stop it again. */ +	clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);  	del_timer_sync(&hcd->rh_timer);  	if (hcd->irq >= 0)  		free_irq(hcd->irq, hcd); + +	usb_put_dev(hcd->self.root_hub);  	usb_deregister_bus(&hcd->self);  	hcd_buffer_destroy(hcd);  }  | 
