drivers/usb/core/hcd-pci.c

Source file repositories/reference/linux-study-clean/drivers/usb/core/hcd-pci.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/core/hcd-pci.c
Extension
.c
Size
17404 bytes
Lines
653
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

* Store this function in the HCD's struct pci_driver as probe().
 *
 * Return: 0 if successful.
 */
int usb_hcd_pci_probe(struct pci_dev *dev, const struct hc_driver *driver)
{
	struct usb_hcd		*hcd;
	int			retval;
	int			hcd_irq = 0;

	if (usb_disabled())
		return -ENODEV;

	if (!driver)
		return -EINVAL;

	if (pci_enable_device(dev) < 0)
		return -ENODEV;

	/*
	 * The xHCI driver has its own irq management
	 * make sure irq setup is not touched for xhci in generic hcd code
	 */
	if ((driver->flags & HCD_MASK) < HCD_USB3) {
		retval = pci_alloc_irq_vectors(dev, 1, 1,
					       PCI_IRQ_INTX | PCI_IRQ_MSI);
		if (retval < 0) {
			dev_err(&dev->dev,
			"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
				pci_name(dev));
			retval = -ENODEV;
			goto disable_pci;
		}
		hcd_irq = pci_irq_vector(dev, 0);
	}

	hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
	if (!hcd) {
		retval = -ENOMEM;
		goto free_irq_vectors;
	}

	hcd->amd_resume_bug = usb_hcd_amd_resume_bug(dev, driver);

	if (driver->flags & HCD_MEMORY) {
		/* XHCI, EHCI, OHCI */
		hcd->rsrc_start = pci_resource_start(dev, 0);
		hcd->rsrc_len = pci_resource_len(dev, 0);
		if (!devm_request_mem_region(&dev->dev, hcd->rsrc_start,
				hcd->rsrc_len, driver->description)) {
			dev_dbg(&dev->dev, "controller already in use\n");
			retval = -EBUSY;
			goto put_hcd;
		}
		hcd->regs = devm_ioremap(&dev->dev, hcd->rsrc_start,
				hcd->rsrc_len);
		if (hcd->regs == NULL) {
			dev_dbg(&dev->dev, "error mapping memory\n");
			retval = -EFAULT;
			goto put_hcd;
		}

	} else {
		/* UHCI */
		int	region;

		for (region = 0; region < PCI_STD_NUM_BARS; region++) {
			if (!(pci_resource_flags(dev, region) &
					IORESOURCE_IO))
				continue;

			hcd->rsrc_start = pci_resource_start(dev, region);
			hcd->rsrc_len = pci_resource_len(dev, region);
			if (devm_request_region(&dev->dev, hcd->rsrc_start,
					hcd->rsrc_len, driver->description))
				break;
		}
		if (region == PCI_STD_NUM_BARS) {
			dev_dbg(&dev->dev, "no i/o regions available\n");
			retval = -EBUSY;
			goto put_hcd;
		}
	}

	pci_set_master(dev);

	/* 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);

Annotation

Implementation Notes