USB Device Desctiptor 相关
前面有篇文章说到如何获取U盘描述符,最终我们读取描述符的时候是通过以下语句实现的:
lpudd[i] = m_ppCDeviceOnPort[i]->m_deviceInfo.Descriptor;
将驱动中保存的Desctiptor信息,赋值到传入的buffer中。因此,引出来一个问题,驱动中保存的Descriptor信息是什么时候产生的?宏观上来讲,应该是USB Device插入的时候,驱动从USB Device读取相关信息,并最终生成Descriptor。但具体是怎么实现的呢?今天就来分析一下这个过程。
首要的工作当然还是顺藤摸瓜,一步步找到入口。一步步跟踪下来,发现最初的启动点上函数OTG_Init。这次采用自上而下的方式来分析该过程。
1、OTG_Init函数中调用函数HCD_Init来初始化host controller。
g_OtgCoreInfo.m_dwHostContext = HCD_Init((DWORD)&hostSettings);
2、HCD_Init函数中,首先从输入参数host setting中获取中断线程优先级,并保存在全局变量中。接下来,调用函数HcdPdd_Init。
POTG_HOST_SETTINGS pHostSettings = (POTG_HOST_SETTINGS)dwContext;
...
g_IstThreadPriority = pHostSettings->m_dwISTPriority;
...
g_dwPddContext =HcdPdd_Init(dwContext);
...
return g_dwPddContext;
可见,通过调用函数HcdPdd_Init获取PDD上下文环境,在本层中保存一份到全局变量,同时返回给上一层。
3、HcdPdd_Init函数中首先创建一个SEHCDPdd结构体对象。然后以该对象的指针,和host setting指针为参数,调用函数InitializeEHCI。函数InitializeEHCI的实现在本层中。
SEHCDPdd * pPddObject = malloc(sizeof(SEHCDPdd));
...
fRet = InitializeEHCI(pPddObject, (POTG_HOST_SETTINGS)dwContext);
...
return (DWORD)pPddObject;
4、InitializeEHCI函数中,主要初始化SEHCDPdd结构体对象的各个成员。这次来看看各个成员的初始过程吧,逃避解决不了问题,好歹先混个脸熟。
// 指定HCI driver使用的共享内存的大小,以及其中高优先级内存的大小。
// MSDN的HcdMdd_CreateMemoryObject函数的说明中,建议共享内存的大小为64KB,高优先级内存的大小为20KB。若
// 高优先级内存小于20KB,可能产生由于内存分配失败导致的同步传输错误。低优先级内存小于44KB,不会产生同步传输错误
// 不过,可能会降低性能。
pPddObject->dwPhysicalMemSize = gcTotalAvailablePhysicalMemory;
dwHPPhysicalMemSize = gcHighPriorityPhysicalMemory;
// 初始化DMA Adapter的属性
pPddObject->AdapterObject.ObjectSize = sizeof(DMA_ADAPTER_OBJECT);
pPddObject->AdapterObject.InterfaceType = PCIBus;
pPddObject->AdapterObject.BusNumber = 0;
// 分配DMA用的共享buffer
// Allocates a shared buffer (physically contiguous pages, locked) and returns
// the virtual address (to be used by the DMA device driver) and the logical
// address (to be used by the DMA adapter) for DMA operations.
pPddObject->pvVirtualAddress = // 共DMA device driver使用的虚拟地址
HalAllocateCommonBuffer(
&pPddObject->AdapterObject, // Pointer to DMA adapter descriptor. pPddObject->dwPhysicalMemSize, // Size of buffer to allocate.
&pPddObject->LogicalAddress, // Pointer to logical (bus-relative) address buffer
FALSE // Flag to choose cached or uncached buffer allocation.
)
// 创建host controller interface使用的共享内存
// HcdMdd_CreateMemoryObject函数具体介绍请参考msdn
pobMem = // host controller driver memory object
HcdMdd_CreateMemoryObject(
pPddObject->dwPhysicalMemSize, // Total size of the host controller device shared memory area.
dwHPPhysicalMemSize, // Specifies the bytes reserved for high-priority isochronous or interrupt // transfers and the host controller interface (HCI) communication area.
(PUCHAR) pPddObject->pvVirtualAddress, // Pointer to the virtual address of a memory area, which // might be NULL.
(PUCHAR) pPddObject->LogicalAddress.LowPart // Pointer to the physical address of a memory area, // which might be NULL.
)
// 接下来到我们这次分析的重点了
// 创建并初始化host controller interface driver对象
pobEHCD = HcdMdd_CreateHcdObject(pPddObject, pobMem, NULL, (PUCHAR)pHostSetting->m_dwRegBase, 0)
// 将创建的对象赋值到成员变量中
pPddObject->lpvMemoryObject = pobMem;
pPddObject->lpvEHCDMddObject = pobEHCD;
// 其他成员初始化
pPddObject->ioPortBase = (PUCHAR)pHostSetting->m_dwRegBase;
pPddObject->dwSysIntr = 0;
HcdMdd_SetCapability(pobEHCD,pHostSetting->m_dwCapability);
5、HcdMdd_CreateHcdObject函数中首先调用CreateHCDObject函数创建host controller interface driver对象。然后调用host controller interface driver对象的DeviceInitialize函数初始化该对象。
CHcd * pobUhcd =
CreateHCDObject(lpvUhcdPddObject,(CPhysMem *)lpvMemoryObject,szRegKey,ioPortBase,dwSysIntr);
...
pobUhcd->DeviceInitialize( )
...
return pobUhcd;
6、CreateHCDObject函数中,直接创建一个CEhcd对象并返回。
7、DeviceInitialize函数的注释如下:
// Set up the Host Controller hardware, associated data structures,
// and threads so that schedule processing can begin.
// Re初始化内存
m_pMem ->ReInit();
// 调用父类初始函数
BOOL fCDeviceInitOK = CDeviceGlobal::Initialize(this);
BOOL fCHWInitOK = CHW::Initialize( );
// 设置root hub的相关属性,set up the root hub object
...
// 设置CEhcd对象的root hub
SetRootHub( new CRootHub( deviceInfo, FALSE,TRUE, usbHubDescriptor,this ));
// Signal root hub to start processing port changes // The root hub doesn't have any pipes, so we pass NULL as the // endpoint0 pipe
GetRootHub()->EnterOperationalState( NULL )
8、函数CRootHub::EnterOperationalState中创建event, device array,线程。
// 创建hub status change event
// m_hHubStatusChangeEvent - Auto Reset, and Initial State = non-signaled
m_hHubStatusChangeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
// Allocate memory for the device array of this hub based on
// the number of ports given in the m_usbHubDescriptor structure
AllocateDeviceArray()
// 创建线程,并设置线程优先级
m_hHubStatusChangeThread = CreateThread( 0, 0, HubStatusChangeThreadStub, this, 0, NULL );
CeSetThreadPriority( m_hHubStatusChangeThread, g_IstThreadPriority);
此处说明一下,上面列出的EnterOperationalState函数的实现,是属于类CRootHub的。类CExternalHub中也有函数EnterOperationalState的实现。类的继承关系:
// CDevice (ADT)
// / /
// CFunction CHub (ADT)
// / /
// CRootHub CExternalHub
9、函数CHub::HubStatusChangeThreadStub中将传入的指针转化为CHub类的指针,并调用其HubStatusChangeThread函数。
return ((CHub*)context)->HubStatusChangeThread();
10、HubStatusChangeThread函数,处理hub上port状态的改变。
// before we can process port changes, we need
// to power all ports
// 跟过去发现,函数CRootHub::PowerAllHubPorts中除了打了两句log,返回了个TRUE,其他什么也没干。
// 不过,函数CExternalHub::PowerAllHubPorts中还是有具体动作的。
fSuccess = PowerAllHubPorts();
// 延迟
Sleep( 100 + 2 * m_usbHubDescriptor.bPowerOnToPowerGood );
// Set or clear a remove wakeup feature External HUB.
// 从注释可见,该函数主要是针对External HUB的。root hub中该函数为空。
SetOrClearRemoteWakup(TRUE);
...
// 本来想把该Thread函数中的每条语句仔细阅读一遍,不过发现这不是短时间可以完成的。
// 此处先不细看了,留个作业,改天再细细品味
// 等待port状态改变事件
fSuccess = WaitForPortStatusChange( port, hubStatus );
// 判断是否是连接状态改变
if ( hubStatus.change.port.ConnectStatusChange )
// Reset port and get speed infomation.
ResetAndEnablePort( port );
Sleep(20);
GetStatus(port , hubStatus);
// 判断Port是否连接
if ( hubStatus.status.port.PortConnected )
//调用函数AttachDevice
AttachDevice( port, hubStatus.status.port.DeviceIsLowSpeed, m_fIsHighSpeed?hubStatus.status.port.DeviceIsHighSpeed:FALSE );
11、AttachDevice函数中,根据当前的状态,判断下一步该作什么操作,逐步完成device 的attach操作。
// 在状态DEVICE_CONFIG_STATUS_SCHEDULING_SET_CONFIG的时候,会去判断连接的设备是hub还是function。
if ( deviceInfo.Descriptor.bDeviceClass == USB_DEVICE_CLASS_HUB )
// 如果是hub,会创建一个CExternalHub对象
pNewDevice = new CExternalHub( address, deviceInfo, fIsLowSpeed,fIsHighSpeed, m_tierNumber + 1, usbHubDescriptor, m_pCHcd, this,port);
// 如果是Function,会创建一个Function对象
pNewDevice = new CFunction( address, deviceInfo, fIsLowSpeed,fIsHighSpeed, m_tierNumber + 1, m_pCHcd, this,port);
// 将新创建的对象对象追加到DeviceOnPort对象列表
m_ppCDeviceOnPort[ port - 1 ] = pNewDevice;
// 然后调用该对象的EnterOperationalState函数。
pNewDevice->EnterOperationalState( pControlPipe )
在创建hub或者Function对象的时候,构造函数中有一个参数deviceInfo。在父类CDevice的构造函数中,该参数被赋值给了成员变量m_deviceInfo(USB_DEVICE_INFO)。结构体USB_DEVICE_INFO中有一个成员Descriptor,记述的就是设备的描述符。
在函数AttachDevice函数中,状态为DEVICE_CONFIG_STATUS_SCHEDULING_GET_DEVICE_DESCRIPTOR的时候,会调用函数GetDescriptor获取设备的描述符。
函数GetDescriptor中通过调用函数CPipeAbs::IssueTransfer来获取描述符。
status = pControlPipe->IssueTransfer( address, // address of device TransferDoneCallbackSetEvent, // callback routine m_hHubStatusChangeEvent, // callback param USB_IN_TRANSFER | USB_SEND_TO_DEVICE, // transfer flags &usbRequest, // control request 0, // dwStartingFrame (not used) 0, // dwFrames (not used) NULL, // aLengths (not used) wDescriptorSize, // buffer size pBuffer, // buffer 0, // phys addr of buffer (not used) this, // cancel ID NULL, // adwIsochErrors (not used) NULL, // adwIsochLengths (not used) &m_fTransferDone, // OUT status param &m_dwBytesTransferred, // OUT status param &m_dwErrorFlags ); // OUT status param
CPipeAbs的对象,在函数AttachDevice中状态为DEVICE_CONFIG_STATUS_OPENING_ENDPOINT0_PIPE时被创建。
pControlPipe = CreateControlPipe( &usbEndpointZeroDescriptor, fIsLowSpeed, fIsHighSpeed ,0, uTTHubAddr,uTTHubPort, m_pCHcd);
函数CControlPipe创建一个CControlPipe对象。
return new CControlPipe(lpEndpointDescriptor,fIsLowSpeed,fIsHighSpeed,bDeviceAddress,
bHubAddress,bHubPort,(CEhcd * const)pChcd);
Pipe相关类的继承关系:
// CPipe (ADT) // / / // CQueuedPipe (ADT) CIsochronousPipe // / | / // / | / // CControlPipe CInterruptPipe CBulkPipe
函数CControlPipe::IssueTransfer函数中,调用函数CQueuedPipe::IssueTransfer来实现具体功能。
HCD_REQUEST_STATUS status = CQueuedPipe::IssueTransfer( address, lpStartAddress,lpvNotifyParameter, dwFlags,lpvControlHeader, dwStartingFrame, dwFrames, aLengths, dwBufferSize, lpvClientBuffer, paBuffer, lpvCancelId, adwIsochErrors, adwIsochLengths, lpfComplete, lpdwBytesTransferred, lpdwError );
函数CQueuedPipe::IssueTransfer中创建一个CQTransfer对象,并将其加到m_pUnQueuedTransfer队列中。接下来调用函数ScheduleTransfer。
函数CQueuedPipe::ScheduleTransfer中设置m_pQueuedTransfer。从m_pUnQueuedTransfer队列中取出第一个,赋值给m_pQueuedTransfer。然后Queue Transfer。
// 调用函数GetQHead获取m_pPipeQHead。
GetQHead()
// m_pPipeQHead在CControlPipe::OpenPipe函数中被创建
m_pPipeQHead = new( m_pCEhcd->GetPhysMem()) CQH (this);
// 接下来调用函数CQH::QueueTD
GetQHead()->QueueTD(pCurTransfer->GetCQTDList())
函数CQH::QueueTD中存在以下语句:
// This will activate the TD trasnfer.
nextQTDPointer.dwLinkPointer =pCurTD->GetPhysAddr();
函数CQueuedPipe::ScheduleTransfer中若不能Queue Transfer,则调用函数CQueuedPipe::CheckForDoneTransfers检查传输是否完成。
函数CQueuedPipe::CheckForDoneTransfers中调用函数CQTransfer::DoneTransfer。
函数CQTransfer::DoneTransfer中回调函数m_sTransfer.lpStartAddress
( *m_sTransfer.lpStartAddress )(m_sTransfer.lpvNotifyParameter );
追溯可以发生,m_sTransfer.lpStartAddress指向的是函数CDevice::TransferDoneCallbackSetEvent。其实现如下:
SetEvent( (HANDLE) context );
此处set的event,是函数GetDescriptor调用函数CPipeAbs::IssueTransfer时传入的参数m_hHubStatusChangeEvent。
函数CRootHub::WaitForPortStatusChange中有对事件m_hHubStatusChangeEvent的等待。
转载于:https://www.cnblogs.com/andriod-html5/archive/2011/04/01/2539597.html
USB Device Desctiptor 相关相关推荐
- S3C2440 WINCE6将USB DEVICE改成USB HOST,实现两个USB HOST
S3C2440一般默认的是一个USB DEVICE,一个USB HOST,即一个主口,一个从口,先来看看USB Device与USB Host相关知识. USB Host: 最底层就是USB Host ...
- STM32驱动开发(二)--USB Device RNDIS虚拟网卡(USB2.0 基础概念讲解)
STM32驱动开发(二)–USB Device RNDIS虚拟网卡(USB2.0基础概念讲解) 一.简介 本文基于stm32 Rndis实例,github开源, 使用STM32F407单板.结合协 ...
- 20200213ubuntu20.04下的笔记本USB摄像头的相关资料
20200213ubuntu20.04下的笔记本USB摄像头的相关资料 rootroot@rootroot-HP-Laptop-14s-dp0xxx:~$ rootroot@rootroot-HP- ...
- USB device USB controller USB passthrough
近期往 openstack 里倒腾 USB passthrough[1],遂把 USB 知识做较为全面的整理,以供分享. USB device 什么是 USB device, 上图机智的小萌狗就是 U ...
- UDC (usb device controller) Framework - USB gadget driver framework
http://blog.csdn.net/u011279649/article/details/11059433 USB gadget driver的框架可分为三部分:UDC-core, compos ...
- Vmware提示:host usb device connections disabled-(vmware 主机已禁用 usb 设备连接)
Vmware提示:host usb device connections disabled-(vmware 主机已禁用 usb 设备连接) VMware Workstation,提示提示Host US ...
- USB查看器 USB Device Tree Viewer(UsbTreeView.exe)的使用(重启Intel Realsense摄像头)
文章目录 简介 打开后界面 测试U盘弹出后是否能找回 测试挽回掉线的摄像头 简介 USB Device Tree Viewer是一个非常实用的USB设备查看器,它可以发现所有的usb接口的使用情况,并 ...
- StackOverflow How to programmatically unplug replug an arbitrary USB device? 如何以编程方式拔出并重新插入任意USB设备
文章目录 方法1:通过devcon工具重启usb hub 像这种情况,明明插了六个摄像头,它偏偏掉一个... 刚好,我们可以测试How to programmatically unplug & ...
- USB device如何进入suspend模式
1. 当没有使能usb device(usb_conf DEVEN没有置1),device处于L3状态 2. 当使能了usb device,但是没有连接到host,device处于L2(suspend ...
- Start booting from USB device boot failed 解决办法(老机器问题)
Start booting from USB device boot failed 解决办法 问题: 一般情况下,我们设置电脑BIOS USB 第一启动方式最重要的两步: 1.Removable De ...
最新文章
- 表格下划线怎么加粗_这招高!Excel签名栏的下划线随列宽变化,是不是感觉牛哄哄的?...
- String.format()【演示具体的例子来说明】
- 滴滴重磅发布:KDD2018大会187页人工智能+交通教程
- python画折线图代码-Python折线图的分析过程和画图的方法
- IE6 CSS的一个bug
- 面向新闻媒体的命名实体识别技术
- 简单的二叉树创建与遍历
- FreeRTOS+STM32F103中断中发送任务通知单片机死机问题
- wpf的控件style
- 一起来学习BERT常见的几个变体
- STM32F407 窗口看门狗 个人笔记
- matlab网格划分提取坐标,ANSYS-划分网格后导出单元和结点坐标等信息
- cad字体安装_为什么CAD图纸打开后会显示很多问号“???”,该怎么解决
- is 简写 缩写_为什么e.g.是for example的缩写?它和i.e.是什么关系?
- css中repeat用法,CSS background-repeat用法及代码示例
- 【直播教程】直播间没人看?5大技巧教你提升!
- 前端大佬谈国产开源:VUE 的成功在于社区运营
- iOS 内购 payment.applicationUsername 的坑
- 计算机应用1.2版,201303《计算机应用基础》在线作1_2.doc
- 论文笔记-建筑能源管理的强化模型预测控制
热门文章
- FISCO BCOS 区块链 学习开发步骤
- thinkphp 访问根目录文件
- 计算机科学与技术志愿意愿,高考志愿填报如何得高分
- java中修改对象类的数据_Java中创建对象的六个步骤 细分后(new关键字)对象头详细介绍...
- ORM框架使用优缺点
- Centos7.x 安装Kubernetes(K8s) 1.16.2 kubeadm kubelet kubectl 单机版 2019-10-20更新
- nginx 禁止访问配置,指定URL地址指定IP允许访问
- 2.4.PHP7.1 狐教程-【PHP常量】
- JMS 基本概念、消息结构、确认模式 acknowledgeMode
- 阶段3 3.SpringMVC·_06.异常处理及拦截器_2 SpringMVC异常处理之演示程序异常