USBCCGP 关联接口功能设备枚举
2021-09-15
295
0
从上节可知,所有的功能设备都存储在FDO_DEVICE_EXTENSION中的FunctionDescriptor中的,而FunctionDescriptorCount成员记录着子功能数量。
typedef struct _USBC_FUNCTION_DESCRIPTOR{
// The 0-based index of the function described
UCHAR FunctionNumber;
// The number of interfaces contained in this function
UCHAR NumberOfInterfaces;
// A callee allocated array of pointers into the config desc buffer passed as an input
PUSB_INTERFACE_DESCRIPTOR *InterfaceDescriptorList;
// Callee allocated PNP IDs for this PDO
UNICODE_STRING HardwareId;
UNICODE_STRING CompatibleId;
UNICODE_STRING FunctionDescription;
// Custom Flags
ULONG FunctionFlags;
PVOID Reserved;
} USBC_FUNCTION_DESCRIPTOR, *PUSBC_FUNCTION_DESCRIPTOR;
关联接口功能设备的枚举是通过USBCCGP_EnumWithAssociationDescriptor
实现的。
function.c
NTSTATUS
USBCCGP_EnumWithAssociationDescriptor(
IN PDEVICE_OBJECT DeviceObject)
{
ULONG DescriptorCount, Index;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
NTSTATUS Status = STATUS_SUCCESS;
//
// get device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(FDODeviceExtension->Common.IsFDO);
//
// count association descriptors
//
DescriptorCount = USBCCGP_CountAssociationDescriptors(FDODeviceExtension->ConfigurationDescriptor);
if (!DescriptorCount)
{
//
// no descriptors found
//
return STATUS_NOT_SUPPORTED;
}
//
// allocate function descriptor array
//
FDODeviceExtension->FunctionDescriptor = AllocateItem(NonPagedPool, sizeof(USBC_FUNCTION_DESCRIPTOR) * DescriptorCount);
if (!FDODeviceExtension->FunctionDescriptor)
{
//
// no memory
//
DPRINT1("USBCCGP_EnumWithAssociationDescriptor failed to allocate function descriptor count %x\n", DescriptorCount);
return STATUS_INSUFFICIENT_RESOURCES;
}
for (Index = 0; Index < DescriptorCount; Index++)
{
//
// init function descriptors
//
Status = USBCCGP_InitFunctionDescriptor(FDODeviceExtension, Index, &FDODeviceExtension->FunctionDescriptor[Index]);
if (!NT_SUCCESS(Status))
{
//
// failed
//
return Status;
}
}
//
// store function descriptor count
//
FDODeviceExtension->FunctionDescriptorCount = DescriptorCount;
//
// done
//
return Status;
}
1.首选获取关联描述符的数量
有几个关联描述符就应该有几个功能设备,这个是通过接口描述符类型来判断的。
ULONG
USBCCGP_CountAssociationDescriptors(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
{
PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
PUCHAR Offset, End;
ULONG Count = 0;
//
// init offsets
//
Offset = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->bLength;
End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
while (Offset < End)
{
//
// get association descriptor
//
Descriptor = (PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR)Offset;
if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
{
//
// found descriptor
//
Count++;
}
//
// move to next descriptor
//
Offset += Descriptor->bLength;
}
//
// done
//
return Count;
}
2.根据关联调备的描述符数量分配USBC_FUNCTION_DESCRIPTOR内存空间
3.使用函数USBCCGP_InitFunctionDescriptor找到各个对应的关联描述符,并分析相关信息,实现各个子功能设备USBC_FUNCTION_DESCRIPTOR结构体数据信息的填充。
NTSTATUS
USBCCGP_InitFunctionDescriptor(
IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
IN ULONG FunctionNumber,
OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
{
PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR Descriptor;
NTSTATUS Status;
LPWSTR DescriptionBuffer;
WCHAR Buffer[100];
ULONG Index;
// init function number
FunctionDescriptor->FunctionNumber = (UCHAR)FunctionNumber;
// get association descriptor
Descriptor = USBCCGP_GetAssociationDescriptorAtIndex(FDODeviceExtension->ConfigurationDescriptor, FunctionNumber);
ASSERT(Descriptor);
// store number interfaces
FunctionDescriptor->NumberOfInterfaces = Descriptor->bInterfaceCount;
// allocate array for interface count
FunctionDescriptor->InterfaceDescriptorList = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * Descriptor->bInterfaceCount);
if (!FunctionDescriptor->InterfaceDescriptorList)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
// init interface list
Status = USBCCGP_InitInterfaceListOfFunctionDescriptor(FDODeviceExtension->ConfigurationDescriptor, Descriptor, FunctionDescriptor);
if (!NT_SUCCESS(Status))
{
//
// failed
//
return Status;
}
//
// now init interface description
//
if (Descriptor->iFunction)
{
//
// get interface description
//
Status = USBCCGP_GetStringDescriptor(FDODeviceExtension->NextDeviceObject,
100 * sizeof(WCHAR),
Descriptor->iFunction,
0x0409, //FIXME
(PVOID*)&DescriptionBuffer);
if (!NT_SUCCESS(Status))
{
//
// no description
//
RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, L"");
}
else
{
//
// init description
//
RtlInitUnicodeString(&FunctionDescriptor->FunctionDescription, DescriptionBuffer);
}
DPRINT1("FunctionDescription %wZ\n", &FunctionDescriptor->FunctionDescription);
}
//
// now init hardware id
//
Index = swprintf(Buffer, L"USB\\VID_%04x&PID_%04x&Rev_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
FDODeviceExtension->DeviceDescriptor->idProduct,
FDODeviceExtension->DeviceDescriptor->bcdDevice,
Descriptor->bFirstInterface) + 1;
Index += swprintf(&Buffer[Index], L"USB\\VID_%04x&PID_%04x&MI_%02x", FDODeviceExtension->DeviceDescriptor->idVendor,
FDODeviceExtension->DeviceDescriptor->idProduct,
Descriptor->bFirstInterface) + 1;
// allocate result buffer
DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
if (!DescriptionBuffer)
{
//
// failed to allocate memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
// copy description
RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
FunctionDescriptor->HardwareId.Buffer = DescriptionBuffer;
FunctionDescriptor->HardwareId.Length = Index * sizeof(WCHAR);
FunctionDescriptor->HardwareId.MaximumLength = (Index + 1) * sizeof(WCHAR);
//
// now init the compatible id
//
Index = swprintf(Buffer, L"USB\\Class_%02x&SubClass_%02x&Prot_%02x", Descriptor->bFunctionClass, Descriptor->bFunctionSubClass, Descriptor->bFunctionProtocol) + 1;
Index += swprintf(&Buffer[Index], L"USB\\Class_%02x&SubClass_%02x", Descriptor->bFunctionClass, Descriptor->bFunctionSubClass) + 1;
Index += swprintf(&Buffer[Index], L"USB\\Class_%02x", Descriptor->bFunctionClass) + 1;
// allocate result buffer
DescriptionBuffer = AllocateItem(NonPagedPool, (Index + 1) * sizeof(WCHAR));
if (!DescriptionBuffer)
{
//
// failed to allocate memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
// copy description
RtlCopyMemory(DescriptionBuffer, Buffer, (Index + 1) * sizeof(WCHAR));
FunctionDescriptor->CompatibleId.Buffer = DescriptionBuffer;
FunctionDescriptor->CompatibleId.Length = Index * sizeof(WCHAR);
FunctionDescriptor->CompatibleId.MaximumLength = (Index + 1) * sizeof(WCHAR);
//
// done
//
return STATUS_SUCCESS;
}
3.1.在各个关联调备中可能有多个接口描述符,如UVC中就会有VC和VC,所以对于各个关联接口描述符中,需要初始化FUNCTION_DESCRIPTOR中的 PUSB_INTERFACE_DESCRIPTOR *InterfaceDescriptorList;
成员。并使用函数USBCCGP_InitInterfaceListOfFunctionDescriptor
来初始化。
NTSTATUS
USBCCGP_InitInterfaceListOfFunctionDescriptor(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR AssociationDescriptor,
OUT PUSBC_FUNCTION_DESCRIPTOR FunctionDescriptor)
{
PUSB_INTERFACE_DESCRIPTOR Descriptor;
PUCHAR Offset, End;
ULONG Count = 0;
//
// init offsets
//
Offset = (PUCHAR)AssociationDescriptor + AssociationDescriptor->bLength;
End = (PUCHAR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength;
while (Offset < End)
{
//
// get association descriptor
//
Descriptor = (PUSB_INTERFACE_DESCRIPTOR)Offset;
if (Descriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
{
//
// store interface descriptor
//
FunctionDescriptor->InterfaceDescriptorList[Count] = Descriptor;
Count++;
if (Count == AssociationDescriptor->bInterfaceCount)
{
//
// got all interfaces
//
return STATUS_SUCCESS;
}
}
if (Descriptor->bLength == sizeof(USB_INTERFACE_ASSOCIATION_DESCRIPTOR) && Descriptor->bDescriptorType == USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
{
//
// WTF? a association descriptor which overlaps the next association descriptor
//
DPRINT1("Invalid association descriptor\n");
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
//
// move to next descriptor
//
Offset += Descriptor->bLength;
}
//
// invalid association descriptor
//
DPRINT1("Invalid association descriptor\n");
return STATUS_UNSUCCESSFUL;
}
在上面的USBCCGP_GetAssociationDescriptorAtIndex函数中,获取的接口描述符并非是关联描述符的指针,而是其下一个接口描述符的指针。
3.2最后,如果功能调备有设置字符描述符,通过函数USBCCGP_GetStringDescriptor获取它。
NTSTATUS
NTAPI
USBCCGP_GetStringDescriptor(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG DescriptorLength,
IN UCHAR DescriptorIndex,
IN LANGID LanguageId,
OUT PVOID *OutDescriptor)
{
NTSTATUS Status;
PUSB_STRING_DESCRIPTOR StringDescriptor;
ULONG Size;
PVOID Buffer;
// retrieve descriptor
Status = USBCCGP_GetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor);
if (!NT_SUCCESS(Status))
{
// failed
return Status;
}
// get descriptor structure
StringDescriptor = (PUSB_STRING_DESCRIPTOR)*OutDescriptor;
// sanity check
ASSERT(StringDescriptor->bLength < DescriptorLength - 2);
if (StringDescriptor->bLength == 2)
{
// invalid descriptor
FreeItem(StringDescriptor);
return STATUS_DEVICE_DATA_ERROR;
}
// calculate size
Size = StringDescriptor->bLength + sizeof(WCHAR);
// allocate buffer
Buffer = AllocateItem(NonPagedPool, Size);
if (!Buffer)
{
// no memory
FreeItem(StringDescriptor);
return STATUS_INSUFFICIENT_RESOURCES;
}
// copy result
RtlCopyMemory(Buffer, StringDescriptor->bString, Size - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
// free buffer
FreeItem(StringDescriptor);
// store result
*OutDescriptor = (PVOID)Buffer;
return STATUS_SUCCESS;
}
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936