Windows 驱动开发

摘要:
在《Windows驱动开发-5》我们所说的读写操作在本篇实现。在WDF中实现此功能主要为:EvtIoRead和EvtIoWrite。pDeviceContext-˃BulkReadPipe=WdfUsbInterfaceGetConfiguredPipe;//pipeInfoWdfUsbTargetPipeSetNoMaximumPacketSizeCheck;pDeviceContext-˃BulkWritePipe=WdfUsbInterfaceGetConfiguredPipe;//pipeInfo获取WDFUSBPIPE使用WdfUsbInterfaceGetConfiguredPipe方法。WDFUSBPIPEWdfUsbInterfaceGetConfiguredPipe;測试WDFUSBPIPE使用WdfUsbTargetPipeSetNoMaximumPacketSizeCheck方法.VOIDWdfUsbTargetPipeSetNoMaximumPacketSizeCheck;最后,实现以上两个回调事件和他们的完毕例程。

在《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
"));

    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
", 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
", 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
", 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!
", 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
", 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
", 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
", (INT64)bytesRead));  
    } else {
        KdPrint(("Read failed - request status 0x%x UsbdStatus 0x%x
",
                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
", (INT64)bytesWritten));        
    } else {
        KdPrint(("Write failed: request Status 0x%x UsbdStatus 0x%x
", 
                status, usbCompletionParams->UsbdStatus));
    }

    WdfRequestCompleteWithInformation(Request, status, bytesWritten);

    return;
}


參考文章:

1. 《Working with USB Pipes

2. 《How to send USB bulk transfer requests


免责声明:文章转载自《Windows 驱动开发》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Linux下pppoe客户端拔号--pppoe-setupiterable类型的遍历方式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

ftp命令

ftp命令是标准文件传输协议的用户界面。Ftp是在TCP/IP网络上的计算机之间传输文件的一种简单有效的方法。它允许用户传输ASCII文件和二进制文件。用户可以在目录中上下移动,列出目录内容,将文件从远程计算机复制到本地计算机,并将文件从本地计算机传输到远程系统。它用于确定用户可以对要传输的文件进行何种访问。用户显然需要知道进行ftp会话的计算机的名称或IP...

es6 解构赋值

functiondemo(){return{"name":"张三","age":21}}var{name,age}=demo();console.log;//结果:张三console.log;//结果:21三、定义函数参数functiondemo{console.log;console.log;console.log;}demo;四、函数参数的默认值传统的参...

Redis之有序集合(Zset)

序列号命令和描述1ZADDkeyscore1member1[score2member2]将一个或多个成员添加到有序集合。...

Ubuntu 下查看CPU 信息命令

看看带有“处理器”一词的行数,即逻辑CPU的数量。因此,您可以在cmd下输入以下命令:cat/proc/cpuinfo|greproprocessor|wc-l因此,C++程序自然会想到使用strstr函数来查找processor关键字的出现次数。...

Systemd简介与使用

Systemd在并行启动中采用了比Upstart更激进的方案。图2显示了systemd的并行启动模式。它允许所有配置的服务同时启动。事实上,大多数使用systemd的现代发行版都与此类似。系统通过配置这些单元来切换和管理服务。...

如何快速把ps序列图层建立帧动画?

工具ps1。将序列帧图片加载到ps新建-˃脚本-˃将文件加载到堆栈2中。创建序列帧动画窗口-˃时间线-˃时间线面板的右上菜单-˃从层3创建帧。移除多余的透明画布选择所有层-˃图像-˃剪辑-˃基于透明度4。将图层保存到图片文件-˃脚本-˃将图层保存为文件隐藏白色背景5。导出序列框架文件-˃自动-˃联系人表6存储为png...