drivers/usb/host/uhci-hub.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/uhci-hub.c
Extension
.c
Size
11472 bytes
Lines
422
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 (unlikely(status & USBPORTSC_PR)) {
			if (time_after_eq(jiffies, uhci->ports_timeout)) {
				CLR_RH_PORTSTAT(USBPORTSC_PR);
				udelay(10);

				/* HP's server management chip requires
				 * a longer delay. */
				if (uhci->wait_for_hp)
					wait_for_HP(uhci, port_addr);

				/* If the port was enabled before, turning
				 * reset on caused a port enable change.
				 * Turning reset off causes a port connect
				 * status change.  Clear these changes. */
				CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
				SET_RH_PORTSTAT(USBPORTSC_PE);
			}
		}
		if (unlikely(status & USBPORTSC_RD)) {
			if (!test_bit(port, &uhci->resuming_ports)) {

				/* Port received a wakeup request */
				set_bit(port, &uhci->resuming_ports);
				uhci->ports_timeout = jiffies +
					msecs_to_jiffies(USB_RESUME_TIMEOUT);
				usb_hcd_start_port_resume(
						&uhci_to_hcd(uhci)->self, port);

				/* Make sure we see the port again
				 * after the resuming period is over. */
				mod_timer(&uhci_to_hcd(uhci)->rh_timer,
						uhci->ports_timeout);
			} else if (time_after_eq(jiffies,
						uhci->ports_timeout)) {
				uhci_finish_suspend(uhci, port, port_addr);
			}
		}
	}
}

static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
	unsigned long flags;
	int status = 0;

	spin_lock_irqsave(&uhci->lock, flags);

	uhci_scan_schedule(uhci);
	if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
		goto done;
	uhci_check_ports(uhci);

	status = get_hub_status_data(uhci, buf);

	switch (uhci->rh_state) {
	    case UHCI_RH_SUSPENDED:
		/* if port change, ask to be resumed */
		if (status || uhci->resuming_ports) {
			status = 1;
			usb_hcd_resume_root_hub(hcd);
		}
		break;

	    case UHCI_RH_AUTO_STOPPED:
		/* if port change, auto start */
		if (status)
			wakeup_rh(uhci);
		break;

	    case UHCI_RH_RUNNING:
		/* are any devices attached? */
		if (!any_ports_active(uhci)) {
			uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
			uhci->auto_stop_time = jiffies + HZ;
		}
		break;

	    case UHCI_RH_RUNNING_NODEVS:
		/* auto-stop if nothing connected for 1 second */
		if (any_ports_active(uhci))
			uhci->rh_state = UHCI_RH_RUNNING;
		else if (time_after_eq(jiffies, uhci->auto_stop_time) &&
				!uhci->wait_for_hp)
			suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
		break;

	    default:
		break;
	}

Annotation

Implementation Notes