drivers/usb/host/ohci-hub.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/ohci-hub.c
Extension
.c
Size
21461 bytes
Lines
804
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 (!ohci->autostop) {
			ohci_dbg (ohci, "already suspended\n");
			goto done;
		}
	}
	ohci_dbg (ohci, "%s root hub\n",
			autostop ? "auto-stop" : "suspend");

	/* First stop any processing */
	if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) {
		ohci->hc_control &= ~OHCI_SCHED_ENABLES;
		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
		ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus);

		/* sched disables take effect on the next frame,
		 * then the last WDH could take 6+ msec
		 */
		ohci_dbg (ohci, "stopping schedules ...\n");
		ohci->autostop = 0;
		spin_unlock_irq (&ohci->lock);
		msleep (8);
		spin_lock_irq (&ohci->lock);
	}
	update_done_list(ohci);
	ohci_work(ohci);

	/* All ED unlinks should be finished, no need for SOF interrupts */
	ohci_writel(ohci, OHCI_INTR_SF, &ohci->regs->intrdisable);

	/*
	 * Some controllers don't handle "global" suspend properly if
	 * there are unsuspended ports.  For these controllers, put all
	 * the enabled ports into suspend before suspending the root hub.
	 */
	if (ohci->flags & OHCI_QUIRK_GLOBAL_SUSPEND) {
		__hc32 __iomem	*portstat = ohci->regs->roothub.portstatus;
		int		i;
		unsigned	temp;

		for (i = 0; i < ohci->num_ports; (++i, ++portstat)) {
			temp = ohci_readl(ohci, portstat);
			if ((temp & (RH_PS_PES | RH_PS_PSS)) ==
					RH_PS_PES)
				ohci_writel(ohci, RH_PS_PSS, portstat);
		}
	}

	/* maybe resume can wake root hub */
	if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {
		ohci->hc_control |= OHCI_CTRL_RWE;
	} else {
		ohci_writel(ohci, OHCI_INTR_RHSC | OHCI_INTR_RD,
				&ohci->regs->intrdisable);
		ohci->hc_control &= ~OHCI_CTRL_RWE;
	}

	/* Suspend hub ... this is the "global (to this bus) suspend" mode,
	 * which doesn't imply ports will first be individually suspended.
	 */
	ohci->hc_control &= ~OHCI_CTRL_HCFS;
	ohci->hc_control |= OHCI_USB_SUSPEND;
	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
	(void) ohci_readl (ohci, &ohci->regs->control);

	/* no resumes until devices finish suspending */
	if (!autostop) {
		ohci->next_statechange = jiffies + msecs_to_jiffies (5);
		ohci->autostop = 0;
		ohci->rh_state = OHCI_RH_SUSPENDED;
	}

done:
	return status;
}

static inline struct ed *find_head (struct ed *ed)
{
	/* for bulk and control lists */
	while (ed->ed_prev)
		ed = ed->ed_prev;
	return ed;
}

/* caller has locked the root hub */
static int ohci_rh_resume (struct ohci_hcd *ohci)
__releases(ohci->lock)
__acquires(ohci->lock)
{
	struct usb_hcd		*hcd = ohci_to_hcd (ohci);

Annotation

Implementation Notes