Windows 驱动开发 - 7

时间:2023-03-08 21:38:21

在《Windows 驱动开发 - 5》我们所说的读写操作在本篇实现。

在WDF中实现此功能主要为:EvtIoRead和EvtIoWrite。

首先,在EvtDeviceAdd设置以上两个回调事件。

ioQueueConfig.EvtIoRead = EvtIoRead;
ioQueueConfig.EvtIoWrite = EvtIoWrite;

然后。在EvtDevicePrepareHardware中获取WDFUSBPIPE并測试他。

pDeviceContext->BulkReadPipe = WdfUsbInterfaceGetConfiguredPipe(
pDeviceContext->UsbInterface,
BULK_IN_ENDPOINT_INDEX,
NULL);// pipeInfo WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pDeviceContext->BulkReadPipe); pDeviceContext->BulkWritePipe = WdfUsbInterfaceGetConfiguredPipe(
pDeviceContext->UsbInterface,
BULK_OUT_ENDPOINT_INDEX,
NULL);// pipeInfo

(1)获取WDFUSBPIPE

使用WdfUsbInterfaceGetConfiguredPipe方法。

WDFUSBPIPE WdfUsbInterfaceGetConfiguredPipe(
[in] WDFUSBINTERFACE UsbInterface,
[in] UCHAR PipeIndex,
[out, optional] PWDF_USB_PIPE_INFORMATION PipeInfo
);

(2) 測试WDFUSBPIPE

使用WdfUsbTargetPipeSetNoMaximumPacketSizeCheck方法.

VOID WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(
[in] WDFUSBPIPE Pipe
);

最后,实现以上两个回调事件和他们的完毕例程。

1. 获得传输缓存

读:WdfRequestRetrieveOutputMemory

NTSTATUS WdfRequestRetrieveOutputMemory(
[in] WDFREQUEST Request,
[out] WDFMEMORY *Memory
);

写:WdfRequestRetrieveInputMemory

NTSTATUS WdfRequestRetrieveInputMemory(
[in] WDFREQUEST Request,
[out] WDFMEMORY *Memory
);

2. 格式化并发送一个请求对象到USB驱动程序堆栈

读:WdfUsbTargetPipeFormatRequestForRead

NTSTATUS WdfUsbTargetPipeFormatRequestForRead(
[in] WDFUSBPIPE Pipe,
[in] WDFREQUEST Request,
[in, optional] WDFMEMORY ReadMemory,
[in, optional] PWDFMEMORY_OFFSET ReadOffset
);

写:WdfUsbTargetPipeFormatRequestForWrite

NTSTATUS WdfUsbTargetPipeFormatRequestForWrite(
[in] WDFUSBPIPE Pipe,
[in] WDFREQUEST Request,
[in, optional] WDFMEMORY WriteMemory,
[in, optional] PWDFMEMORY_OFFSET WriteOffset
);

3. 对请求实现一个完毕例程

(1)
设置完毕例程

使用WdfRequestSetCompletionRoutine方法。

VOID WdfRequestSetCompletionRoutine(
[in] WDFREQUEST Request,
[in, optional] PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine,
[in, optional] WDFCONTEXT CompletionContext
);

(2)完毕例程

1).检查请求状态

status = CompletionParams->IoStatus.Status;

2). 检查传输的字节数

读完:

bytesRead =  usbCompletionParams->Parameters.PipeRead.Length;

写完:

bytesWritten =  usbCompletionParams->Parameters.PipeWrite.Length;

3). 检查USBD状态

首先。赋值

usbCompletionParams = CompletionParams->Parameters.Usb.Completion;

最后,获取

usbCompletionParams->UsbdStatus;

注:

读:EvtIoRead

写:EvtIoWrite

读完:EvtRequestReadCompletionRoutine

写完:EvtRequestWriteCompletionRoutine

附:

step4.c

