博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android作为主usb设备,加载流程
阅读量:4284 次
发布时间:2019-05-27

本文共 11752 字,大约阅读时间需要 39 分钟。

android手机或平板,作为主设备,对usb的加载流程如下,这时外围设备是usb从设备,例如:usb的hub或者u 盘。

软件版本:android 6.0.1

1. 开机后,usb功能正常初始化;这时插入usb的U盘,或者hub;则首先调用如下代码。

        

static int hcd_pci_runtime_resume(struct device *dev){	int	retval;	powermac_set_asic(to_pci_dev(dev), 1);	retval = resume_common(dev, PM_EVENT_AUTO_RESUME);	dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);	return retval;}

然后继续调用:

static int resume_common(struct device *dev, int event){	struct pci_dev		*pci_dev = to_pci_dev(dev);	struct usb_hcd		*hcd = pci_get_drvdata(pci_dev);	int			retval;	if (HCD_RH_RUNNING(hcd) ||			(hcd->shared_hcd &&			 HCD_RH_RUNNING(hcd->shared_hcd))) {		dev_dbg(dev, "can't resume, not suspended!\n");		return 0;	}	retval = pci_enable_device(pci_dev);	if (retval < 0) {		dev_err(dev, "can't re-enable after resume, %d!\n", retval);		return retval;	}	pci_set_master(pci_dev);	if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {		/*		 * Only EHCI controllers have to wait for their companions.		 * No locking is needed because PCI controller drivers do not		 * get unbound during system resume.		 */		if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME)			for_each_companion(pci_dev, hcd,					ehci_wait_for_companions);		retval = hcd->driver->pci_resume(hcd,				event == PM_EVENT_RESTORE);		if (retval) {			dev_err(dev, "PCI post-resume error %d!\n", retval);			if (hcd->shared_hcd)				usb_hc_died(hcd->shared_hcd);			usb_hc_died(hcd);		}	}	return retval;}
在 代码 hcd->driver->pci_resume()    里, 调用函数如下:

static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated){	struct xhci_hcd		*xhci = hcd_to_xhci(hcd);	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);	int			retval = 0;	/* Due to one HW bug, XHCI will keep generating PME wakeups and fail	 * to stay in runtime suspended state, so required to clear the internal	 * PME flag once it is back to D0 as the software workaround */	if (xhci->quirks & XHCI_SPURIOUS_PME) {		xhci_intel_clr_internal_pme_flag(xhci);		xhci_intel_ssic_port_unused(xhci, 0);	}	/* The BIOS on systems with the Intel Panther Point chipset may or may	 * not support xHCI natively.  That means that during system resume, it	 * may switch the ports back to EHCI so that users can use their	 * keyboard to select a kernel from GRUB after resume from hibernate.	 *	 * The BIOS is supposed to remember whether the OS had xHCI ports	 * enabled before resume, and switch the ports back to xHCI when the	 * BIOS/OS semaphore is written, but we all know we can't trust BIOS	 * writers.	 *	 * Unconditionally switch the ports back to xHCI after a system resume.	 * It should not matter whether the EHCI or xHCI controller is	 * resumed first. It's enough to do the switchover in xHCI because	 * USB core won't notice anything as the hub driver doesn't start	 * running again until after all the devices (including both EHCI and	 * xHCI host controllers) have been resumed.	 */	if (pdev->vendor == PCI_VENDOR_ID_INTEL)		usb_enable_intel_xhci_ports(pdev);	retval = xhci_resume(xhci, hibernated);	return retval;}
然后调用函数,xhci_resume();

