drivers/usb/host/ehci-timer.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/ehci-timer.c
Extension
.c
Size
13259 bytes
Lines
427
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source 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 (ehci->ASS_poll_count++ < 2) {
			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
			return;
		}
		ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n",
				want, actual);
	}
	ehci->ASS_poll_count = 0;

	/* The status is up-to-date; restart or stop the schedule as needed */
	if (want == 0) {	/* Stopped */
		if (ehci->async_count > 0)
			ehci_set_command_bit(ehci, CMD_ASE);

	} else {		/* Running */
		if (ehci->async_count == 0) {

			/* Turn off the schedule after a while */
			ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC,
					true);
		}
	}
}

/* Turn off the async schedule after a brief delay */
static void ehci_disable_ASE(struct ehci_hcd *ehci)
{
	ehci_clear_command_bit(ehci, CMD_ASE);
}


/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
static void ehci_poll_PSS(struct ehci_hcd *ehci)
{
	unsigned	actual, want;

	/* Don't do anything if the controller isn't running (e.g., died) */
	if (ehci->rh_state != EHCI_RH_RUNNING)
		return;

	want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
	actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;

	if (want != actual) {

		/* Poll again later, but give up after about 2-4 ms */
		if (ehci->PSS_poll_count++ < 2) {
			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
			return;
		}
		ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
				want, actual);
	}
	ehci->PSS_poll_count = 0;

	/* The status is up-to-date; restart or stop the schedule as needed */
	if (want == 0) {	/* Stopped */
		if (ehci->periodic_count > 0)
			ehci_set_command_bit(ehci, CMD_PSE);

	} else {		/* Running */
		if (ehci->periodic_count == 0) {

			/* Turn off the schedule after a while */
			ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
					true);
		}
	}
}

/* Turn off the periodic schedule after a brief delay */
static void ehci_disable_PSE(struct ehci_hcd *ehci)
{
	ehci_clear_command_bit(ehci, CMD_PSE);
}


/* Poll the STS_HALT status bit; see when a dead controller stops */
static void ehci_handle_controller_death(struct ehci_hcd *ehci)
{
	if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) {

		/* Give up after a few milliseconds */
		if (ehci->died_poll_count++ < 5) {
			/* Try again later */
			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true);
			return;
		}
		ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n");
	}

Annotation

Implementation Notes