/*++

Step4: This steps shows:
1) How to register Read and Write events on the default queue.
2) Retrieve memory from read and write request, format the
requests and send it to USB target.
--*/ #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 BULK_OUT_ENDPOINT_INDEX 1
#define BULK_IN_ENDPOINT_INDEX 2
#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;
WDFUSBPIPE BulkReadPipe;
WDFUSBPIPE BulkWritePipe;
} DEVICE_CONTEXT, *PDEVICE_CONTEXT; WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext) NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;
NTSTATUS status; KdPrint(("DriverEntry of Step4\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;
} NTSTATUS
EvtDeviceAdd(
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;
ioQueueConfig.EvtIoRead = EvtIoRead;
ioQueueConfig.EvtIoWrite = EvtIoWrite; 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;
} NTSTATUS
EvtDevicePrepareHardware(
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; pDeviceContext->BulkReadPipe = WdfUsbInterfaceGetConfiguredPipe(
pDeviceContext->UsbInterface,
BULK_IN_ENDPOINT_INDEX,
NULL);// pipeInfo WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pDeviceContext->BulkReadPipe); pDeviceContext->BulkWritePipe = WdfUsbInterfaceGetConfiguredPipe(
pDeviceContext->UsbInterface,
BULK_OUT_ENDPOINT_INDEX,
NULL);// pipeInfo WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pDeviceContext->BulkWritePipe); return status;
} VOID
EvtIoDeviceControl(
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;
} VOID
EvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
WDFUSBPIPE pipe;
NTSTATUS status;
WDFMEMORY reqMemory;
PDEVICE_CONTEXT pDeviceContext;
BOOLEAN ret; UNREFERENCED_PARAMETER(Length); pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); pipe = pDeviceContext->BulkReadPipe; status = WdfRequestRetrieveOutputMemory(Request, &reqMemory);
if(!NT_SUCCESS(status)){
goto Exit;
} status = WdfUsbTargetPipeFormatRequestForRead(pipe,
Request,
reqMemory,
NULL // Offsets
);
if (!NT_SUCCESS(status)) {
goto Exit;
} WdfRequestSetCompletionRoutine(Request,
EvtRequestReadCompletionRoutine,
pipe);
ret = WdfRequestSend(Request,
WdfUsbTargetPipeGetIoTarget(pipe),
WDF_NO_SEND_OPTIONS); if (ret == FALSE) {
status = WdfRequestGetStatus(Request);
goto Exit;
} else {
return;
} Exit:
WdfRequestCompleteWithInformation(Request, status, 0); return;
} VOID
EvtRequestReadCompletionRoutine(
IN WDFREQUEST Request,
IN WDFIOTARGET Target,
PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
IN WDFCONTEXT Context
)
{
NTSTATUS status;
size_t bytesRead = 0;
PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; UNREFERENCED_PARAMETER(Target);
UNREFERENCED_PARAMETER(Context); status = CompletionParams->IoStatus.Status; usbCompletionParams = CompletionParams->Parameters.Usb.Completion; bytesRead = usbCompletionParams->Parameters.PipeRead.Length; if (NT_SUCCESS(status)){
KdPrint(("Number of bytes read: %I64d\n", (INT64)bytesRead));
} else {
KdPrint(("Read failed - request status 0x%x UsbdStatus 0x%x\n",
status, usbCompletionParams->UsbdStatus)); } WdfRequestCompleteWithInformation(Request, status, bytesRead); return;
} VOID
EvtIoWrite(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
NTSTATUS status;
WDFUSBPIPE pipe;
WDFMEMORY reqMemory;
PDEVICE_CONTEXT pDeviceContext;
BOOLEAN ret; UNREFERENCED_PARAMETER(Length); pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); pipe = pDeviceContext->BulkWritePipe; status = WdfRequestRetrieveInputMemory(Request, &reqMemory);
if(!NT_SUCCESS(status)){
goto Exit;
} status = WdfUsbTargetPipeFormatRequestForWrite(pipe,
Request,
reqMemory,
NULL); // Offset
if (!NT_SUCCESS(status)) {
goto Exit;
} WdfRequestSetCompletionRoutine(
Request,
EvtRequestWriteCompletionRoutine,
pipe);
ret = WdfRequestSend(Request,
WdfUsbTargetPipeGetIoTarget(pipe),
WDF_NO_SEND_OPTIONS);
if (ret == FALSE) {
status = WdfRequestGetStatus(Request);
goto Exit;
} else {
return;
} Exit:
WdfRequestCompleteWithInformation(Request, status, 0); return;
} VOID
EvtRequestWriteCompletionRoutine(
IN WDFREQUEST Request,
IN WDFIOTARGET Target,
PWDF_REQUEST_COMPLETION_PARAMS CompletionParams,
IN WDFCONTEXT Context
)
{
NTSTATUS status;
size_t bytesWritten = 0;
PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; UNREFERENCED_PARAMETER(Target);
UNREFERENCED_PARAMETER(Context); status = CompletionParams->IoStatus.Status; usbCompletionParams = CompletionParams->Parameters.Usb.Completion; bytesWritten = usbCompletionParams->Parameters.PipeWrite.Length; if (NT_SUCCESS(status)){
KdPrint(("Number of bytes written: %I64d\n", (INT64)bytesWritten));
} else {
KdPrint(("Write failed: request Status 0x%x UsbdStatus 0x%x\n",
status, usbCompletionParams->UsbdStatus));
} WdfRequestCompleteWithInformation(Request, status, bytesWritten); return;
}

參考文章:

1. 《Working with USB Pipes

2. 《How to send USB bulk transfer requests