USBCCGP 总线过滤驱动接口

总线驱动或过滤驱动的接口其实就是一个USBC_DEVICE_CONFIGURATION_INTERFACE_V1的结构体,其用于创建PDO.

#define USBC_DEVICE_CONFIGURATION_INTERFACE_VERSION_1         0x0001

typedef struct _USBC_DEVICE_CONFIGURATION_INTERFACE_V1 {
    USHORT Size;
    USHORT Version;
    PVOID Context;
    PINTERFACE_REFERENCE InterfaceReference;
    PINTERFACE_DEREFERENCE InterfaceDereference;

    USBC_START_DEVICE_CALLBACK StartDeviceCallback;
    USBC_PDO_ENABLE_CALLBACK   PdoEnableCallback;

    PVOID Reserved[7];
} USBC_DEVICE_CONFIGURATION_INTERFACE_V1, *PUSBC_DEVICE_CONFIGURATION_INTERFACE_V1;

这块功能一般是不用的,除非我们的所定制。

这个接口是通过专门的IRP实现的,函数代码如下:

NTSTATUS
USBCCGP_QueryInterface(
    IN PDEVICE_OBJECT DeviceObject,
    OUT PUSBC_DEVICE_CONFIGURATION_INTERFACE_V1 BusInterface)
{
    KEVENT Event;
    NTSTATUS Status;
    PIRP Irp;
    IO_STATUS_BLOCK IoStatus;
    PIO_STACK_LOCATION Stack;

    /* Sanity checks */
    ASSERT(DeviceObject);

    /* Initialize event */
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    /* Init interface */
    RtlZeroMemory(BusInterface, sizeof(USBC_DEVICE_CONFIGURATION_INTERFACE_V1));
    BusInterface->Version = USBC_DEVICE_CONFIGURATION_INTERFACE_VERSION_1;
    BusInterface->Size = sizeof(USBC_DEVICE_CONFIGURATION_INTERFACE_V1);

    /* Create irp */
    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
                                       DeviceObject,
                                       NULL,
                                       0,
                                       NULL,
                                       &Event,
                                       &IoStatus);

    //
    // was irp built
    //
    if (Irp == NULL)
    {
        //
        // no memory
        //
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // initialize request
    //
    Stack = IoGetNextIrpStackLocation(Irp);
    Stack->MajorFunction = IRP_MJ_PNP;
    Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
    Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
    Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBC_CONFIGURATION_GUID;
    Stack->Parameters.QueryInterface.Version = 2;
    Stack->Parameters.QueryInterface.Interface = (PINTERFACE)&BusInterface;
    Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

    //
    // call driver
    //
    Status = IoCallDriver(DeviceObject, Irp);

    //
    // did operation complete
    //
    if (Status == STATUS_PENDING)
    {
        //
        // wait for completion
        //
        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);

        //
        // collect status
        //
        Status = IoStatus.Status;
    }

    return Status;
}

可以看到,和以前的一样,就是设置完成函数,调用然后等待。

使用接口枚举子设备

在后面我们即将看到,子设备的枚举是通过USBCCGP_EnumerateFunctions来实现的,其第一个调用的函数就是通过USBCCGP_CustomEnumWithInterface来枚举子设备的。

NTSTATUS
USBCCGP_CustomEnumWithInterface(
    IN PDEVICE_OBJECT DeviceObject)
{
    PFDO_DEVICE_EXTENSION FDODeviceExtension;
    ULONG FunctionDescriptorBufferLength = 0;
    NTSTATUS Status;
    PUSBC_FUNCTION_DESCRIPTOR  FunctionDescriptorBuffer = NULL;

    //
    // get device extension
    //
    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    ASSERT(FDODeviceExtension->Common.IsFDO);

    if (FDODeviceExtension->BusInterface.StartDeviceCallback == NULL)
    {
        //
        // not supported
        //
        return STATUS_NOT_SUPPORTED;
    }

    //
    // invoke callback
    //
    Status = FDODeviceExtension->BusInterface.StartDeviceCallback(FDODeviceExtension->DeviceDescriptor,
                                                                  FDODeviceExtension->ConfigurationDescriptor,
                                                                  &FunctionDescriptorBuffer,
                                                                  &FunctionDescriptorBufferLength,
                                                                  DeviceObject,
                                                                  FDODeviceExtension->PhysicalDeviceObject);

    DPRINT("USBCCGP_CustomEnumWithInterface Status %lx\n", Status);
    if (!NT_SUCCESS(Status))
    {
        //
        // failed
        //
        return Status;
    }

    DPRINT("FunctionDescriptorBufferLength %lu\n", FunctionDescriptorBufferLength);
    DPRINT("FunctionDescriptorBuffer %p\n", FunctionDescriptorBuffer);

    //
    // assume length % function buffer size
    //
    ASSERT(FunctionDescriptorBufferLength);
    ASSERT(FunctionDescriptorBufferLength % sizeof(USBC_FUNCTION_DESCRIPTOR) == 0);

    //
    // store result
    //
    FDODeviceExtension->FunctionDescriptor = FunctionDescriptorBuffer;
    FDODeviceExtension->FunctionDescriptorCount = FunctionDescriptorBufferLength / sizeof(USBC_FUNCTION_DESCRIPTOR);

    //
    // success
    //
    return STATUS_SUCCESS;
}

可以看到,这个子设备的枚举其实就是调用下层驱动来实现的。

说明一下:

枚举设备从REACTOS代码来看,当前版本(V0.4.13)这块的代码是一个未完成的工程。
在FDO_DEVCIE_EXTENSION成员变量FunctionDescriptor中保存着所有枚举的子设备,不过可以明显地看到,接口设备、关联描述符和后面的音频描述符都是直接修改,而非累加设备的。

每个子设备的信息如下:

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;
  • USB基础
  • USB摄像头UVC
  • USB人机交互HID
  • USB音频UAC
  • Windows基础
  • 磁盘与文件系统
  • Windows编程
  • Windows驱动
  • 开发模块
  • Windows运维
  • Linux相关
  • C语言学习
  • 高级语言
  • 前端开发
  • 服务器开发
  • 数据库
  • 字节流笔记
  • 字节流
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    Powered by bytekits.com,汇天下文字,成非凡梦想!!!