drivers/usb/host/ehci-hub.c

Source file repositories/reference/linux-study-clean/drivers/usb/host/ehci-hub.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/ehci-hub.c
Extension
.c
Size
34021 bytes
Lines
1223
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (test_bit(port, &ehci->owned_ports)) {
			reg = &ehci->regs->port_status[port];
			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
			if (!(status & PORT_POWER))
				ehci_port_power(ehci, port, true);
		}
	}

	/* Give the connections some time to appear */
	msleep(20);

	spin_lock_irq(&ehci->lock);
	port = HCS_N_PORTS(ehci->hcs_params);
	while (port--) {
		if (test_bit(port, &ehci->owned_ports)) {
			reg = &ehci->regs->port_status[port];
			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;

			/* Port already owned by companion? */
			if (status & PORT_OWNER)
				clear_bit(port, &ehci->owned_ports);
			else if (test_bit(port, &ehci->companion_ports))
				ehci_writel(ehci, status & ~PORT_PE, reg);
			else {
				spin_unlock_irq(&ehci->lock);
				ehci_hub_control(hcd, SetPortFeature,
						USB_PORT_FEAT_RESET, port + 1,
						NULL, 0);
				spin_lock_irq(&ehci->lock);
			}
		}
	}
	spin_unlock_irq(&ehci->lock);

	if (!ehci->owned_ports)
		return;
	msleep(90);		/* Wait for resets to complete */

	spin_lock_irq(&ehci->lock);
	port = HCS_N_PORTS(ehci->hcs_params);
	while (port--) {
		if (test_bit(port, &ehci->owned_ports)) {
			spin_unlock_irq(&ehci->lock);
			ehci_hub_control(hcd, GetPortStatus,
					0, port + 1,
					(char *) &buf, sizeof(buf));
			spin_lock_irq(&ehci->lock);

			/* The companion should now own the port,
			 * but if something went wrong the port must not
			 * remain enabled.
			 */
			reg = &ehci->regs->port_status[port];
			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
			if (status & PORT_OWNER)
				ehci_writel(ehci, status | PORT_CSC, reg);
			else {
				ehci_dbg(ehci, "failed handover port %d: %x\n",
						port + 1, status);
				ehci_writel(ehci, status & ~PORT_PE, reg);
			}
		}
	}

	ehci->owned_ports = 0;
	spin_unlock_irq(&ehci->lock);
}

static int ehci_port_change(struct ehci_hcd *ehci)
{
	int i = HCS_N_PORTS(ehci->hcs_params);

	/* First check if the controller indicates a change event */

	if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)
		return 1;

	/*
	 * Not all controllers appear to update this while going from D3 to D0,
	 * so check the individual port status registers as well
	 */

	while (i--)
		if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC)
			return 1;

	return 0;
}

void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,

Annotation

Implementation Notes