驱动程序中USB设备的配置过程(参考Windows XP DDK)

驱动程序中USB设备的配置过程(参考Windows XP DDK)

DDK驱动程序写得很规范,USB初始化、数据传输的过程写的很清楚。通过阅读DDK驱动程序,我对原来USB驱动程序中许多不理解的地方有了更清楚的理解.下面就参照DDK提供的iso_usb例子对USB设备的配置过程进行总结。

1.驱动程序加载后首先执行DriverEntry入口函数。

该函数设定了对各个IRP进行处理的派遣函数。 

2.DriverEntry函数执行完成后,开始执行AddDevice函数。

这个函数创建设备对象把设备对象连接到设备堆栈上,清除DO_DEVICE_INITIALIZING标志。然后配置管理器(不是IO管理器)向驱动程序发送一个即插即用请求 IRP_MN_START_DEVICE,而调用下面的HandleStartDevice函数。 

3. 在HandleStartDevice函数中完成了USB设备的配置过程:

首先为设备选择一个配置(大多数设备仅有一种配置)。

选定了某种配置后,接着应该选择配置中的一个或多个接口

然后向总线驱动程序发送配置选择URB总线驱动程序接收到该URB后向设备发出命令使用选定的配置和接口。 

(1)为设备选择配置的过程其实就是获取设备的配置描述符的过程。Iso_usb中使用了两个URB来读取配置描述符。

//首先获取固定大小的配置描述符,这时,此描述符不包含接口描述符和端点描述符。 

siz = sizeof(USB_CONFIGURATION_DESCRIPTOR); 

configurationDescriptor = ExAllocatePool(NonPagedPool, siz); 

if(configurationDescriptor)

 {   

//UsbBuildGetDescriptorRequest函数构造指定类型的urb        

UsbBuildGetDescriptorRequest(

urb,                

(USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),               

USB_CONFIGURATION_DESCRIPTOR_TYPE,                

0,                

0,                

configurationDescriptor,               

NULL,                

sizeof(USB_CONFIGURATION_DESCRIPTOR),                

NULL);   

//CallUSBD函数负责把urb转发到底层总线驱动程序         

ntStatus = CallUSBD(DeviceObject, urb);         

…… 

}

 …… 

//然后获取全部的配置描述符,包括接口描述符和端点描述符 

siz = configurationDescriptor->wTotalLength; 

ExFreePool(configurationDescriptor); 

configurationDescriptor = ExAllocatePool(NonPagedPool, siz);

if(configurationDescriptor) 

{         

UsbBuildGetDescriptorRequest(               

urb,                

(USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),               

USB_CONFIGURATION_DESCRIPTOR_TYPE,               

0,                

0,                

configurationDescriptor,                

NULL,                

siz,                

NULL);         

ntStatus = CallUSBD(DeviceObject, urb);         

…… 

(2)从配置描述符中提取感兴趣的接口描述符,

总线驱动程序提供了函数USBD_ParseConfigurationDescriptorEx以简化这个过程。 

interfaceDescriptor =USBD_ParseConfigurationDescriptorEx(                            

ConfigurationDescriptor,                                      

ConfigurationDescriptor,                                    

interfaceindex,                                    

0,          

-1, 

-1, 

-1); 

该函数各个参数的含义是:

第一个参数是上一步获取的完整的配置描述符;

第二个参数是描述符内部开始搜索的地址,如果从头开始搜索,需要设置和第一个参数相同;

剩下的五个参数是和感兴趣的接口相关搜索关键字,分别是InterfaceNumber, AlternateSetting, InterfaceClass, InterfaceSubClass, InterfaceProtoco。但相关的关键字不 需要的时候,可以设置成-1。 

由于配置描述符中可能包含多个接口,所以驱动程序需要将上述函数返回的接口描述符保存在USBD_INTERFACE_LIST_ENTRY类型的数组中。

iso_usb程序:

首先使用ExAllocatePool函数为接口描述符分配足够的内存。 

interfaceList =ExAllocatePool( NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (numberOfInterfaces + 1)); 

然后通过循环使用USBD_ParseConfigurationDescriptorEx函数获取的接口描述符对数组进行初始化。初始化时,应该把接口描述符地址赋给 USBD_INTERFACE_LIST_ENTRY结构的InterfaceDescriptor成员,并把Interface成员置NULL。

最后需要将数组的最后一个元素的两个成员全部置为NULL。 

(3)初始化接口。

首先调用USBD_CreateConfigurationRequestEx函数创建一个urb。

然后需要对接口中的管道进行相应的初始化,

最后将这个urb传递给底层驱动程序,由底层总线驱动程序完成接口的初始化。 

urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, tmp); Interface = &urb->UrbSelectConfiguration.Interface;

//需要初始化管道的MaximumTransferSize成员。它代表单一URB能携带的最大数据量 

for(i=0; i<Interface->NumberOfPipes; i++)

 {             

Interface->Pipes[i].MaximumTransferSize = <constant>         

ntStatus = CallUSBD(DeviceObject, urb); 

(4)但USB设备配置完成之后,应该将一些句柄保存到设备扩展中供以后使用。 

Ø         URB成员UrbSelectConfiguration.ConfigurationHandle返回配置句柄; 

Ø         USBD_INTERFACE_INFORMATION结构中InterfaceHandle返回接口句柄; 

Ø         每个USBD_PIPE_INFORMATION结构中都含有与端点对应的管道句柄PipeHandle 

(5)关闭设备。

当驱动程序接到一个IRP_MN_STOP_DEVICE请求时,应该把设备置成为配置状态,创建并传递一个含有NULL配置指针的配置选择URB可以达到这个目的。 

siz = sizeof(struct _URB_SELECT_CONFIGURATION); 

urb = ExAllocatePool(NonPagedPool, siz); 

UsbBuildSelectConfigurationRequest(urb, (USHORT)siz, NULL); 

ntStatus = CallUSBD(DeviceObject, urb);



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值