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

📄 hcd.c

📁 飞利浦isp1161 arm-linux驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
			length = hcd->driver->hub_status_data (hcd,					urb->transfer_buffer);			spin_unlock_irqrestore (&urb->lock, flags);			if (length > 0) {				urb->actual_length = length;				urb->status = 0;				urb->complete (urb);			}			spin_lock_irqsave (&hcd_data_lock, flags);			urb->status = -EINPROGRESS;			if (HCD_IS_RUNNING (hcd->state)					&& rh_status_urb (hcd, urb) != 0) {				/* another driver snuck in? */				dbg ("%s, can't resubmit roothub status urb?",					hcd->bus_name);				spin_unlock_irqrestore (&hcd_data_lock, flags);				BUG ();			}			spin_unlock_irqrestore (&hcd_data_lock, flags);		} else			spin_unlock_irqrestore (&urb->lock, flags);	} else {		/* this urb's been unlinked */		urb->hcpriv = 0;		spin_unlock_irqrestore (&urb->lock, flags);		usb_hcd_giveback_urb (hcd, urb);	}}/*-------------------------------------------------------------------------*/static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb){	if (usb_pipeint (urb->pipe)) {		int		retval;		unsigned long	flags;		spin_lock_irqsave (&hcd_data_lock, flags);		retval = rh_status_urb (hcd, urb);		spin_unlock_irqrestore (&hcd_data_lock, flags);		return retval;	}	if (usb_pipecontrol (urb->pipe))		return rh_call_control (hcd, urb);	else		return -EINVAL;}/*-------------------------------------------------------------------------*/static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb){	unsigned long	flags;	spin_lock_irqsave (&hcd_data_lock, flags);	del_timer_sync (&hcd->rh_timer);	hcd->rh_timer.data = 0;	spin_unlock_irqrestore (&hcd_data_lock, flags);	/* we rely on RH callback code not unlinking its URB! */	usb_hcd_giveback_urb (hcd, urb);}/*-------------------------------------------------------------------------*/#ifdef CONFIG_PCI/* PCI-based HCs are normal, but custom bus glue should be ok */static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);static void hc_died (struct usb_hcd *hcd);/*-------------------------------------------------------------------------*//* configure so an HC device and id are always provided *//* always called with process context; sleeping is OK *//** * usb_hcd_pci_probe - initialize PCI-based HCDs * @dev: USB Host Controller being probed * @id: pci hotplug id connecting controller to HCD framework * Context: !in_interrupt() * * Allocates basic PCI resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. * * Store this function in the HCD's struct pci_driver as probe(). */int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id){	struct hc_driver	*driver;	unsigned long		resource, len;	void			*base;	u8			latency, limit;	struct usb_bus		*bus;	struct usb_hcd		*hcd;	int			retval, region;	char			buf [8], *bufp = buf;	if (!id || !(driver = (struct hc_driver *) id->driver_data))		return -EINVAL;	if (pci_enable_device (dev) < 0)		return -ENODEV;	        if (!dev->irq) {        	err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",			dev->slot_name);   	        return -ENODEV;        }		if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI		region = 0;		resource = pci_resource_start (dev, 0);		len = pci_resource_len (dev, 0);		if (!request_mem_region (resource, len, driver->description)) {			dbg ("controller already in use");			return -EBUSY;		}		base = ioremap_nocache (resource, len);		if (base == NULL) {			dbg ("error mapping memory");			retval = -EFAULT;clean_1:			release_mem_region (resource, len);			err ("init %s fail, %d", dev->slot_name, retval);			return retval;		}	} else { 				// UHCI		resource = len = 0;		for (region = 0; region < PCI_ROM_RESOURCE; region++) {			if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))				continue;			resource = pci_resource_start (dev, region);			len = pci_resource_len (dev, region);			if (request_region (resource, len,					driver->description))				break;		}		if (region == PCI_ROM_RESOURCE) {			dbg ("no i/o regions available");			return -EBUSY;		}		base = (void *) resource;	}	// driver->start(), later on, will transfer device from	// control by SMM/BIOS to control by Linux (if needed)	pci_set_master (dev);	hcd = driver->hcd_alloc ();	if (hcd == NULL){		dbg ("hcd alloc fail");		retval = -ENOMEM;clean_2:		if (driver->flags & HCD_MEMORY) {			iounmap (base);			goto clean_1;		} else {			release_region (resource, len);			err ("init %s fail, %d", dev->slot_name, retval);			return retval;		}	}	pci_set_drvdata(dev, hcd);	hcd->driver = driver;	hcd->description = driver->description;	hcd->pdev = dev;	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);	if (latency) {		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);		if (limit && limit < latency) {			dbg ("PCI latency reduced to max %d", limit);			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);		}	}#ifndef __sparc__	sprintf (buf, "%d", dev->irq);#else	bufp = __irq_itoa(dev->irq);#endif	if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)			!= 0) {		err ("request interrupt %s failed", bufp);		retval = -EBUSY;clean_3:		driver->hcd_free (hcd);		goto clean_2;	}	hcd->irq = dev->irq;	hcd->regs = base;	hcd->region = region;	info ("irq %s, %s %p", bufp,		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",		base);// FIXME simpler: make "bus" be that data, not pointer to it.	bus = usb_alloc_bus (&hcd_operations);	if (bus == NULL) {		dbg ("usb_alloc_bus fail");		retval = -ENOMEM;		free_irq (dev->irq, hcd);		goto clean_3;	}	hcd->bus = bus;	hcd->bus_name = dev->slot_name;	hcd->product_desc = dev->name;	bus->hcpriv = (void *) hcd;	INIT_LIST_HEAD (&hcd->dev_list);	INIT_LIST_HEAD (&hcd->hcd_list);	down (&hcd_list_lock);	list_add (&hcd->hcd_list, &hcd_list);	up (&hcd_list_lock);	usb_register_bus (bus);	if ((retval = driver->start (hcd)) < 0)		usb_hcd_pci_remove (dev);	return retval;} EXPORT_SYMBOL (usb_hcd_pci_probe);/* may be called without controller electrically present *//* may be called with controller, bus, and devices active *//** * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs * @dev: USB Host Controller being removed * Context: !in_interrupt() * * Reverses the effect of usb_hcd_pci_probe(), first invoking * the HCD's stop() method.  It is always called from a thread * context, normally "rmmod", "apmd", or something similar. * * Store this function in the HCD's struct pci_driver as remove(). */void usb_hcd_pci_remove (struct pci_dev *dev){	struct usb_hcd		*hcd;	struct usb_device	*hub;	hcd = pci_get_drvdata(dev);	if (!hcd)		return;	info ("remove: %s, state %x", hcd->bus_name, hcd->state);	if (in_interrupt ()) BUG ();	hub = hcd->bus->root_hub;	hcd->state = USB_STATE_QUIESCING;	dbg ("%s: roothub graceful disconnect", hcd->bus_name);	usb_disconnect (&hub);	// usb_disconnect (&hcd->bus->root_hub);	hcd->driver->stop (hcd);	hcd->state = USB_STATE_HALT;	free_irq (hcd->irq, hcd);	if (hcd->driver->flags & HCD_MEMORY) {		iounmap (hcd->regs);		release_mem_region (pci_resource_start (dev, 0),			pci_resource_len (dev, 0));	} else {		release_region (pci_resource_start (dev, hcd->region),			pci_resource_len (dev, hcd->region));	}	down (&hcd_list_lock);	list_del (&hcd->hcd_list);	up (&hcd_list_lock);	usb_deregister_bus (hcd->bus);	usb_free_bus (hcd->bus);	hcd->bus = NULL;	hcd->driver->hcd_free (hcd);}EXPORT_SYMBOL (usb_hcd_pci_remove);#ifdef	CONFIG_PM/* * Some "sleep" power levels imply updating struct usb_driver * to include a callback asking hcds to do their bit by checking * if all the drivers can suspend.  Gets involved with remote wakeup. * * If there are pending urbs, then HCs will need to access memory, * causing extra power drain.  New sleep()/wakeup() PM calls might * be needed, beyond PCI suspend()/resume().  The root hub timer * still be accessing memory though ... * * FIXME:  USB should have some power budgeting support working with * all kinds of hubs. * * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume. * D1 and D2 states should do something, yes? * * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake() * for all supported states, so that USB remote wakeup can work for any * devices that support it (and are connected via powered hubs). * * FIXME:  resume doesn't seem to work right any more... */// 2.4 kernels have issued concurrent resumes (w/APM)// we defend against that error; PCI doesn't yet./** * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD * @dev: USB Host Controller being suspended * * Store this function in the HCD's struct pci_driver as suspend(). */int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state){	struct usb_hcd		*hcd;	int			retval;	hcd = pci_get_drvdata(dev);	info ("suspend %s to state %d", hcd->bus_name, state);	pci_save_state (dev, hcd->pci_state);	// FIXME for all connected devices, leaf-to-root:	// driver->suspend()	// proposed "new 2.5 driver model" will automate that	/* driver may want to disable DMA etc */	retval = hcd->driver->suspend (hcd, state);	hcd->state = USB_STATE_SUSPENDED; 	pci_set_power_state (dev, state);	return retval;}EXPORT_SYMBOL (usb_hcd_pci_suspend);/** * usb_hcd_pci_resume - power management resume of a PCI-based HCD * @dev: USB Host Controller being resumed * * Store this function in the HCD's struct pci_driver as resume(). */int usb_hcd_pci_resume (struct pci_dev *dev){	struct usb_hcd		*hcd;	int			retval;	hcd = pci_get_drvdata(dev);	info ("resume %s", hcd->bus_name);	/* guard against multiple resumes (APM bug?) */	atomic_inc (&hcd->resume_count);	if (atomic_read (&hcd->resume_count) != 1) {		err ("concurrent PCI resumes for %s", hcd->bus_name);		retval = 0;		goto done;	}	retval = -EBUSY;	if (hcd->state != USB_STATE_SUSPENDED) {		dbg ("can't resume, not suspended!");		goto done;	}	hcd->state = USB_STATE_RESUMING;	pci_set_power_state (dev, 0);	pci_restore_state (dev, hcd->pci_state);	retval = hcd->driver->resume (hcd);	if (!HCD_IS_RUNNING (hcd->state)) {		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);		hc_died (hcd);// FIXME:  recover, reset etc.	} else {		// FIXME for all connected devices, root-to-leaf:		// driver->resume ();		// proposed "new 2.5 driver model" will automate that	}done:	atomic_dec (&hcd->resume_count);	return retval;}EXPORT_SYMBOL (usb_hcd_pci_resume);#endif	/* CONFIG_PM */#endif/*-------------------------------------------------------------------------*//* * Generic HC operations. *//*-------------------------------------------------------------------------*//* called from khubd, or root hub init threads for hcd-private init */static int hcd_alloc_dev (struct usb_device *udev){	struct hcd_dev		*dev;	struct usb_hcd		*hcd;	unsigned long		flags;	if (!udev || udev->hcpriv)		return -EINVAL;	if (!udev->bus || !udev->bus->hcpriv)		return -ENODEV;	hcd = udev->bus->hcpriv;	if (hcd->state == USB_STATE_QUIESCING)		return -ENOLINK;	dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);	if (dev == NULL)		return -ENOMEM;	memset (dev, 0, sizeof *dev);	INIT_LIST_HEAD (&dev->dev_list);	INIT_LIST_HEAD (&dev->urb_list);	spin_lock_irqsave (&hcd_data_lock, flags);	list_add (&dev->dev_list, &hcd->dev_list);	// refcount is implicit	udev->hcpriv = dev;	spin_unlock_irqrestore (&hcd_data_lock, flags);	return 0;}/*-------------------------------------------------------------------------*/static void hc_died (struct usb_hcd *hcd){	struct list_head	*devlist, *urblist;	struct hcd_dev		*dev;	struct urb		*urb;	unsigned long		flags;		/* flag every pending urb as done */	spin_lock_irqsave (&hcd_data_lock, flags);	list_for_each (devlist, &hcd->dev_list) {		dev = list_entry (devlist, struct hcd_dev, dev_list);		list_for_each (urblist, &dev->urb_list) {			urb = list_entry (urblist, struct urb, urb_list);			dbg ("shutdown %s urb %p pipe %x, current status %d",				hcd->bus_name, urb, urb->pipe, urb->status);			if (urb->status == -EINPROGRESS)				urb->status = -ESHUTDOWN;		}	}	urb = (struct urb *) hcd->rh_timer.data;	if (urb)		urb->status = -ESHUTDOWN;	spin_unlock_irqrestore (&hcd_data_lock, flags);	if (urb)		rh_status_dequeue (hcd, urb);	hcd->driver->stop (hcd);}/*-------------------------------------------------------------------------*/static void urb_unlink (struct urb *urb){	unsigned long		flags;	struct usb_device	*dev;	/* Release any periodic transfer bandwidth */	if (urb->bandwidth)		usb_release_bandwidth (urb->dev, urb,			usb_pipeisoc (urb->pipe));	/* clear all state linking urb to this dev (and hcd) */	spin_lock_irqsave (&hcd_data_lock, flags);

⌨️ 快捷键说明

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