USB驱动开发——基于windows的WDM模型
译自 Programming the Microsoft Windows Driver Model / Walter On
和其他设备驱动不同,USB设备驱动不直接与底层硬件进行通信,而是先建立一个称为USB请求块(USB request blocks,URB)的数据结构,把它发送给父级驱动,父级驱动根据URB中的信息对底层硬件进行相应操作,这里父级驱动通常就是指USB总线驱动。发送URB可以使用主功能码为IRP_MJ_INTERNAL_DEVICE_CONTROL的IRP来实现,也可以直接调用父级驱动提供的接口调用函数来实现。
1. 初始化请求
URB时一种预先定义的数据结构,包含许多域(field)。为了建立一个URB,首先要开辟一个存储空间来存储这个URB,然后运行初始化程序向这个空间来填充一些数据,即设置URB的各个域,例如,若令设备能够对一个IRP_MN_START_DEVICE请求做出相应,那么首先需要做的一个工作就是读取设备描述符,可能需要使用类似下面的一段代码:
USB_DEVICE_DESCRIPTOR dd;
URB urb;
UsbBuildGetDescriptorRequest(&urb,
sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, &dd, NULL,
sizeof(dd), NULL);
这里声明了一个名为urb的URB类型的局部变量,用它来存储要构建的URB。URB这种数据结构是在USBDI.H中进行定义的,USBDI.H可以在DDK开发软件安装目录下找到。URB是一种共用体结构,里面又定义了一些子结构体,每个结构体用于存放特定的USB请求。URB具体定义如下:
typedef struct _URB {
union {
struct _URB_HEADER UrbHeader;
struct _URB_SELECT_INTERFACE UrbSelectInterface;
struct _URB_SELECT_CONFIGURATION UrbSelectConfiguration;
struct _URB_PIPE_REQUEST UrbPipeRequest;
struct _URB_FRAME_LENGTH_CONTROL UrbFrameLengthControl;
struct _URB_GET_FRAME_LENGTH UrbGetFrameLength;
struct _URB_SET_FRAME_LENGTH UrbSetFrameLength;
struct _URB_GET_CURRENT_FRAME_NUMBER UrbGetCurrentFrameNumber;
struct _URB_CONTROL_TRANSFER UrbControlTransfer;
struct _URB_BULK_OR_INTERRUPT_TRANSFER UrbBulkOrInterruptTransfer;
struct _URB_ISOCH_TRANSFER UrbIsochronousTransfer;
// for standard control transfers on the default pipe
struct _URB_CONTROL_DESCRIPTOR_REQUEST UrbControlDescriptorRequest;
struct _URB_CONTROL_GET_STATUS_REQUEST UrbControlGetStatusRequest;
struct _URB_CONTROL_FEATURE_REQUEST UrbControlFeatureRequest;
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST UrbControlVendorClassRequest;
struct _URB_CONTROL_GET_INTERFACE_REQUEST UrbControlGetInterfaceRequest;
struct _URB_CONTROL_GET_CONFIGURATION_REQUEST UrbControlGetConfigurationRequest;
};
} URB, *PURB;
这里类似于 _URB_**** 的代码也是在USBDI.H预先定义的某种结构体类型,例如: _URB_CONTROL_GET_STATUS_REQUEST在USBDI.H中定义如下:
struct _URB_CONTROL_DESCRIPTOR_REQUEST {
#ifdef OSR21_COMPAT
struct _URB_HEADER;
#else
struct _URB_HEADER Hdr; // function co
#endif
PVOID Reserved;
ULONG Reserved0;
ULONG TransferBufferLength;
PVOID TransferBuffer;
PMDL TransferBufferMDL; // *optional*
struct _URB *UrbLink; // *optional* link to next urb request
// if this is a chain of commands
struct _URB_HCD_AREA hca; // fields for HCD use
USHORT Reserved1;
UCHAR Index;
UCHAR DescriptorType;
USHORT LanguageId;
USHORT Reserved2;
};
初始化URB可以通过类似于UsbBuildGetDescriptorRequest这样的函数来完成,以下给出一个表来说明:
这些函数是在另一个头文件USBDLIB.H中定义的,在DDK安装目录下查找即可,对于表中的函数都可以在DDK的说明文档里找到,利用这些函数就可以实现对URB的初始化。这里以UsbBuildGetDescriptorRequest为例,说明一个函数具体功能,有些参数我也不能完全讲清其含义,把英文直接贴在上面了。
VOID UsbBuildGetDescriptorRequest( IN OUT PURB Urb, // 指向一个要初始化的URB首地址 IN USHORT Length, // 确定URB的长度 IN UCHAR DescriptorType, // 确定描述符类型 IN UCHAR Index, // Specifies the device-defined index of the descriptor that is to be retrieved IN USHORT LanguageId, // Specifies the language ID of the descriptor to be retrieved when USB_STRING_DESCRIPTOR_TYPE is set in DescriptorType. This parameter must be zero for any other value in DescriptorType. IN PVOID TransferBuffer OPTIONAL, // 读回的描述符后所存放的地址 IN PMDL TransferBufferMDL OPTIONAL, // Pointer to a resident buffer to receive the descriptor data or is NULL if an MDL is supplied in TransferBufferMDL. IN ULONG TransferBufferLength, // Specifies the length of the buffer specified in TransferBuffer or described in TransferBufferMDL. IN PURB Link OPTIONAL // 必需为NULL );