Wince 5.0 获取U盘描述符

最近由于项目需求,需要获取U盘的描述符。而现有的usb otg驱动中没有提供这样的接口。没有办法,只能自己动手来修改了。本人刚开始接触USB 驱动,在代码的海洋中还比较迷茫。以下代码的实现是公司内一位大牛所作,本人只是借来学习一用。也算对USB驱动有个初步的了解。

先罗嗦两句。刚开始看到文件夹usbotg,还有点不太理解是什么意思。当时在想,usb驱动为什么不直接放在usb文件夹下,而是放在usbotg文件夹下?otg是嘛意思?资料当然也很好找,usb家族里面,对该成员有详细介绍(http://www.usb.org/developers/onthego)。原来otg就是On The Go。

传统的usb协议中分为host 和function,一个设备,要么是host,要么是function。例如,一般PC是作为host,而其他的设备,U盘,打印机,相机等是作为function存在的。这样就有一个问题,对PC的依赖过大,离开了host PC,两个usb function在一起,只能干瞪眼,没办法进行交互。当然,两个host,通过usb cable接起来,也是互相不认识的。为了解决该问题,在usb 2.0的基础上,出现了otg的概念。

usbotg中,一个设备既可以作为host,也可以作为function。两个usb 设备连接到一起,根据功能的需要,其中一个(usb1)作为host,另外一个(usb2)作为function。如果功能改变了,需要把usb2作为host,而把usb1作为function,可以通过HNP(Host Negotiation Protocol)来实现。具体怎么实现,可以到usb老家里面看看协议。

由于懒惰,本人还没详细看过协议。此处只是介绍个皮毛。若有不妥之处,还望各位大虾指正。

好了,废话不多说了,一步步来看实现吧。

1、首先当然是考察可行性。

也就是驱动中是否能够提供这样的接口。调查发现,在otg driver中保存的g_OtgCoreInfo(OTG_CORE_INFO)变量中有一个m_dwHostContext成员,保存的是Host Controller Driver的Context。m_dwHostContext会在OTG_Init函数中被初始化,代码如下:

g_OtgCoreInfo.m_dwHostContext = HCD_Init((DWORD)&hostSettings);

Host Controller Driver中保存有一个g_dwPddContext(DWORD,其实是SEHCDPdd结构体的指针)变量,在函数HCD_Init(在MDD中)中会调用HcdPdd_Init函数来初始化该变量,并最终把该

变量作为函数返回值返回。代码如下:

g_dwPddContext =HcdPdd_Init(dwContext);

...

return g_dwPddContext;

HcdPdd_Init(在HDD中)函数中首先创建一个SEHCDPdd对象,然后调用InitializeEHCI函数初始化该对象,最后将该对象的指针返回。

SEHCDPdd * pPddObject = malloc(sizeof(SEHCDPdd));

...

fRet = InitializeEHCI(pPddObject, (POTG_HOST_SETTINGS)dwContext);

...

return (DWORD)pPddObject;

InitializeEHCI(在HDD中)函数中,初始化pPddObject变量中的各个成员,我们本次只关注成员lpvEHCDMddObject的初始化:

pobEHCD = HcdMdd_CreateHcdObject(pPddObject, pobMem, NULL, (PUCHAR)pHostSetting->m_dwRegBase, 0)

...

pPddObject->lpvEHCDMddObject = pobEHCD;

HcdMdd_CreateHcdObject函数(在MDD中)中调用CreateHCDObject函数创建HCD Object。并将对象指针返回。

CHcd * pobUhcd = CreateHCDObject(lpvUhcdPddObject,

(CPhysMem *)lpvMemoryObject,szRegKey,ioPortBase,dwSysIntr);

...

return pobUhcd;

CreateHCDObject函数(在HDD中)中,创建一个CEhcd对象,并返回。

return new CEhcd (pvUhcdPddObject, pCPhysMem,szDriverRegistryKey,portBase,dwSysIntr);

CEhcd类继承自CHW类,CHW类继承自CHcd类。CHcd类中包含一个CRootHub*类型的成员。

CRootHub* m_pCRootHub; // pointer to CRootHub object, which represents // the built-in hardware USB ports

CRootHub类继承自CHub类,CHub类继承自CDevice类。

CHub类中有函数获取当前hub上连接设备的列表。

CDevice** GetDeviceList() {return m_ppCDeviceOnPort;};

CDevice类包含一个m_deviceInfo(USB_DEVICE_INFO)成员变量,USB_DEVICE_INFO结构体中包含一个Descriptor(USB_DEVICE_DESCRIPTOR)成员,该成员就是用来保存USB设备的Descriptor信息的。USB_DEVICE_DESCRIPTOR结构体的内容是在USB协议中规定的。

2、既然找到了描述符的位置所在,接下来想办法把它提供出去就OK了。

首先,要追加个函数,把Descriptor的内容返回出去。该接口可以加在CDevice类,或者CHub类中。如果放在CDevice类中,只能获取该设备的Descriptor,如果想获取hub上连接的所有usb设备的descritor,还需要在CHub类,或其他地方追加接口,来对hub上连接的usb设备的list进行控制。这样比较麻烦,此处选择了一种比较懒省事的方法,在CHub类中追加接口函数(GetDeviceDescriptor),一次将hub上连接的所有usb设备的Descriptor全部取出。

遍历hub的所有port,也就是变量CHub类的成员变量m_ppCDeviceOnPort

(范围取min(m_usbHubDescriptor.bNumberOfPorts, MAX_DEVICE_PER_HUB))

判断port上是否有设备,若有,将设备的Descripror赋值给output buffer。

(lpudd[i] = m_ppCDeviceOnPort[i]->m_deviceInfo.Descriptor;)

3、最底层的实现有了,接下来就是如何把函数一步步输出去了。

此处有个疑问,既然上面有了底层实现,我们直接在IOControl函数中追加个IOConrol Code,然后调用底层的实现不就行了?相信有些初学者也有同样的疑问。看一下第一步中的分析,就应该比较清楚了。在第一步的分析中,可以发现,不同的对象,是在不同的层中创建的。对相应对象的操作,也都在对应的层中。如果我们跳过中间层,直接访问底层实现,就破坏了分层驱动的结构。

m_pCRootHub(CRootHub)是CEHcd类的一个成员变量,所以可以通过CEHcd的对象,来最终实现对上述函数的调用。CEHcd的对象是在函数HcdMdd_CreateHcdObject中创建的,所以我们可以在HcdMdd_CreateHcdObject函数定义的地方,追加一个函数(HcdMdd_GetHubConnectedDeviceDescriptor),来实现对底层实现的调用。假设Root hub上只接了我们的hub。首先通过m_pCRootHub获取root hub上设备的列表(CHub),然后调用列表中对象的GetDeviceDescriptor函数。

CDevice **lppcd = pobHcd->m_pCRootHub->GetDeviceList();

((CHub *)lppcd[0])->GetDeviceDescriptor(lpudd);

4、从第一步的分析中可知,HcdMdd_CreateHcdObject函数的返回值,被保存在了pPddObject(SEHCDPdd)的lpvEHCDMddObject成员中。pPddObject的创建和初始化是在HcdPdd_Init函数和InitializeEHCI函数中实现的。所以在HcdPdd_层中,我们可以追加函数(HcdPdd_GetHubConnectedDeviceDescriptor),实现对函数HcdMdd_GetHubConnectedDeviceDescriptor的调用。

HcdMdd_GetExtHubConnectedDeviceDesc(pPddObject->lpvEHCDMddObject, lpudd);

5、由步骤1的分析可知,HcdPdd_Init函数在HCD_Init函数中被调用。用来给全局变量g_dwPddContext赋值。所以,可以在HCD_层中,追加函数(HCD_GetHubConnectedDeviceDescriptor),通过保存的全局变量,实现对函数HcdPdd_GetHubConnectedDeviceDescriptor的调用。

6、继续往上,函数OTG_Init中调用了函数HCD_Init。终于到头了,此时,我们可以在OTG_IOControl函数中追加一个case,来调用函数HCD_GetHubConnectedDeviceDescriptor。当然,要追加相应的IOCTL Code的定义。

如果不需要Descriptor的全部信息,可以定义一个自己的结构体,在GetDeviceDescriptor函数中,取出Descriptor的部分成员,赋值给自己定义的结构体即可。

IOCTL 和结构体的定义,可以放在文件USB_def.h文件中。

参考:

typedef struct __OTG_CORE_INFO {

DWORD m_dwRegBase; // @field Base address of core registers

HINTR m_hSysIntr; // @field Handle returned by the OS_RegisterInterrupt

DWORD m_dwSysIntr; // @field System interrupt number of OTG controller

DWORD m_dwOpenCnt; // @field Open counter of the driver

DWORD m_dwHostContext; // @field Context of host controller driver

DWORD m_dwFuncContext; // @field Context of function controller driver

DWORD m_dwFuncBusContext; // @field context of function controller bus

BOOL bInSleepOrSM_Mode;

BOOL bInPowerHandler;

// Note: Implementation of the message queue is OS-dependent

HPROC m_hSrcProc; // @field Handle to a source process that owns the m_hMsgQ

HMSGQ m_hMsgQ; // @field Handle to opened message queue

DWORD m_dwPortNum;

DWORD m_dwPortMode;

} OTG_CORE_INFO, *POTG_CORE_INFO;

typedef struct _SEHCDPdd

{

LPVOID lpvMemoryObject;

LPVOID lpvEHCDMddObject;

PVOID pvVirtualAddress; // DMA buffers as seen by the CPU

DWORD dwPhysicalMemSize;

PHYSICAL_ADDRESS LogicalAddress; // DMA buffers as seen by the DMA controller and bus interfaces

DMA_ADAPTER_OBJECT AdapterObject;

TCHAR szDriverRegKey[MAX_PATH];

PUCHAR ioPortBase;

DWORD dwSysIntr;

CRITICAL_SECTION csPdd; // serializes access to the PDD object

HANDLE IsrHandle;

HANDLE hParentBusHandle;

} SEHCDPdd;

typedef struct _USB_DEVICE_INFO {

DWORD dwCount;

USB_DEVICE_DESCRIPTOR Descriptor;

LPNON_CONST_USB_CONFIGURATION lpConfigs;

LPNON_CONST_USB_CONFIGURATION lpActiveConfig;

} USB_DEVICE_INFO, * LPUSB_DEVICE_INFO;

typedef struct _USB_DEVICE_DESCRIPTOR

{

BYTE bLength;

BYTE bDescriptorType;

BYTE bcdUSBLo;

BYTE bcdUSBHi;

BYTE bDeviceClass;

BYTE bDeviceSubClass;

BYTE bDeviceProtocol;

BYTE bMaxPacketSize0;

BYTE idVendorLo;

BYTE idVendorHi;

BYTE idProductLo;

BYTE idProductHi;

BYTE bcdDeviceLo;

BYTE bcdDeviceHi;

BYTE iManufacturer;

BYTE iProduct;

BYTE iSerialNumber;

BYTE bNumConfigurations;

} USB_DEVICE_DESCRIPTOR, * PUSB_DEVICE_DESCRIPTOR;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值