WinCE6.0 USB Host驱动加载流程详解(一)

 http://jazka.blog.51cto.com/809003/743720

    前面已经讲过WinCE6.0USB驱动的整体结构,今天来看看USB Host驱动部分。可能是因为USB Host驱动一般不修改的原因,这方面的资料少的可怜,所以只能自己研究了。分析的源码微软已经提供了,在目录WINCE600\PUBLIC\COMMON\OAK\DRIVERS\USB下面。

    该目录下包含CLASSUSBDHCDCOMMONINC文件夹,其中COMMONINC文件夹中包含的一个关于锁功能的文件lock.cHCD文件夹中是对USB1.1USB2.0等协议的支持,为USBD提供操作控制器的接口,一般不会去做修改,这里不去深究。

USBD
LIBRARY                 USBD
EXPORTS
                                HcdAttach
                                HcdDetach
                                HcdDeviceAttached
                                HcdDeviceDetached
                                HcdSelectConfiguration
                                RegisterClientDriverID
                                UnRegisterClientDriverID
                                OpenClientRegistryKey
                                GetClientRegistryPath
                                RegisterClientSettings
                                UnRegisterClientSettings
                                GetUSBDVersion
    在系统启动之后,由设备管理器device.exe加载USBD.DLL驱动程序,入口同样是函数DllMain(),之后调用HcdAttach()函数初始化一些Hcd控制器的资源,包括一些接口函数的列表。具体有哪些函数,后面会讲到。到这里USBD.DLL启动完成。
    一般来说,大部分驱动都是由device.exe进程根据注册表信息进行加载的,当第一次插入USB设备时,由于注册表不存在相关的信息,会提示未能识别的USB设备,要求用户输入驱动程序的名称,即驱动DLL的文件名。那么下面看看这一过程在代码中是如何实现的?
    当插入USB设备之后,系统调用USBD.DLL驱动中的HcdDeviceAttached()函数。该函数内,首先调用LoadDeviceDrivers()函数来加载USB设备对应的Client层驱动,具体如何调用下面再讲。如果没有找到合适的驱动,加载失败了,便会调用函数GetClientDriverName(),该函数执行的功能便是提示用户无法识别USB设备,请输入相应的驱动程序名称,以便系统加载。
    解释了上面的问题后,看一下LoadDeviceDrivers()函数是如何查找正确的Client层驱动的。当插入USB设备之后,系统会读取USB的设备描述符,然后根据描述符的值在注册表HKEY_LOCAL_MACHINE\Drivers\USB\LoadClients下面进行扫描来查找相应的驱动程序。该注册表的键值格式为:LoadClients/<Group1 Id>/<Group2 Id>/<Group3 Id>/<Driver Name>
这里称为第一组\第二组\第三组,每组又是由三个值中间加下划线组成,如下:
第一组:dwVendorId_dwProductId_dwReleaseNumber
第二组:dwDeviceClass_dwDeviceSubClass_dwDeviceProtocol
第三组:dwInterfaceClass_dwInterfaceSubClass_dwInterfaceProtocol
    如果有一个值设置为USB_NO_INFO,则键名不包括该值。如果整个组中每个值都设置成USB_NO_INFO,则键名为Default。具体的每组包含的值的意义,请查阅相关资料。
    在扫描注册表找到相应的驱动之后,LoadDeviceDrivers()函数调用LoadUSBClient()函数加载Client驱动。加载的流程为:LoadUSBClient()函数调用LoadRegisteredDriver()函数,在LoadRegisteredDriver()内,获取到Client驱动的DLL名称之后,调用LoadDriver()函数将驱动程序加载到自己的虚拟地址空间,接着便通过GetProcAddress()函数获得Client驱动中USBDeviceAttach()函数的地址,最后执行USBDeviceAttach()函数,运行Client驱动程序。
    回到上面,如果没有找到匹配的驱动,则会提示用户输入驱动的名称,在用户输入之后,HcdDeviceAttached()便调用InstallClientDriver()函数,该函数里面通过LoadLibrary()函数将驱动程序映射到当前的虚拟地址空间,接着通过GetProcAddress()函数获得Client驱动中USBInstallDrvier()函数的地址,同时执行该函数完成相关注册表的设置。最后回到循环中,继续执行LoadDeviceDrivers()函数。
       上面运行的LoadDriver()LoadLibrary()函数会在第一次加载对应的驱动的时候,运行驱动程序的DllMain()入口函数。到这里就解释了从USBD驱动转向了Client驱动的整个过程。
