drivers/usb/dwc2/hcd_intr.c

Source file repositories/reference/linux-study-clean/drivers/usb/dwc2/hcd_intr.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/dwc2/hcd_intr.c
Extension
.c
Size
66996 bytes
Lines
2267
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 (expected != curr_frame_number) {
			hsotg->frame_num_array[hsotg->frame_num_idx] =
					curr_frame_number;
			hsotg->last_frame_num_array[hsotg->frame_num_idx] =
					hsotg->last_frame_num;
			hsotg->frame_num_idx++;
		}
	} else if (!hsotg->dumped_frame_num_array) {
		int i;

		dev_info(hsotg->dev, "Frame     Last Frame\n");
		dev_info(hsotg->dev, "-----     ----------\n");
		for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
			dev_info(hsotg->dev, "0x%04x    0x%04x\n",
				 hsotg->frame_num_array[i],
				 hsotg->last_frame_num_array[i]);
		}
		hsotg->dumped_frame_num_array = 1;
	}
#endif
	hsotg->last_frame_num = curr_frame_number;
}

static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
				    struct dwc2_host_chan *chan,
				    struct dwc2_qtd *qtd)
{
	struct usb_device *root_hub = dwc2_hsotg_to_hcd(hsotg)->self.root_hub;
	struct urb *usb_urb;

	if (!chan->qh)
		return;

	if (chan->qh->dev_speed == USB_SPEED_HIGH)
		return;

	if (!qtd->urb)
		return;

	usb_urb = qtd->urb->priv;
	if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
		return;

	/*
	 * The root hub doesn't really have a TT, but Linux thinks it
	 * does because how could you have a "high speed hub" that
	 * directly talks directly to low speed devices without a TT?
	 * It's all lies.  Lies, I tell you.
	 */
	if (usb_urb->dev->tt->hub == root_hub)
		return;

	if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
		chan->qh->tt_buffer_dirty = 1;
		if (usb_hub_clear_tt_buffer(usb_urb))
			/* Clear failed; let's hope things work anyway */
			chan->qh->tt_buffer_dirty = 0;
	}
}

/*
 * Handles the start-of-frame interrupt in host mode. Non-periodic
 * transactions may be queued to the DWC_otg controller for the current
 * (micro)frame. Periodic transactions may be queued to the controller
 * for the next (micro)frame.
 */
static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
{
	struct list_head *qh_entry;
	struct dwc2_qh *qh;
	enum dwc2_transaction_type tr_type;

	/* Clear interrupt */
	dwc2_writel(hsotg, GINTSTS_SOF, GINTSTS);

#ifdef DEBUG_SOF
	dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
#endif

	hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);

	dwc2_track_missed_sofs(hsotg);

	/* Determine whether any periodic QHs should be executed */
	qh_entry = hsotg->periodic_sched_inactive.next;
	while (qh_entry != &hsotg->periodic_sched_inactive) {
		qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry);
		qh_entry = qh_entry->next;
		if (dwc2_frame_num_le(qh->next_active_frame,
				      hsotg->frame_number)) {

Annotation

Implementation Notes