int xhci_resume(struct xhci_hcd *xhci, bool hibernated){	u32			command, temp = 0, status;	struct usb_hcd		*hcd = xhci_to_hcd(xhci);	struct usb_hcd		*secondary_hcd;	int			retval = 0;	bool			comp_timer_running = false;	pr_info("wgq[%s-%d] hibernated[%d]\n",__func__,__LINE__,hibernated);	/* Wait a bit if either of the roothubs need to settle from the	 * transition into bus suspend.	 */	if (time_before(jiffies, xhci->bus_state[0].next_statechange) ||			time_before(jiffies,				xhci->bus_state[1].next_statechange))		msleep(100);	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);	set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);	spin_lock_irq(&xhci->lock);	if (xhci->quirks & XHCI_RESET_ON_RESUME)		hibernated = true;	if (!hibernated) {		/* step 1: restore register */		xhci_restore_registers(xhci);		/* step 2: initialize command ring buffer */		xhci_set_cmd_ring_deq(xhci);		/* step 3: restore state and start state*/		/* step 3: set CRS flag */		command = readl(&xhci->op_regs->command);		command |= CMD_CRS;		writel(command, &xhci->op_regs->command);		if (xhci_handshake(xhci, &xhci->op_regs->status,			      STS_RESTORE, 0, 10 * 1000)) {			xhci_warn(xhci, "WARN: xHC restore state timeout\n");			spin_unlock_irq(&xhci->lock);			return -ETIMEDOUT;		}		temp = readl(&xhci->op_regs->status);	}	/* If restore operation fails, re-initialize the HC during resume */	if ((temp & STS_SRE) || hibernated) {		if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&				!(xhci_all_ports_seen_u0(xhci))) {			del_timer_sync(&xhci->comp_mode_recovery_timer);			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,				"Compliance Mode Recovery Timer deleted!");		}		/* Let the USB core know _both_ roothubs lost power. */		usb_root_hub_lost_power(xhci->main_hcd->self.root_hub);		usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);		xhci_dbg(xhci, "Stop HCD\n");		xhci_halt(xhci);		xhci_reset(xhci);		spin_unlock_irq(&xhci->lock);		xhci_cleanup_msix(xhci);		xhci_dbg(xhci, "// Disabling event ring interrupts\n");		temp = readl(&xhci->op_regs->status);		writel(temp & ~STS_EINT, &xhci->op_regs->status);		temp = readl(&xhci->ir_set->irq_pending);		writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);		xhci_print_ir_set(xhci, 0);		xhci_dbg(xhci, "cleaning up memory\n");		xhci_mem_cleanup(xhci);		xhci_dbg(xhci, "xhci_stop completed - status = %x\n",			    readl(&xhci->op_regs->status));		/* USB core calls the PCI reinit and start functions twice:		 * first with the primary HCD, and then with the secondary HCD.		 * If we don't do the same, the host will never be started.		 */		if (!usb_hcd_is_primary_hcd(hcd))			secondary_hcd = hcd;		else			secondary_hcd = xhci->shared_hcd;		xhci_dbg(xhci, "Initialize the xhci_hcd\n");		retval = xhci_init(hcd->primary_hcd);		if (retval)			return retval;		comp_timer_running = true;		xhci_dbg(xhci, "Start the primary HCD\n");		retval = xhci_run(hcd->primary_hcd);		if (!retval) {			xhci_dbg(xhci, "Start the secondary HCD\n");			retval = xhci_run(secondary_hcd);		}		hcd->state = HC_STATE_SUSPENDED;		xhci->shared_hcd->state = HC_STATE_SUSPENDED;		goto done;	}	/* step 4: set Run/Stop bit */	command = readl(&xhci->op_regs->command);	command |= CMD_RUN;	writel(command, &xhci->op_regs->command);	xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT,		  0, 250 * 1000);	xhci_resume_pending_ports(xhci);	/* step 5: walk topology and initialize portsc,	 * portpmsc and portli	 */	/* this is done in bus_resume */	/* step 6: restart each of the previously	 * Running endpoints by ringing their doorbells	 */	spin_unlock_irq(&xhci->lock); done:	if (retval == 0) {		/* Resume root hubs only when have pending events. */		status = readl(&xhci->op_regs->status);		if (status & STS_EINT) {			usb_hcd_resume_root_hub(hcd);			usb_hcd_resume_root_hub(xhci->shared_hcd);		}	}	/*	 * If system is subject to the Quirk, Compliance Mode Timer needs to	 * be re-initialized Always after a system resume. Ports are subject	 * to suffer the Compliance Mode issue again. It doesn't matter if	 * ports have entered previously to U0 before system's suspension.	 */	if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running)		compliance_mode_recovery_timer_init(xhci);	/* Re-enable port polling. */	xhci_dbg(xhci, "%s: starting port polling.\n", __func__);	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);	usb_hcd_poll_rh_status(hcd);	return retval;}
在以上的函数中,当执行完下面写寄存器命令后,正常情况下,会触发一个中断函数。见下面。

command = readl(&xhci->op_regs->command);	command |= CMD_RUN;	writel(command, &xhci->op_regs->command);
2。如果正常,则会触发以下中断函数。

irqreturn_t xhci_msi_irq(int irq, void *hcd){	return xhci_irq(hcd);}
进而调用以下函数,进行处理;

