上篇《Windows 驱动开发 - 5》我们设置了回调事件EvtIoDeviceControl,我们在此篇来实现他。
我们知道在进行读写之前我们要进行一定约定,比如同步。
在WDF中控制同步约定的方法为:WdfUsbTargetDeviceSendControlTransferSynchronously
NTSTATUS WdfUsbTargetDeviceSendControlTransferSynchronously( [in] WDFUSBDEVICE UsbDevice, [in, optional] WDFREQUEST Request, [in, optional] PWDF_REQUEST_SEND_OPTIONS RequestOptions, [in] PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, [in, optional] PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, [out, optional] PULONG BytesTransferred);(1) 选项请求
对WDF_REQUEST_SEND_OPTIONS结构的设置。
typedef struct _WDF_REQUEST_SEND_OPTIONS { ULONG Size; ULONG Flags; LONGLONG Timeout;} WDF_REQUEST_SEND_OPTIONS, *PWDF_REQUEST_SEND_OPTIONS;1). 初始化
使用WDF_REQUEST_SEND_OPTIONS_INIT方法进行初始化.
VOID WDF_REQUEST_SEND_OPTIONS_INIT( _Out_ PWDF_REQUEST_SEND_OPTIONS Options, _In_ ULONG Flags);
2). 设置超时
使用WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT方法进行超时设置。
VOID WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT( _Inout_ PWDF_REQUEST_SEND_OPTIONS Options, _In_ LONGLONG Timeout);
(2) 包设置
使用WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR方法进行包设置。
VOID WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR( _Out_ PWDF_USB_CONTROL_SETUP_PACKET Packet, _In_ WDF_USB_BMREQUEST_DIRECTION Direction, _In_ WDF_USB_BMREQUEST_RECIPIENT Recipient, _In_ BYTE Request, _In_ USHORT Value, _In_ USHORT Index);
(3) 内存描述
1). 内存请求
使用WdfRequestRetrieveInputMemory方法进行请求。
NTSTATUS WdfRequestRetrieveInputMemory( [in] WDFREQUEST Request, [out] WDFMEMORY *Memory);
2). 初始化内存句柄
使用WDF_MEMORY_DESCRIPTOR_INIT_HANDLE方法进行内存句柄的初始化。
VOID WDF_MEMORY_DESCRIPTOR_INIT_HANDLE( _Out_ PWDF_MEMORY_DESCRIPTOR Descriptor, _In_ WDFMEMORY Memory, _In_opt_ PWDFMEMORY_OFFSET Offsets);
代码:
step3.c
/*++Step3: This steps shows: 1) How to create a default parallel queue to receive a IOCTL requests to set bar graph display. 2) How to retreive memory handle from the requests and use that to send a vendor command to the USB device.--*/#include "ntddk.h"#include "wdf.h"#include "prototypes.h"#pragma warning(disable:4200) // suppress nameless struct/union warning#pragma warning(disable:4201) // suppress nameless struct/union warning#pragma warning(disable:4214) // suppress bit field types other than int warning#include "usbdi.h"#pragma warning(default:4200)#pragma warning(default:4201)#pragma warning(default:4214)#include "wdfusb.h"#include "initguid.h"DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, // Generated using guidgen.exe 0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84);// {573E8C73-0CB4-4471-A1BF-FAB26C31D384}#define IOCTL_INDEX 0x800#define FILE_DEVICE_OSRUSBFX2 0x65500#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\ IOCTL_INDEX + 5, \ METHOD_BUFFERED, \ FILE_WRITE_ACCESS)typedef struct _DEVICE_CONTEXT { WDFUSBDEVICE UsbDevice; WDFUSBINTERFACE UsbInterface;} DEVICE_CONTEXT, *PDEVICE_CONTEXT;WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext)NTSTATUSDriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ){ WDF_DRIVER_CONFIG config; NTSTATUS status; KdPrint(("DriverEntry of Step3\n")); WDF_DRIVER_CONFIG_INIT(&config, EvtDeviceAdd); status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE ); if (!NT_SUCCESS(status)) { KdPrint(("WdfDriverCreate failed 0x%x\n", status)); } return status;}NTSTATUSEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ){ WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; WDFDEVICE device; PDEVICE_CONTEXT pDevContext; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_IO_QUEUE_CONFIG ioQueueConfig; UNREFERENCED_PARAMETER(Driver); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { KdPrint(("WdfDeviceCreate failed 0x%x\n", status)); return status; } pDevContext = GetDeviceContext(device); status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, NULL);// Reference String if (!NT_SUCCESS(status)) { KdPrint(("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); return status; } WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel); ioQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl; status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoQueueCreate failed %!STATUS!\n", status)); return status; } return status;}NTSTATUSEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ){ NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); pDeviceContext = GetDeviceContext(Device); // // Create the USB device if it is not already created. // if (pDeviceContext->UsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->UsbDevice); if (!NT_SUCCESS(status)) { KdPrint(("WdfUsbTargetDeviceCreate failed 0x%x\n", status)); return status; } } WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if(!NT_SUCCESS(status)) { KdPrint(("WdfUsbTargetDeviceSelectConfig failed 0x%x\n", status)); return status; } pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; return status;}VOIDEvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ){ WDFDEVICE device; PDEVICE_CONTEXT pDevContext; size_t bytesTransferred = 0; NTSTATUS status; WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; WDF_MEMORY_DESCRIPTOR memDesc; WDFMEMORY memory; WDF_REQUEST_SEND_OPTIONS sendOptions; UNREFERENCED_PARAMETER(InputBufferLength); UNREFERENCED_PARAMETER(OutputBufferLength); device = WdfIoQueueGetDevice(Queue); pDevContext = GetDeviceContext(device); switch(IoControlCode) { case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: if(InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_OVERFLOW; bytesTransferred = sizeof(UCHAR); break; } status = WdfRequestRetrieveInputMemory(Request, &memory); if (!NT_SUCCESS(status)) { KdPrint(("WdfRequestRetrieveMemory failed 0x%x", status)); break; } WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, BmRequestHostToDevice, BmRequestToDevice, USBFX2LK_SET_BARGRAPH_DISPLAY, // Request 0, // Value 0); // Index WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&memDesc, memory, NULL); // // Send the I/O with a timeout to avoid hanging the calling // thread indefinitely. // WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(100)); status = WdfUsbTargetDeviceSendControlTransferSynchronously( pDevContext->UsbDevice, NULL, // Optional WDFREQUEST &sendOptions, // PWDF_REQUEST_SEND_OPTIONS &controlSetupPacket, &memDesc, (PULONG)&bytesTransferred); if (!NT_SUCCESS(status)) { KdPrint(("SendControlTransfer failed 0x%x", status)); break; } break; default: status = STATUS_INVALID_DEVICE_REQUEST; break; } WdfRequestCompleteWithInformation(Request, status, bytesTransferred); return;}