chapter 8.6: I/O事件回调函数

接收带I/O请求时framework可以做的事:
    1.把request放入queue
    2.调用callback而不是放入queue
    3.代driver处理请求
    4.转发到默认I/O target
    5.标记请求为失败


为了I/O的文件对象
从应用程序角度,所有I/O都是通过文件句柄执行的。从驱动角度看,文件不重要,除非需要执行多客户端的会话相关动作(比如完成某个会话所有请求)。
当应用程序打开文件句柄时,I/O manager创建了一个文件对象,而WDF也创建了一个framework file object来表示file object。定义了3个文件相关请求:Create cleanup和close,driver可以opt in
UMDF的每个I/O 请求都必须有对应的有效file object
KMDF可以没有关联文件


自动转发Create cleanup和close
自动转发只对一些I/O请求有效,比如UMDF filter driver只关心写请求,就可以对其他的Create cleanup和close自动转发。
framework不对cleanup和close创建WDF request object,唯一让它们转发至默认I/O target的方法就是配置自动转发。
framework只有在WDF提供了 create callback时,才会创建WDF request object
framework是否分派/转发/完成Create cleanup和close请求由以下决定:
    1.device的automatic-forwarding flag配置
    2.driver是否是filter或function
    3.是否为该事件类型实现了回调函数
    4.对于create请求,驱动是否为它配置了queue
UMDF设置自动转发:====
KMDF设置自动转发:在创建驱动对象前在WDF_FILEOBJECT_CONFIG中设置AutoForwardCleanupClose。
    WdfDefault(function和filter驱动不同),WdfTrue,WdfFalse
----------/Unbalanced Create and Cleanup/Close Requests\-------------
若驱动实现了一个create callback,它必须处理所有的create请求:只能同时完成所有的请求,或者转发所有的请求到I/O target。而不能实现一部分create请求,转发其他的。
驱动必须和framework处理cleanup和close请求一样处理create请求(转发给I/O target或完成它们)
原因是UMDF的 AutoForwardCreateCleanupClose 和KMDF的AutoForwardCleanupClose 为设备对象应用了所有的这些请求,framework无法确定哪些请求由驱动完成,哪些请求又被转发到另一个驱动。低层的驱动必须接受和cleanup/close请求一致的创建请求。


create request的I/O事件回调函数
若设备同时能有一至多个用户或文件,则必须处理创建请求。此时,驱动要访问framework对请求创建的文件对象,通过这个可以区分用户,再file object context area中提供用户相关的存储区域。
处理创建请求:
    UMDF实现IQueueCallbackCreate接口,或IQueueCallbackDefaultIoHandler接口
    KMDF实现EvtDeviceFileCreate(不使用queue),或实现EvtIoDefault并配置一个接受创建请求的queue。
WDF对create有默认实现。


在UMDF中处理创建请求
    =========

在KMDF中处理创建请求
下表总结了KMDF根据驱动的配置对创建请求的处理方式

If the driver

The kernel-mode framework

Configures a queue for WdfRequestTypeCreate and registers EvtIoDefault for the queue

Queues create requests.

Registers EvtDeviceFileCreate by calling WdfDeviceInitSetFileObjectConfig from EvtDriverDeviceAdd

Invokes the EvtDeviceFileCreate callback and does not queue create requests.

Is a function driver and neither configures a queue to receive create requests nor registers the EvtDeviceFileCreate callback

Opens a file object and completes create requests with STATUS_SUCCESS.

Is a filter driver and neither configures a queue to receive create requests nor registers the EvtDeviceFileCreate callback

Forwards create requests to the default I/O target.

framework不会自动把[创建请求]加入到默认queue中!需要调用WdfDeviceConfigureRequestDispatching来显式允许默认queue接受create request,并为queue实现EvtIoDefault回调函数。
若filter driver处理create request,需要在完成任务后转发给默认I/O target。
若filter driver完成了create request,需要设置AutoForwardCleanupClose为WdfFalse,这样KMDF才能不转发相关的清楚和关闭请求。
若KMDF bus/function driver不为它注册callback或建立queue,则KMDF自动处理[创建请求],返回成功。这个默认操作有!!安全隐患。若设备不支持创建请求,需要注册EvtDeviceFileCreate回调函数,显式置请求为失败(和WDM不同,WDM默认创建请求为失败)。
例子:Toaster注册EvtDeviceFileCreate的代码
WDF_FILEOBJECT_CONFIG      fileConfig;
WDF_FILEOBJECT_CONFIG_INIT(&fileConfig,
                            ToasterEvtDeviceFileCreate,
                            ToasterEvtFileClose,
                            WDF_NO_EVENT_CALLBACK // no Cleanup
                            );
