USBCCGP 配置设备
获取设备的配置描述符通过前面已经知道,其包括的内容比较多,如接口描述符、端点描述符等,其中有很多我们进行数据通讯的信息,所以下来我们就要对设备进行配置。
在USBCCGP USB复合设备驱动中,由于其将各个独立的接口会枚举成一个单独的设备,所以一般情况下有几个接口描述符就会被枚举成几个设备(UVC设备除外).
USB设备的配置,就是对其配置描述符的解析分隔归类。
1.根据接口描述符的数量逐步使用函数USBD_ParseConfigurationDescriptorEx
进行解析,并分别存储在USBD_INTERFACE_LIST_ENTRY
中。
2.然后通过调用函数USBD_CreateConfigurationRequestEx,其上面1解析出的各个接口描述符数据传进行,返回一个URB.
3.将这个URB同步调用下层PDO,返回选择后的接口描述符。选择后的接口描述符是被下层总线驱动初始化的,其含有可直接进行数据通讯的信息。
4.将这些选择后的接口描述符存储,以待数据通读或枚举子设行时使用。
配置描述符的入口函数是:USBCCGP_SelectConfiguration
descriptor.c
NTSTATUS
USBCCGP_SelectConfiguration(
IN PDEVICE_OBJECT DeviceObject,
IN PFDO_DEVICE_EXTENSION DeviceExtension)
{
PUSBD_INTERFACE_INFORMATION InterfaceInformation;
NTSTATUS Status;
PURB Urb;
ULONG Index;
//
// now scan configuration descriptors
//
Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor);
if (!NT_SUCCESS(Status))
{
//
// failed to scan
//
return Status;
}
//
// now allocate the urb
//
Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList);
if (!Urb)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// submit urb
//
Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
if (!NT_SUCCESS(Status))
{
//
// failed to set configuration
//
DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status);
ExFreePool(Urb);
return Status;
}
//
// get interface information
//
InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++)
{
//
// allocate buffer to store interface information
//
DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length);
if (!DeviceExtension->InterfaceList[Index].Interface)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// copy interface information
//
RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length);
//
// move to next interface
//
InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
}
//
// store pipe handle
//
DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
//
// free interface list & urb
//
ExFreePool(Urb);
//
// done
//
return Status;
}
可以看到,
1.首选是进行接口描述符的解析,使用函数USBCCGP_ScanConfigurationDescriptor
来实现。
NTSTATUS
NTAPI
USBCCGP_ScanConfigurationDescriptor(
IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
{
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
ULONG InterfaceIndex = 0;
ULONG DescriptorCount;
//
// sanity checks
//
ASSERT(ConfigurationDescriptor);
ASSERT(ConfigurationDescriptor->bNumInterfaces);
//
// count all interface descriptors
//
DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
if (DescriptorCount == 0)
{
DPRINT1("[USBCCGP] DescriptorCount is zero\n");
return STATUS_INVALID_PARAMETER;
}
//
// allocate array holding the interface descriptors
//
FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
if (!FDODeviceExtension->InterfaceList)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// reset interface list count
//
FDODeviceExtension->InterfaceListCount = 0;
do
{
//
// parse configuration descriptor
//
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
if (InterfaceDescriptor)
{
//
// store in interface list
//
ASSERT(FDODeviceExtension->InterfaceListCount < DescriptorCount);
FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
FDODeviceExtension->InterfaceListCount++;
}
else
{
DumpConfigurationDescriptor(ConfigurationDescriptor);
DumpFullConfigurationDescriptor(FDODeviceExtension, ConfigurationDescriptor);
//
// see issue
// CORE-6574 Test 3 (USB Web Cam)
//
if (FDODeviceExtension->DeviceDescriptor && FDODeviceExtension->DeviceDescriptor->idVendor == 0x0458 && FDODeviceExtension->DeviceDescriptor->idProduct == 0x705f)
ASSERT(FALSE);
}
//
// move to next interface
//
InterfaceIndex++;
}while(InterfaceIndex < DescriptorCount);
//
// sanity check
//
ASSERT(FDODeviceExtension->InterfaceListCount);
//
// done
//
return STATUS_SUCCESS;
}
2.然后根据接口描述符数据使用函数USBD_CreateConfigurationRequestEx来创建对应的URB.
3.将URB下传给总线驱动的PDO(USBCCGP_SyncUrbRequest),返回返择后的接口描述符。
4.解析存储后的接口描述符。
说明:
接口描述符数据必须必须比接口描述符多一个,且最后一个的成员变量都得设为NULL.
存储接口描述符和选择后的接口描述符使用对构体USBD_INTERFACE_LIST_ENTRY来存储
typedef struct _USBD_INTERFACE_LIST_ENTRY {
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
PUSBD_INTERFACE_INFORMATION Interface;
} USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY;
其中InterfaceDescriptor为对应的接口描述符,Interface为选择后即由下层总线驱动数据配置后的信息。
结构体定义如下:
typedef struct _USBD_INTERFACE_INFORMATION {
USHORT Length;
UCHAR InterfaceNumber;
UCHAR AlternateSetting;
UCHAR Class;
UCHAR SubClass;
UCHAR Protocol;
UCHAR Reserved;
USBD_INTERFACE_HANDLE InterfaceHandle;
ULONG NumberOfPipes;
USBD_PIPE_INFORMATION Pipes[1];
} USBD_INTERFACE_INFORMATION, *PUSBD_INTERFACE_INFORMATION;
可以看到,有端点数量,接口ID和端点的相关信息
typedef struct _USBD_PIPE_INFORMATION {
USHORT MaximumPacketSize;
UCHAR EndpointAddress;
UCHAR Interval;
USBD_PIPE_TYPE PipeType;
USBD_PIPE_HANDLE PipeHandle;
ULONG MaximumTransferSize;
ULONG PipeFlags;
} USBD_PIPE_INFORMATION, *PUSBD_PIPE_INFORMATION;
附:扫描接口描述符函数
NTSTATUS
NTAPI
USBCCGP_ScanConfigurationDescriptor(
IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
{
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
ULONG InterfaceIndex = 0;
ULONG DescriptorCount;
//
// sanity checks
//
ASSERT(ConfigurationDescriptor);
ASSERT(ConfigurationDescriptor->bNumInterfaces);
//
// count all interface descriptors
//
DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
if (DescriptorCount == 0)
{
DPRINT1("[USBCCGP] DescriptorCount is zero\n");
return STATUS_INVALID_PARAMETER;
}
//
// allocate array holding the interface descriptors
//
FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
if (!FDODeviceExtension->InterfaceList)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// reset interface list count
//
FDODeviceExtension->InterfaceListCount = 0;
do
{
//
// parse configuration descriptor
//
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
if (InterfaceDescriptor)
{
//
// store in interface list
//
ASSERT(FDODeviceExtension->InterfaceListCount < DescriptorCount);
FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
FDODeviceExtension->InterfaceListCount++;
}
else
{
DumpConfigurationDescriptor(ConfigurationDescriptor);
DumpFullConfigurationDescriptor(FDODeviceExtension, ConfigurationDescriptor);
//
// see issue
// CORE-6574 Test 3 (USB Web Cam)
//
if (FDODeviceExtension->DeviceDescriptor && FDODeviceExtension->DeviceDescriptor->idVendor == 0x0458 && FDODeviceExtension->DeviceDescriptor->idProduct == 0x705f)
ASSERT(FALSE);
}
//
// move to next interface
//
InterfaceIndex++;
}while(InterfaceIndex < DescriptorCount);
//
// sanity check
//
ASSERT(FDODeviceExtension->InterfaceListCount);
//
// done
//
return STATUS_SUCCESS;
}