hcd.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,743 行 · 第 1/4 页

C
1,743
字号
/** * usb_hcd_resume_root_hub - called by HCD to resume its root hub  * @hcd: host controller for this root hub * * The USB host controller calls this function when its root hub is * suspended (with the remote wakeup feature enabled) and a remote * wakeup request is received.  The routine submits a workqueue request * to resume the root hub (that is, manage its downstream ports again). */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)		queue_work(ksuspend_usb_wq, &hcd->wakeup_work);	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);}EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);/*-------------------------------------------------------------------------*//** * usb_bus_start_enum - start immediate enumeration (for OTG) * @bus: the bus (must use hcd framework) * @port_num: 1-based number of port; usually bus->otg_port * Context: in_interrupt() * * Starts enumeration, with an immediate reset followed later by * khubd identifying and possibly configuring the device. * This is needed by OTG controller drivers, where it helps meet * HNP protocol timing requirements for starting a port reset. */int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num){	struct usb_hcd		*hcd;	int			status = -EOPNOTSUPP;	/* NOTE: since HNP can't start by grabbing the bus's address0_sem,	 * boards with root hubs hooked up to internal devices (instead of	 * just the OTG port) may need more attention to resetting...	 */	hcd = container_of (bus, struct usb_hcd, self);	if (port_num && hcd->driver->start_port_reset)		status = hcd->driver->start_port_reset(hcd, port_num);	/* run khubd shortly after (first) root port reset finishes;	 * it may issue others, until at least 50 msecs have passed.	 */	if (status == 0)		mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10));	return status;}EXPORT_SYMBOL (usb_bus_start_enum);/*-------------------------------------------------------------------------*//** * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB * @urb: urb being returned to the USB device driver. * Context: in_interrupt() * * This hands the URB from HCD to its USB device driver, using its * completion function.  The HCD has freed all per-urb resources * (and is done using urb->hcpriv).  It also released all HCD locks; * the device driver won't cause problems if it frees, modifies, * or resubmits this URB. */void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb){	int at_root_hub;	at_root_hub = (urb->dev == hcd->self.root_hub);	urb_unlink (urb);	/* lower level hcd code should use *_dma exclusively if the	 * host controller does DMA */	if (hcd->self.uses_dma && !at_root_hub) {		if (usb_pipecontrol (urb->pipe)			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))			dma_unmap_single (hcd->self.controller, urb->setup_dma,					sizeof (struct usb_ctrlrequest),					DMA_TO_DEVICE);		if (urb->transfer_buffer_length != 0			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))			dma_unmap_single (hcd->self.controller, 					urb->transfer_dma,					urb->transfer_buffer_length,					usb_pipein (urb->pipe)					    ? DMA_FROM_DEVICE					    : DMA_TO_DEVICE);	}	usbmon_urb_complete (&hcd->self, urb);	/* pass ownership to the completion handler */	urb->complete (urb);	atomic_dec (&urb->use_count);	if (unlikely (urb->reject))		wake_up (&usb_kill_urb_queue);	usb_put_urb (urb);}EXPORT_SYMBOL (usb_hcd_giveback_urb);/*-------------------------------------------------------------------------*//** * usb_hcd_irq - hook IRQs to HCD framework (bus glue) * @irq: the IRQ being raised * @__hcd: pointer to the HCD whose IRQ is being signaled * @r: saved hardware registers * * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. */irqreturn_t usb_hcd_irq (int irq, void *__hcd){	struct usb_hcd		*hcd = __hcd;	int			start = hcd->state;	if (unlikely(start == HC_STATE_HALT ||	    !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))		return IRQ_NONE;	if (hcd->driver->irq (hcd) == IRQ_NONE)		return IRQ_NONE;	set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);	if (unlikely(hcd->state == HC_STATE_HALT))		usb_hc_died (hcd);	return IRQ_HANDLED;}/*-------------------------------------------------------------------------*//** * usb_hc_died - report abnormal shutdown of a host controller (bus glue) * @hcd: pointer to the HCD representing the controller * * This is called by bus glue to report a USB host controller that died * while operations may still have been pending.  It's called automatically * by the PCI glue, so only glue for non-PCI busses should need to call it.  */void usb_hc_died (struct usb_hcd *hcd){	unsigned long flags;	dev_err (hcd->self.controller, "HC died; cleaning up\n");	spin_lock_irqsave (&hcd_root_hub_lock, flags);	if (hcd->rh_registered) {		hcd->poll_rh = 0;		/* make khubd clean up old urbs and devices */		usb_set_device_state (hcd->self.root_hub,				USB_STATE_NOTATTACHED);		usb_kick_khubd (hcd->self.root_hub);	}	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);}EXPORT_SYMBOL_GPL (usb_hc_died);/*-------------------------------------------------------------------------*//** * usb_create_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd * @dev: device for this HC, stored in hcd->self.controller * @bus_name: value to store in hcd->self.bus_name * Context: !in_interrupt() * * Allocate a struct usb_hcd, with extra space at the end for the * HC driver's private data.  Initialize the generic members of the * hcd structure. * * If memory is unavailable, returns NULL. */struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,		struct device *dev, char *bus_name){	struct usb_hcd *hcd;	hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);	if (!hcd) {		dev_dbg (dev, "hcd alloc failed\n");		return NULL;	}	dev_set_drvdata(dev, hcd);	kref_init(&hcd->kref);	usb_bus_init(&hcd->self);	hcd->self.controller = dev;	hcd->self.bus_name = bus_name;	hcd->self.uses_dma = (dev->dma_mask != NULL);	init_timer(&hcd->rh_timer);	hcd->rh_timer.function = rh_timer_func;	hcd->rh_timer.data = (unsigned long) hcd;	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);	hcd->driver = driver;	hcd->product_desc = (driver->product_desc) ? driver->product_desc :			"USB Host Controller";	return hcd;}EXPORT_SYMBOL (usb_create_hcd);static void hcd_release (struct kref *kref){	struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);	kfree(hcd);}struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd){	if (hcd)		kref_get (&hcd->kref);	return hcd;}EXPORT_SYMBOL (usb_get_hcd);void usb_put_hcd (struct usb_hcd *hcd){	if (hcd)		kref_put (&hcd->kref, hcd_release);}EXPORT_SYMBOL (usb_put_hcd);/** * usb_add_hcd - finish generic HCD structure initialization and register * @hcd: the usb_hcd structure to initialize * @irqnum: Interrupt line to allocate * @irqflags: Interrupt type flags * * Finish the remaining parts of generic HCD initialization: allocate the * buffers of consistent memory, register the bus, request the IRQ line, * and call the driver's reset() and start() routines. */int usb_add_hcd(struct usb_hcd *hcd,		unsigned int irqnum, unsigned long irqflags){	int retval;	struct usb_device *rhdev;	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);	/* HC is in reset state, but accessible.  Now do the one-time init,	 * bottom up so that hcds can customize the root hubs before khubd	 * starts talking to them.  (Note, bus id is assigned early too.)	 */	if ((retval = hcd_buffer_create(hcd)) != 0) {		dev_dbg(hcd->self.controller, "pool alloc failed\n");		return retval;	}	if ((retval = usb_register_bus(&hcd->self)) < 0)		goto err_register_bus;	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {		dev_err(hcd->self.controller, "unable to allocate root hub\n");		retval = -ENOMEM;		goto err_allocate_root_hub;	}	rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :			USB_SPEED_FULL;	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	 * recording the overall controller's system wakeup capability.	 */	device_init_wakeup(&rhdev->dev, 1);	/* "reset" is misnamed; its role is now one-time init. the controller	 * should already have been reset (and boot firmware kicked off etc).	 */	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {		dev_err(hcd->self.controller, "can't setup\n");		goto err_hcd_driver_setup;	}	/* NOTE: root hub and controller capabilities may not be the same */	if (device_can_wakeup(hcd->self.controller)			&& device_can_wakeup(&hcd->self.root_hub->dev))		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");	/* enable irqs just before we start the controller */	if (hcd->driver->irq) {		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",				hcd->driver->description, hcd->self.busnum);		if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,				hcd->irq_descr, hcd)) != 0) {			dev_err(hcd->self.controller,					"request interrupt %d failed\n", irqnum);			goto err_request_irq;		}		hcd->irq = irqnum;		dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum,				(hcd->driver->flags & HCD_MEMORY) ?					"io mem" : "io base",					(unsigned long long)hcd->rsrc_start);	} else {		hcd->irq = -1;		if (hcd->rsrc_start)			dev_info(hcd->self.controller, "%s 0x%08llx\n",					(hcd->driver->flags & HCD_MEMORY) ?					"io mem" : "io base",					(unsigned long long)hcd->rsrc_start);	}	if ((retval = hcd->driver->start(hcd)) < 0) {		dev_err(hcd->self.controller, "startup error %d\n", retval);		goto err_hcd_driver_start;	}	/* starting here, usbcore will pay attention to this root hub */	rhdev->bus_mA = min(500u, hcd->power_budget);	if ((retval = register_root_hub(hcd)) != 0)		goto err_register_root_hub;	if (hcd->uses_new_polling && hcd->poll_rh)		usb_hcd_poll_rh_status(hcd);	return retval;err_register_root_hub:	hcd->driver->stop(hcd);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_allocate_root_hub:	usb_deregister_bus(&hcd->self);err_register_bus:	hcd_buffer_destroy(hcd);	return retval;} EXPORT_SYMBOL (usb_add_hcd);/** * usb_remove_hcd - shutdown processing for generic HCDs * @hcd: the usb_hcd structure to remove * Context: !in_interrupt() * * Disconnects the root hub, then reverses the effects of usb_add_hcd(), * invoking the HCD's stop() method. */void usb_remove_hcd(struct usb_hcd *hcd){	dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);	if (HC_IS_RUNNING (hcd->state))		hcd->state = HC_STATE_QUIESCING;	dev_dbg(hcd->self.controller, "roothub graceful disconnect\n");	spin_lock_irq (&hcd_root_hub_lock);	hcd->rh_registered = 0;	spin_unlock_irq (&hcd_root_hub_lock);	cancel_work_sync(&hcd->wakeup_work);	mutex_lock(&usb_bus_list_lock);	usb_disconnect(&hcd->self.root_hub);	mutex_unlock(&usb_bus_list_lock);	hcd->driver->stop(hcd);	hcd->state = HC_STATE_HALT;	hcd->poll_rh = 0;	del_timer_sync(&hcd->rh_timer);	if (hcd->irq >= 0)		free_irq(hcd->irq, hcd);	usb_deregister_bus(&hcd->self);	hcd_buffer_destroy(hcd);}EXPORT_SYMBOL (usb_remove_hcd);voidusb_hcd_platform_shutdown(struct platform_device* dev){	struct usb_hcd *hcd = platform_get_drvdata(dev);	if (hcd->driver->shutdown)		hcd->driver->shutdown(hcd);}EXPORT_SYMBOL (usb_hcd_platform_shutdown);/*-------------------------------------------------------------------------*/struct usb_mon_operations *mon_ops;/* * The registration is unlocked. * We do it this way because we do not want to lock in hot paths. * * Notice that the code is minimally error-proof. Because usbmon needs * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. */ int usb_mon_register (struct usb_mon_operations *ops){	if (mon_ops)		return -EBUSY;	mon_ops = ops;	mb();	return 0;}EXPORT_SYMBOL_GPL (usb_mon_register);void usb_mon_deregister (void){	if (mon_ops == NULL) {		printk(KERN_ERR "USB: monitor was not registered\n");		return;	}	mon_ops = NULL;	mb();}EXPORT_SYMBOL_GPL (usb_mon_deregister);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?