WdfDeviceInitSetFileObjectConfig(DeviceInit,
                                 &fileConfig,
                                 WDF_NO_OBJECT_ATTRIBUTES
                                 );
若EvtDeviceFileCreate把[创建请求]发给默认I/O target,则 I/O completion 回调函数不要改变请求的完成状态。


Cleanup和close的I/O事件回调函数
KMDF和UMDF都不对这两个请求做queue
处理Cleanup和close通知:
    1.UMDF在device callback object中实现IFileCallbackCleanup和IFileCallbackClose接口
    2.KMDF注册EvtFileCleanup和EvtFileClose回调函数
驱动可以任意选择是否支持他们。
下表总结了当Cleanup和close来临时WDF采取的动作

If a UMDF driver

Or if a KMDF driver

WDF …

Implements IFileCallbackCleanup or IFileCallbackClose

Registers EvtFileCleanup or EvtFileClose during EvtDriverDeviceAdd processing

Invokes a callback for a cleanup or close request.

Does not implement a callback for cleanup or close and is a function driver

-or-

Sets AutoForwardCreateCleanupClose to WdfFalse, does not implement the corresponding callback interface, and is a filter driver

Does not register a callback for cleanup or close and is a function driver

-or-

Sets AutoForwardCleanupClose in the FILE_OBJECT_CONFIG structure to WdfFalse, does not implement the corresponding callback function, and is a filter driver

Completes the request with S_OK. (UMDF only)

-or-

Completes the request with STATUS_SUCCESS. (KMDF only)

Does not implement a callback for cleanup or close and is a filter driver

-or-

Sets AutoForwardCreateCleanupClose to WdfTrue and is a function driver

Does not register a callback for cleanup or close and is a filter driver

-or-

Sets AutoForwardCleanupClose to WdfTrue and is a function driver

Forwards the cleanup or close request to the default I/O target.

当最后一个file object的剧本被关闭释放后,framework调用驱动的file cleanup callback(取消file的所有I/O request),所以文件就没有任何clients。
当cleanup callback返回后,且取消file的所有I/O request后,framework调用file close callback释放资源。
KMDF驱动: framework 在任意线程同步调用EvtFileClose 
?有误?“Listing 8-11 in the previous section shows how a KMDF driver registers the create and close callbacks.”


read,write,Device I/O control请求的I/O事件回调
framework 对这些请求的处理流程见chapter 8.4的最后一张图


Read和Write请求的callback
下表是callback函数

Type of request

UMDF queue callback interfaces

KMDF event callback functions

Read

IQueueCallbackRead or

IQueueCallbackDefaultIoHandler

EvtIoRead or EvtIoDefault

Write

IQueueCallbackWrite or

IQueueCallbackDefaultIoHandler

EvtIoWrite or EvtIoDefault

表8-12
这些回调函数的参数:
    1.分派请求的queue的handle
    2.请求自己的handle
    3.读或写的比特数
在回调函数中可以对请求调用方法来获得更多信息(如buffer),在驱动获得所要的信息后,它可以初始化I/O操作
UMDF例子
=======
KMDF例子:
Osrusbfx2 driver 为一个串行queue注册了EvtIoRead callback:
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential);
    ioQueueConfig.EvtIoRead = OsrFxEvtIoRead;
    ioQueueConfig.EvtIoStop = OsrFxEvtIoStop;
    status = WdfIoQueueCreate( device,
                               &ioQueueConfig,
                               WDF_NO_OBJECT_ATTRIBUTES,
                               &queue
                               );
EvtIoRead代码:
VOID OsrFxEvtIoRead(
    IN WDFQUEUE         Queue,
    IN WDFREQUEST       Request,
    IN size_t           Length
    )
{
    WDFUSBPIPE                  pipe;
    NTSTATUS                    status;
    WDFMEMORY                   reqMemory;
    PDEVICE_CONTEXT             pDeviceContext;
    UNREFERENCED_PARAMETER(Queue);
    // First validate input parameters.
    if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) {
        status = STATUS_INVALID_PARAMETER;
        goto Exit;
    }
    pDeviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue));
    pipe = pDeviceContext->BulkReadPipe;
    status = WdfRequestRetrieveOutputMemory(Request, &reqMemory);
    if(!NT_SUCCESS(status)){
        goto Exit;
    }
    // The format call validates that you are reading or
    // writing to the right pipe type, sets the transfer flags,
    // creates an URB and initializes the request.
    status = WdfUsbTargetPipeFormatRequestForRead(pipe,
                                                  Request,
                                                  reqMemory,
                                                  NULL // Offsets
                                                  );
    if (!NT_SUCCESS(status)) {
        goto Exit;
    }

    WdfRequestSetCompletionRoutine( Request,
                                    EvtRequestReadCompletionRoutine,
                                    pipe
                                   );
    // Send the request asynchronously.
    if (WdfRequestSend (Request,
                        WdfUsbTargetPipeGetIoTarget(pipe),
                        WDF_NO_SEND_OPTIONS)
                        == FALSE) {
        // Framework couldn't send the request for some reason.
        status = WdfRequestGetStatus(Request);
        goto Exit;
    }