解释一下上面提到的几个函数。USBInstallDriver函数负责向注册表添加USB设备驱动的信息,以便下次插入时,能够识别该USB设备。USBUnInstallDriver是在设备被移除后清理写入注册表的配置。USBDeviceAttach是在每次插入USB设备时,由系统调用来初始化USB设备、获取USB信息、配置USB以及申请资源。这里需要注意的是下面将要提到的USBD接口函数列表结构体_USB_FUNCS也是通过该函数传入具体的Client驱动中的。上面的这三个接口函数是每一个Client层驱动必须实现的接口。
BOOL USBDeviceAttach(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,
                                         LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId,
                                         LPBOOL fAcceptControl,
                                         LPCUSB_DRIVER_SETTINGS lpDriverSettings, DWORD dwUnused);
BOOL USBInstallDriver(LPCWSTR szDriverLibFile);
BOOL USBUnInstallDriver();
VOID GetUSBDVersion(LPDWORD lpdwMajorVersion, LPDWORD lpdwMinorVersion);
BOOL RegisterClientDriverID(LPCWSTR szUniqueDriverId);
BOOL UnRegisterClientDriverID(LPCWSTR szUniqueDriverId);
BOOL RegisterClientSettings(LPCWSTR lpszDriverLibFile,
                                                        LPCWSTR lpszUniqueDriverId, LPCWSTR szReserved,
                                                        LPCUSB_DRIVER_SETTINGS lpDriverSettings);
BOOL UnRegisterClientSettings(LPCWSTR lpszUniqueDriverId, LPCWSTR szReserved,
                                                            LPCUSB_DRIVER_SETTINGS lpDriverSettings);
HKEY OpenClientRegistryKey(LPCWSTR szUniqueDriverId);
BOOL GetClientRegistryPath(LPWSTR szRegistryPath, DWORD dwRegPathUnit, LPCWSTR szUniqueDriverId);
    可以看出上面几个函数都是通过def文件显式导出的。除此之外,usbdi.h中还有一个函数指针列表结构体_USB_FUNCS,里面包含了USBD的另外一部分接口,是在def中没有导出的,通过函数指针结构体在驱动之间进行传递的。_USB_FUNCS中的函数指针的实体都在文件usbddrv.cpp的文件中,整个USB驱动只有一个_USB_FUNCS的全局变量gc_UsbFuncs,它的声明及初始化在usbd.c中。在始化ddrv.c
    USBD提供的主要接口函数归类如下:
USBD的传输函数
IssueControlTransfer      IssueBulkTransfer     IssueInterruptTransfer              IssueIsochTransfer
IsTransferComplete              GetTransferStatus     GetIsochResults                AbortTransfer
CloseTransfer
USBDUSB设备建立通讯管道的函数
OpenPipe                            AbortPipeTransfers        ResetPipe                            ClosePipe
IsPipeHalted                 IsDefaultPipeHalted       ResetDefaultPipe
USBD针对总线上数据打包的函数
GetFrameNumber          GetFrameLength           TakeFrameLengthControl
SetFrameLength            ReleaseFrameLengthControl
USBDUSB设备进行交互的函数
OpenClientRegistryKey         RegisterNotificationRoutine         UnRegisterNotificationRoutine
GetUSBDVersion                 LoadGenericInterfaceDriver         TranslateStringDescr
FindInterface                       RegisterClientDriverID                UnRegisterClientDriverID
GetDeviceInfo                     RegisterClientSettings                  UnRegisterClientSettings
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值