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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值