⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hcd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",				"resume", status);		usb_hc_died(hcd);	}	return status;}/* * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports * @hcd: host controller for this root hub * * This call arranges that usb_hcd_resume_root_hub() is safe to call later; * that the HCD's root hub polling is deactivated; and that the root's hub * driver is suspended.  HCDs may call this to autosuspend when their root * hub's downstream ports are all inactive:  unpowered, disconnected, * disabled, or suspended. * * The HCD will autoresume on device connect change detection (using SRP * or a D+/D- pullup).  The HCD also autoresumes on remote wakeup signaling * from any ports that are suspended (if that is enabled).  In most cases, * overcurrent signaling (on powered ports) will also start autoresume. * * Always called with IRQs blocked. */void usb_hcd_suspend_root_hub (struct usb_hcd *hcd){	struct urb	*urb;	spin_lock (&hcd_root_hub_lock);	usb_suspend_root_hub (hcd->self.root_hub);	/* force status urb to complete/unlink while suspended */	if (hcd->status_urb) {		urb = hcd->status_urb;		urb->status = -ECONNRESET;		urb->hcpriv = NULL;		urb->actual_length = 0;		del_timer (&hcd->rh_timer);		hcd->poll_pending = 0;		hcd->status_urb = NULL;	} else		urb = NULL;	spin_unlock (&hcd_root_hub_lock);	hcd->state = HC_STATE_SUSPENDED;	if (urb)		usb_hcd_giveback_urb (hcd, urb, NULL);}EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);/** * 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.  It queues a request for khubd 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)		usb_resume_root_hub (hcd->self.root_hub);	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);}EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);#endif/*-------------------------------------------------------------------------*/#ifdef	CONFIG_USB_OTG/** * 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);#endif/*-------------------------------------------------------------------------*//* * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue) */static struct usb_operations usb_hcd_operations = {	.get_frame_number =	hcd_get_frame_number,	.submit_urb =		hcd_submit_urb,	.unlink_urb =		hcd_unlink_urb,	.buffer_alloc =		hcd_buffer_alloc,	.buffer_free =		hcd_buffer_free,	.disable =		hcd_endpoint_disable,};/*-------------------------------------------------------------------------*//** * 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. * @regs: pt_regs, passed down to the URB completion handler * 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, struct pt_regs *regs){	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 (hcd->self.controller->dma_mask && !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, regs);	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 pt_regs * r){	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, r) == 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);/*-------------------------------------------------------------------------*/static void hcd_release (struct usb_bus *bus){	struct usb_hcd *hcd;	hcd = container_of(bus, struct usb_hcd, self);	kfree(hcd);}/** * 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);	usb_bus_init(&hcd->self);	hcd->self.op = &usb_hcd_operations;	hcd->self.hcpriv = hcd;	hcd->self.release = &hcd_release;	hcd->self.controller = dev;	hcd->self.bus_name = bus_name;	init_timer(&hcd->rh_timer);	hcd->rh_timer.function = rh_timer_func;	hcd->rh_timer.data = (unsigned long) hcd;	hcd->driver = driver;	hcd->product_desc = (driver->product_desc) ? driver->product_desc :			"USB Host Controller";	return hcd;}EXPORT_SYMBOL (usb_create_hcd);void usb_put_hcd (struct usb_hcd *hcd){	dev_set_drvdata(hcd->self.controller, NULL);	usb_bus_put(&hcd->self);}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);	/* till now HC has been in an indeterminate state ... */	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {		dev_err(hcd->self.controller, "can't reset\n");		return retval;	}	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 (hcd->driver->irq) {		char	buf[8], *bufp = buf;#ifdef __sparc__		bufp = __irq_itoa(irqnum);#else		sprintf(buf, "%d", irqnum);#endif		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 %s failed\n", bufp);			goto err_request_irq;		}		hcd->irq = irqnum;		dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,				(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);	}	/* Allocate the root hub before calling hcd->driver->start(),	 * but don't register it until afterward so that the hardware	 * is running.	 */	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;	/* Although in principle hcd->driver->start() might need to use rhdev,	 * none of the current drivers do.	 */	if ((retval = hcd->driver->start(hcd)) < 0) {		dev_err(hcd->self.controller, "startup error %d\n", retval);		goto err_hcd_driver_start;	}	/* hcd->driver->start() reported can_wakeup, probably with	 * assistance from board's boot firmware.	 * NOTE:  normal devices won't enable wakeup by default.	 */	if (hcd->can_wakeup)		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");	hcd->remote_wakeup = hcd->can_wakeup;	if ((retval = register_root_hub(rhdev, 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:	usb_put_dev(rhdev); err_allocate_root_hub:	if (hcd->irq >= 0)		free_irq(irqnum, hcd); err_request_irq:	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);	usb_disconnect(&hcd->self.root_hub);	hcd->poll_rh = 0;	del_timer_sync(&hcd->rh_timer);	hcd->driver->stop(hcd);	hcd->state = HC_STATE_HALT;	if (hcd->irq >= 0)		free_irq(hcd->irq, hcd);	usb_deregister_bus(&hcd->self);	hcd_buffer_destroy(hcd);}EXPORT_SYMBOL (usb_remove_hcd);/*-------------------------------------------------------------------------*/#if defined(CONFIG_USB_MON)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);#endif /* CONFIG_USB_MON */

⌨️ 快捷键说明

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