Exit:
    if (!NT_SUCCESS(status)) {
        WdfRequestCompleteWithInformation(Request, status, 0);
    }
    return;
}
驱动首先验证长度,通过WdfRequestRetrieveOutputMemory获得buffer,为USB target pipe格式化request,设置I/O completion callback,把请求发送到target pipe。


IOCTL请求的callback
下表是callback函数

Type of request

UMDF callback interfaces

KMDF event callback function

Device I/O control

IQueueCallbackDeviceIoControl or IQueueCallbackDefaultIoHandler

EvtIoDeviceControl or EvtIoDefault

Internal device I/O control

None

EvtIoInternalDeviceControl or EvtIoDefault

表8-13
这些回调函数的参数:
    1.分派请求的queue的handle
    2.请求自己的handle
    3.I/O control code(ULONG)
    4.input buffer length
    5.output buffer length
UMDF例子
=====
KMDF例子:
Toaster sample's Toaster.c file.
VOID ToasterEvtIoDeviceControl(
    IN WDFQUEUE     Queue,
    IN WDFREQUEST   Request,
    IN size_t       OutputBufferLength,
    IN size_t       InputBufferLength,
    IN ULONG        IoControlCode
    )
{
    NTSTATUS             status= STATUS_SUCCESS;
    WDF_DEVICE_STATE     deviceState;
    WDFDEVICE            hDevice = WdfIoQueueGetDevice(Queue);
    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);
    PAGED_CODE();

    switch (IoControlCode) {
    case IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE:
        // Please remove this code when you adapt this sample for your hardware.
        WDF_DEVICE_STATE_INIT(&deviceState);
        deviceState.DontDisplayInUI = WdfTrue;
        WdfDeviceSetDeviceState(hDevice, &deviceState);
        break;
    default:
        status = STATUS_INVALID_DEVICE_REQUEST;
    }
    // Complete the Request.
    WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR) 0);
}
Toaster只处理一个IOCTL,用来禁止toaster在Device Manager中显示。若IoControlCode为IOCTL_TOASTER_DONT_DISPLAY_ IN_UI_DEVICE,驱动初始化WDF_DEVICE_STATE,并设置DontDisplayInUI为WdfTrue,调用WdfDeviceSetDeviceState来设置该值。


默认I/O callback
驱动可以为创建了queue但是没有提供其他回调的请求实现默认I/O callback,适用请求类型:read,write,IOCTL,internel device IOCTL。无法为create提供默认I/O callback
default I/O的参数:
    1.分派请求的queue的handle
    2.请求的handle
KMDF例子:EvtIoDefault,AMCC5933 sample
VOID AmccPciEvtIoDefault(
    IN WDFQUEUE       Queue,
    IN WDFREQUEST     Request
    )
{
    PAMCC_DEVICE_EXTENSION    devExt;
    REQUEST_CONTEXT         * transfer;
    NTSTATUS                  status;
    size_t                    length;
    WDF_DMA_DIRECTION         direction;
    WDFDMATRANSACTION         dmaTransaction;
    WDF_REQUEST_PARAMETERS    params;
    WDF_REQUEST_PARAMETERS_INIT(&params);
    WdfRequestGetParameters(Request, &params);
    // Get the device context area.
    devExt = AmccPciGetDevExt(WdfIoQueueGetDevice(Queue));

    // Validate and gather parameters.
    switch (params.Type) {
        case WdfRequestTypeRead:
            length    = params.Parameters.Read.Length;
            direction = WdfDmaDirectionReadFromDevice;
            break;
        case WdfRequestTypeWrite:
            length    = params.Parameters.Write.Length;
            direction = WdfDmaDirectionWriteToDevice;
            break;
        default:
            WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
            return;
    }
    // The length must be non-zero.
    if (length == 0) {
        WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
        return;
    }
    // Code continues to set up DMA operation.
    . . .
    return;
}
这个EvtIoDefault接受read write和IOCTL,通过WdfGetRequestParameters来获得请求的参数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值