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. |
若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… | |
---|---|---|
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. |
当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 |
这些回调函数的参数:
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 |
这些回调函数的参数:
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(¶ms); WdfRequestGetParameters(Request, ¶ms); // 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来获得请求的参数。