irqreturn_t xhci_irq(struct usb_hcd *hcd){	struct xhci_hcd *xhci = hcd_to_xhci(hcd);	u32 status;	u64 temp_64;	union xhci_trb *event_ring_deq;	dma_addr_t deq;	spin_lock(&xhci->lock);	/* Check if the xHC generated the interrupt, or the irq is shared */	status = readl(&xhci->op_regs->status);	if (status == 0xffffffff)		goto hw_died;	if (!(status & STS_EINT)) {		spin_unlock(&xhci->lock);		return IRQ_NONE;	}	if (status & STS_FATAL) {		xhci_warn(xhci, "WARNING: Host System Error\n");		xhci_halt(xhci);hw_died:		spin_unlock(&xhci->lock);		return -ESHUTDOWN;	}	/*	 * Clear the op reg interrupt status first,	 * so we can receive interrupts from other MSI-X interrupters.	 * Write 1 to clear the interrupt status.	 */	status |= STS_EINT;	writel(status, &xhci->op_regs->status);	/* FIXME when MSI-X is supported and there are multiple vectors */	/* Clear the MSI-X event interrupt status */	if (hcd->irq) {		u32 irq_pending;		/* Acknowledge the PCI interrupt */		irq_pending = readl(&xhci->ir_set->irq_pending);		irq_pending |= IMAN_IP;		writel(irq_pending, &xhci->ir_set->irq_pending);	}	if (xhci->xhc_state & XHCI_STATE_DYING) {		xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "				"Shouldn't IRQs be disabled?\n");		/* Clear the event handler busy flag (RW1C);		 * the event ring should be empty.		 */		temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);		xhci_write_64(xhci, temp_64 | ERST_EHB,				&xhci->ir_set->erst_dequeue);		spin_unlock(&xhci->lock);		return IRQ_HANDLED;	}	event_ring_deq = xhci->event_ring->dequeue;	/* FIXME this should be a delayed service routine	 * that clears the EHB.	 */	while (xhci_handle_event(xhci) > 0) {}	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);	/* If necessary, update the HW's version of the event ring deq ptr. */	if (event_ring_deq != xhci->event_ring->dequeue) {		deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,				xhci->event_ring->dequeue);		if (deq == 0)			xhci_warn(xhci, "WARN something wrong with SW event "					"ring dequeue ptr.\n");		/* Update HC event ring dequeue pointer */		temp_64 &= ERST_PTR_MASK;		temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);	}	/* Clear the event handler busy flag (RW1C); event ring is empty. */	temp_64 |= ERST_EHB;	xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);	spin_unlock(&xhci->lock);	return IRQ_HANDLED;}
在以上函数中, while(xhci_handle_event(xhci) > 0) {};  会处理各种信息;

static int xhci_handle_event(struct xhci_hcd *xhci){	union xhci_trb *event;	int update_ptrs = 1;	int ret;	if (!xhci->event_ring || !xhci->event_ring->dequeue) {		xhci->error_bitmask |= 1 << 1;		return 0;	}	event = xhci->event_ring->dequeue;	/* Does the HC or OS own the TRB? */	if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=	    xhci->event_ring->cycle_state) {		xhci->error_bitmask |= 1 << 2;		return 0;	}	/*	 * Barrier between reading the TRB_CYCLE (valid) flag above and any	 * speculative reads of the event's flags/data below.	 */	rmb();	/* FIXME: Handle more event types. */	switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) {	case TRB_TYPE(TRB_COMPLETION):		handle_cmd_completion(xhci, &event->event_cmd);		break;	case TRB_TYPE(TRB_PORT_STATUS):		handle_port_status(xhci, event);		update_ptrs = 0;		break;	case TRB_TYPE(TRB_TRANSFER):		ret = handle_tx_event(xhci, &event->trans_event);		if (ret < 0)			xhci->error_bitmask |= 1 << 9;		else			update_ptrs = 0;		break;	case TRB_TYPE(TRB_DEV_NOTE):		handle_device_notification(xhci, event);		break;	default:		if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=		    TRB_TYPE(48))			handle_vendor_event(xhci, event);		else			xhci->error_bitmask |= 1 << 3;	}	/* Any of the above functions may drop and re-acquire the lock, so check	 * to make sure a watchdog timer didn't mark the host as non-responsive.	 */	if (xhci->xhc_state & XHCI_STATE_DYING) {		xhci_dbg(xhci, "xHCI host dying, returning from "				"event handler.\n");		return 0;	}	if (update_ptrs)		/* Update SW event ring dequeue pointer */		inc_deq(xhci, xhci->event_ring);	/* Are there more items on the event ring?  Caller will call us again to	 * check.	 */	return 1;}
然后可以再根据log跟踪;以上信息仅供参考。

转载地址:http://gjngi.baihongyu.com/

你可能感兴趣的文章
Python __future__ 模块
查看>>
softmax回归
查看>>
TensorFlow入门学习(让机器/算法帮助我们作出选择)
查看>>
把项目从Python2.x移植到Python3.x的经验总结
查看>>
如何在python下安装xgboost
查看>>
xgboost特征选择
查看>>
kaggle数据挖掘竞赛初步--Titanic&lt;数据变换&gt;,kaggle--titanic
查看>>
XGBoost-Python完全调参指南-参数解释篇
查看>>
【scikit-learn】scikit-learn的线性回归模型
查看>>
广告点击率预测 [离线部分]
查看>>
广告点击率预估中的特征选择
查看>>
LIBSVM与LIBLINEAR(二)
查看>>
定向展示广告投放中的点击率预估模型简介
查看>>
十分钟搞定pandas
查看>>
数据科学入门,使用 xgboost 初试 kaggle
查看>>
利用 Python 进行数据分析(十二)pandas:数据合并
查看>>
十分钟搞定pandas
查看>>
sklearn的train_test_split
查看>>
xgboost入门与实战(实战调参篇) 标签: xgboostpythonkaggle机器学习
查看>>
[scikit-learn] 特征二值化编码函数的一些坑
查看>>