How to Port WDM Driver to KMDF Agenda

  • Slides: 89
Download presentation
How to Port WDM Driver to KMDF

How to Port WDM Driver to KMDF

Agenda Introduction to WDF Why should I convert to KMDF: Case Study Basic object

Agenda Introduction to WDF Why should I convert to KMDF: Case Study Basic object model Driver. Entry Pn. P/Power callbacks Self-Managed I/O callbacks How to configure wait-wake & idle power management Interrupt handling Callbacks specific to FDO and PDO Order of callbacks with respect to Pn. P/Power actions

Agenda (con’t) Different types of queues How queue states are managed by WDF Request

Agenda (con’t) Different types of queues How queue states are managed by WDF Request Cancellation Handling Create, Cleanup & Close requests Handling I/O requests – Read/Write/Ioctl Timers/DPC/Work items Locks: Wait. Lock, Spinlock Automatic I/O synchronization Sending request to another driver Escaping to WDM

What is WDF? Windows Driver Foundation consists of User Mode Driver Framework (UMDF )

What is WDF? Windows Driver Foundation consists of User Mode Driver Framework (UMDF ) Kernel Mode Driver Framework (KMDF) Tools: SDV, Driver PREfast, DIG, etc. KMDF is built on top of WDM Drivers written using KMDF are compatible from Windows 2000 forward Drivers are written using objects

Why Convert to WDF? List of things you worry about in WDM Tons of

Why Convert to WDF? List of things you worry about in WDM Tons of rules on handling Pn. P and power IRPs When to use remove locks IRP queuing and cancellation When to map and unmap HW resources When to enable/disable device interfaces When to register/deregister with WMI When to connect & disconnect interrupts Timer DPC and device remove/unload synchronization

Why Convert to WDF? (con’t) Converting S IRPs to D IRPs Supporting wait-wake Supporting

Why Convert to WDF? (con’t) Converting S IRPs to D IRPs Supporting wait-wake Supporting selective suspend (S 0 Sleep) Fast resume Asynchronous start Child device enumeration Complex rules on deleting a PDO Handling Pn. P/power IRPs in a filter driver Error handling Backward compatibility

Case Study: PCIDRV Sample Stats Line Count LOC devoted to Pn. P/PM Locks State

Case Study: PCIDRV Sample Stats Line Count LOC devoted to Pn. P/PM Locks State variables devoted to Pn. P/PM WDF 13, 147 7, 991 8 30 Comments 7, 271 Explicit registration of granular event callbacks adds to the line count 1, 795 Almost 6000 lines of code are eliminated 3 This is the most important statistic. This explains the complexity. 0 There are fewer paths in the driver and thus less testing and complexity. This sample is written for the Intel E 100 B NIC Card It’s a WDM version of network driver with NDIS interfaces separated out in an upper filter driver (ndisedge) Both samples are in the DDK and are functionally equivalent

Case Study: Serial Sample Stats Line Count LOC devoted to Pn. P/PM Locks State

Case Study: Serial Sample Stats Line Count LOC devoted to Pn. P/PM Locks State variables devoted to Pn. P/PM WDM 24, 000 5, 000 10 53 WDF Comments 17, 000 Explicit registration of granular event callbacks adds to the line count 2, 500 0 This is the most important statistic. This explains the complexity. 0 There are fewer paths in the driver and thus less testing and complexity. WDF sample does not support multi-port serial (WDM sample supports it) WDM statistics exclude multi-port support serial code

Case Study: OSRUSBFX 2 Sample Stats Line Count LOC devoted to Pn. P/PM Locks

Case Study: OSRUSBFX 2 Sample Stats Line Count LOC devoted to Pn. P/PM Locks State variables devoted to Pn. P/PM WDF 16, 350 6, 700 9 21 Comments 2, 300 Explicit registration of granular event callbacks adds to the line count 742 includes code to initialize the USB 0 This is the most important statistic. This explains the complexity 0 There are fewer paths in the driver and thus less testing and complexity The WDM version of OSRUSBFx 2 sample (available on osronline. com) and the WDF version provided in the DDK are functionally equivalent

Object Model Objects are the basis of WDF Everything in framework is represented by

Object Model Objects are the basis of WDF Everything in framework is represented by objects (Driver, Device, Request, etc. ) Objects have properties, methods, and events WDFOBJECT Methods Events Properties WDF functions that operate on object Calls made by WDF into the driver to notify something Methods that get or set a single value Have one or more driver owned context memory areas Lifetime of the object is controlled by reference counts Organized hierarchically for controlling object life time Not an inheritance based hierarchy Driver references objects as handles, not pointers

Creating an Object (Abc) Header File: WDF_OBJECT_ATTRIBUTES Struct _ABC_CONTEXT { … } ABC_CONTEXT *PABC_CONTEXT

Creating an Object (Abc) Header File: WDF_OBJECT_ATTRIBUTES Struct _ABC_CONTEXT { … } ABC_CONTEXT *PABC_CONTEXT Size Evt. Cleanup. Callback Evt. Destroy. Callback Execution. Level WDF_DECLARE_CONTEXT_TYPE_WITH_NAME( ABC_CONTEXT, Get. Abc. Context ) Source File: WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE( &Attributes, ABC_CONTEXT ); Attributes. Evt. Cleanup. Callback = Abc. Evt. Cleanup; Attributes. Evt. Destroy. Callback = Abc. Evt. Destroy; WDF_ABC_CONFIG_INIT( &Config ); Wdf. Abc. Create( &Attributes, &Config, &Handle ) Synchronization. Scope Parent. Object Context. Size. Override Context. Type. Info WDF_ABC_CONFIG Size Evt. Callback Period … Context = Get. Abc. Context( Handle ); Inherit. Paren t. Passive Dispatch Inherit. Pare nt. Device Object None

Object Relationship WDFCOLLECTION WDFLOOKASIDE WDFKEY WDFWAITLOCK WDFSPINLOCK WDFSTRING WDFREQUEST – Driver created Predefined WDFDRIVER

Object Relationship WDFCOLLECTION WDFLOOKASIDE WDFKEY WDFWAITLOCK WDFSPINLOCK WDFSTRING WDFREQUEST – Driver created Predefined WDFDRIVER Default, but can be parented to any object WDFDEVICE WDFQUEUE WDFUSBDEVICE WDFDPC WDFTIMER WDFWORKITEM WDFUSBPIPE WDFINTERRUPT WDFIOTARGET WDFCHILDLIST WDFFILEOBJECT WDFREQUEST – queue delivered WDFDMAENABLER WDFTRANSACTION WDFCOMMONBUFFER WDFWMIINSTANCE WDFWMIPROVIDER

Deleting an Object Wdf. Object. Delete() - single delete function to delete all types

Deleting an Object Wdf. Object. Delete() - single delete function to delete all types of objects Child objects will be deleted when their parent is deleted Some objects cannot be deleted by the driver because the lifetime is controlled by WDFDRIVER WDFDEVICE for FDO and PDO WDFFILEOBJECT WDFREQUEST Etc.

Mapping – WDF Objects to WDM WDFDRIVER WDFDEVICE WDFQUEUE WDFREQUEST WDFINTERRUPT WDFDPC WDFWORKITEM WDFDMAENABLER

Mapping – WDF Objects to WDM WDFDRIVER WDFDEVICE WDFQUEUE WDFREQUEST WDFINTERRUPT WDFDPC WDFWORKITEM WDFDMAENABLER WDFIOTARGET WDFWAITLOCK WDFSPINLOCK WDFMEMORY WDFKEY Driver object Device object Cancel-safe queue/Dispatching /Serialization/Autolocking/Synch with Pn. P IRP Interrupt DPC Work item DMA adapter object Sending I/O to another driver - Io. Call. Driver Event dispatcher object – passive level lock Spinlock Kernel pool - refcounted Registry access

Naming Pattern Methods: Object Status = Wdf. Device. Create(); Properties: Operation Cannot fail Wdf.

Naming Pattern Methods: Object Status = Wdf. Device. Create(); Properties: Operation Cannot fail Wdf. Interrupt. Get. Device(); Wdf. Interrupt. Set. Policy(); Can fail: Status = Wdf. Registry. Assign. Value(); Status = Wdf. Registry. Query. Value(); Status = Wdf. Request. Retrieve. Input. Buffer(); Callbacks: PFN_WDF_INTERRUPT_ENABLE Evt. Interrupt. Enable Init Macros: WDF_XXX_CONFIG_INIT WDF_XXX_EVENT_CALLBACKS_INIT

Driver. Entry – WDM Called when the driver is first loaded in memory Sets

Driver. Entry – WDM Called when the driver is first loaded in memory Sets Dispatch routines and returns NTSTATUS Driver. Entry( IN PDRIVER_OBJECT Driver. Object IN PUNICODE_STRING Registry. Path ) { Driver. Object->Driver. Extension->Add. Device = Add. Device; Driver. Object->Major. Function[IRP_MJ_PNP] = Dispatch. Pnp; Driver. Object->Major. Function[IRP_MJ_POWER] = Dispatch. Power; Driver. Object->Major. Function[IRP_MJ_SYSTEM_CONTROL] = Dispatch. Sys. Control; …. return STATUS_SUCCESS; }

Driver. Entry – WDF Driver. Entry is called when the driver is first loaded

Driver. Entry – WDF Driver. Entry is called when the driver is first loaded in memory Fx. Driver. Entry initializes the framework and calls Driver. Entryv NTSTATUS Driver. Entry( IN PDRIVER_OBJECT Driver. Object IN PUNICODE_STRING Registry. Path ) { WDF_DRIVER_CONFIG_INIT( &config Toaster. Evt. Device. Add ); status = Wdf. Driver. Create( Driver. Object Registry. Path WDF_NO_OBJECT_ATTRIBUTES &config WDF_NO_HANDLE ); return STATUS_SUCCESS; } WDF_DRIVER_CONFIG Size Evt. Driver. Device. Add Evt. Driver. Unload Driver. Init. Flags Wdf. Driver. Init. Non. Pnp. Driver Wdf. Driver. Init. No. Dispatch. Override

Pn. P/Power Stage WDFREQUEST Parallel Queue I/O Package Serial Queue Read/Write/Ioctls/ Create/Close/Cleanup Manual Queue

Pn. P/Power Stage WDFREQUEST Parallel Queue I/O Package Serial Queue Read/Write/Ioctls/ Create/Close/Cleanup Manual Queue Pnp/Power Events I R P Driver Next Driver Pnp/Power Events IRP Dispatcher Pnp/Power Package Io. Target Pnp/Power Events Next Driver WMI Package Hardware Resource Management (DMA, Interrupt, I/O)

Add. Device – WDM Toaster. Add. Device( IN PDRIVER_OBJECT Driver. Object, IN PDEVICE_OBJECT Physical.

Add. Device – WDM Toaster. Add. Device( IN PDRIVER_OBJECT Driver. Object, IN PDEVICE_OBJECT Physical. Device. Object { status = Io. Create. Device (. . . &device. Object); fdo. Data = (PFDO_DATA) device. Object->Device. Extension; fdo. Data->Underlying. PDO = Physical. Device. Object; device. Object->Flags |= (DO_POWER_PAGABLE | DO_BUFFERED_IO); fdo. Data->Next. Lower. Driver = Io. Attach. Device. To. Device. Stack ( ); Io. Register. Device. Interface ( &GUID_DEVINTERFACE_TOASTER); device. Object->Flags &= ~DO_DEVICE_INITIALIZING; return status; }

Pn. P/Power Boilerplate – WDM Dispatch. Pnp ( IN PDEVICE_OBJECT Device. Object, IN PIRP

Pn. P/Power Boilerplate – WDM Dispatch. Pnp ( IN PDEVICE_OBJECT Device. Object, IN PIRP Irp ) { status = Io. Acquire. Remove. Lock (, Irp); switch (irp. Stack->Minor. Function) { case IRP_MN_START_DEVICE: status = Io. Forward. Irp. Synchronously(, Irp); Irp->Io. Status = status; Io. Complete. Request (Irp, IO_NO_INCREMENT); Io. Release. Remove. Lock(, Irp); return status; case IRP_MN_REMOVE_DEVICE: Io. Release. Remove. Lock. And. Wait(, Irp); Io. Skip. Current. Irp. Stack. Location(Irp); status = Io. Call. Driver(, Irp); Io. Detach. Device(); Io. Delete. Device(Device. Object); return status; case IRP_MN_QUERY_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_STOP_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: status = STATUS_SUCCESS; break; case IRP_MN_SURPRISE_REMOVAL: status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: status = STATUS_SUCCESS; break; default: status = Irp->Io. Status; break; } Irp->Io. Status = status; status = Forward. Irp(Next. Lower. Driver, Irp); return status; } NTSTATUS Dispatch. Power( IN PDEVICE_OBJECT Device. Object, IN PIRP Irp ) { status = Io. Acquire. Remove. Lock (, ); Po. Start. Next. Power. Irp(Irp); Io. Skip. Current. Irp. Stack. Location(Irp); status = Po. Call. Driver(, Irp); Io. Release. Remove. Lock(, ); return status; }

Pn. P/Power – WDF requires that you register zero or more of these callback

Pn. P/Power – WDF requires that you register zero or more of these callback events, depending on the device, to support pnp/power management Rest of this talk is about how and when to register these events, and how they map to WDM irps Evt. Device. D 0 Entry Evt. Device. D 0 Exit Evt. Device. Prepare. Hardware Evt. Device. Release. Hardware Evt. Interrupt. Enable Evt. Interrupt. Disable Evt. Device. D 0 Entry. Post. Interrupts. Disabled Evt. Device. D 0 Exit. Pre. Interrutps. Disabled Evt. Dma. Enabler. Fill Evt. Dma. Enabler. Flush Evt. Dma. Enabler. Enable Evt. Dma. Enabler. Disable Evt. Dma. Enabler. Self. Managed. Io. Start Evt. Dma. Enabler. Self. Managed. Io. Stop Evt. Device. Arm. Wake. From. S 0 Evt. Device. Disarm. Wake. From. S 0 Evt. Device. Arm. Wake. From. Sx Evt. Device. Disarm. Wake. From. Sx Evt. Device. Wake. From. Sx. Triggered Evt. Device. Wake. From. S 0 Triggered Evt. Device. Self. Managed. Io. Init Evt. Device. Self. Managed. Io. Cleanup Evt. Device. Self. Managed. Io. Suspend Evt. Device. Self. Managed. Io. Restart Evt. Io. Stop Evt. Io. Resume Evt. Device. Query. Remove Evt. Device. Query. Stop Evt. Device. Surprise. Removal

Evt. Device. Add – Software Driver NTSTATUS Toaster. Evt. Device. Add( IN WDFDRIVER Driver

Evt. Device. Add – Software Driver NTSTATUS Toaster. Evt. Device. Add( IN WDFDRIVER Driver IN PWDFDEVICE_INIT Device. Init ) { Wdf. Device. Init. Set. Io. Type(Devcie. Init Wdf. Io. Type. Buffered); Wdf. Device. Init. Set. Io. Type Wdf. Device. Init. Set. Exclusive Wdf. Device. Init. Set. Power. Not. Pageable Wdf. Device. Init. Set. Power. Inrush Wdf. Device. Init. Set. Device. Type Wdf. Device. Init. Assign. Name Wdf. Device. Init. Assign. SDDLString Wdf. Device. Init. Set. Device. Class Wdf. Device. Init. Set. Characteristics WDF_OBJECT_ATTRIBUTES_INIT(&fdo. Attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fdo. Attributes FDO_DATA); status = Wdf. Device. Create(&Device. Init &fdo. Attributes &device); fdo. Data = Toaster. Fdo. Get. Data(device); status = Wdf. Device. Create. Device. Interface(&GUID_DEVINTERFACE_TOASTER ); return status; }

Evt. Device. Add – Filter Driver NTSTATUS Filter. Evt. Device. Add( IN WDFDRIVER Driver

Evt. Device. Add – Filter Driver NTSTATUS Filter. Evt. Device. Add( IN WDFDRIVER Driver IN PWDFDEVICE_INIT Device. Init ) { Wdf. Fdo. Init. Set. Filter(Device. Init); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attributes FILTER_DATA); status = Wdf. Device. Create(&Device. Init &attributes &device); fdo. Data = Filter. Get. Device. Context(device); return status; }

Evt. Device. Add – Hardware Driver NTSTATUS Evt. Device. Add( IN WDFDRIVER Driver, IN

Evt. Device. Add – Hardware Driver NTSTATUS Evt. Device. Add( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT Device. Init ) { Wdf. Device. Init. Set. Io. Type(Device. Init, Wdf. Device. Io. Direct); Wdf. Device. Init. Set. Pnp. Power. Event. Callbacks Wdf. Device. Init. Set. Power. Policy. Ownership Wdf. Device. Init. Set. Ignore. Query. Stop. Remove Wdf. Device. Init. Register. Pnp. State. Change. Callback Wdf. Device. Init. Register. Power. Policy. State. Change. Callback WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp. Power. Callbacks); pnp. Power. Callbacks. Evt. Device. Prepare. Hardware = Evt. Prepare. Hardware; pnp. Power. Callbacks. Evt. Device. Release. Hardware = Evt. Release. Hardware; pnp. Power. Callbacks. Evt. Device. D 0 Entry = Evt. Device. D 0 Entry; pnp. Power. Callbacks. Evt. Device. D 0 Exit = Evt. Device. D 0 Exit; Wdf. Device. Init. Set. Pnp. Power. Event. Callbacks(Device. Init, &pnp. Power. Callbacks); WDF_OBJECT_ATTRIBUTES_INIT(&fdo. Attributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fdo. Attributes, FDO_DATA); fdo. Attributes. Evt. Cleanup. Callback = Evt. Device. Context. Cleanup; status = Wdf. Device. Create(&Device. Init, &fdo. Attributes, &device); status = NICAllocate. Software. Resources(fdo. Data); …. return status; }

Pn. P/Power Callbacks Evt. Device. Prepare. Hardware One time initialization, first callback where device

Pn. P/Power Callbacks Evt. Device. Prepare. Hardware One time initialization, first callback where device is in D 0 Map in memory mapped I/O, inspect hw for revision, features, etc. Evt. Device. Release. Hardware One time deinitialization, called when the device is in Dx! Unmap in memory mapped I/O, etc. Evt. Device. D 0 Entry Bring the device into D 0, no interrupts connected Evt. Device. D 0 Exit Move the device into Dx, no interrupts connected

Mapping – WDF Callbacks to WDM IRPs Evt. Prepare. Hardware Evt. Release. Hardware ↑IRP_MN_START_DEVICE

Mapping – WDF Callbacks to WDM IRPs Evt. Prepare. Hardware Evt. Release. Hardware ↑IRP_MN_START_DEVICE ↓IRP_MN_STOP_DEVICE ↓IRP_MN_SURPRISE_REMOVAL ↓IRP_MN_REMOVE_DEVICE Evt. Device. D 0 Entry ↑IRP_MN_START_DEVICE ↑ IRP_MN_SET_POWER – D 0 Irp Evt. Device. D 0 Exit ↓ IRP_MN_SET_POWER – Dx Irp ↓IRP_MN_SURPRISE_REMOVAL ↓IRP_MN_REMOVE_DEVICE ↓IRP_MN_STOP_DEVICE Evt. Device. Context. Cleanup ↓IRP_MN_REMOVE_DEVICE Up arrow means callback is invoked when the IRP is completed by the lower driver. Down arrow means callback is invoked before forwarding the IRP

Self Managed I/O Drivers may want to override automatic WDF queuing behavior by using

Self Managed I/O Drivers may want to override automatic WDF queuing behavior by using non-power managed queues Drivers may have I/O paths that don’t pass through WDFQUEUEs (timers, DPC, etc. ) WDF provides a set of callbacks that correspond to state changes Evt. Device. Self. Managed. Io. Init Evt. Device. Self. Managed. Io. Cleanup Evt. Device. Self. Managed. Io. Suspend Evt. Device. Self. Managed. Io. Restart Evt. Device. Self. Managed. Io. Flush

Self Managed I/O – Mapping Evt. Device. Self. Managed. Io. Init START_DEVICE Evt. Device.

Self Managed I/O – Mapping Evt. Device. Self. Managed. Io. Init START_DEVICE Evt. Device. Self. Managed. Io. Suspend SURPRISE_REMOVAL or REMOVE, Power-Dx Evt. Device. Self. Managed. Io. Restart Power – D 0, START after STOP Evt. Device. Self. Managed. Io. Flush Evt. Device. Self. Managed. Io. Cleanup REMOVE – For PDO it’s called when the PDO is present REMOVE - For PDO it’s called when the PDO is about to be deleted (Surprise. Remove) PCIDRV sample uses Self Managed I/O callbacks to start and stop a watchdog timer DPC

Power Policy Owner Default rules on power policy ownership Device Type Policy Owner FDO

Power Policy Owner Default rules on power policy ownership Device Type Policy Owner FDO Yes Filter No PDO No Raw-PDO Yes Override the default by calling Wdf. Device. Init. Set. Power. Policy. Ownership

Enabling Wake from Sx WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wake. Settings; WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT( &wake. Settings); status = Wdf. Device.

Enabling Wake from Sx WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wake. Settings; WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT( &wake. Settings); status = Wdf. Device. Assign. Sx. Wake. Settings(Device, &wake. Settings); Interaction with WMI to present the power management tab in device manager is automatically handled Can be called multiple times to change the settings at run-time Default is to allow user control WDF_DEVICE_POWER_ POLICY_WAKE_SETTINGS Size Dx. State User. Control. Of. Idle. Settings Enabled

Idle-Time Power Management – S 0 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idle. Settings; WDF_DEVICE_POWER_ POLICY_IDLE_SETTINGS Size Idle. Cannot.

Idle-Time Power Management – S 0 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idle. Settings; WDF_DEVICE_POWER_ POLICY_IDLE_SETTINGS Size Idle. Cannot. Wake. From. S 0 Idle. Can. Wake. From. S 0 Idle. Usb. Selective. Suspend WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_ INIT( &idle. Settings, Idle. Can. Wake. From. S 0 ); Idle. Caps idle. Settings. Idle. Timeout = 10000; // 10 -sec User. Control. Of. Idle. Settings status = Wdf. Device. Assign. S 0 Idle. Settings( Wdf. Device, &idle. Settings ); Idle. Timeout Dx. State Enabled You can manually stop and resume the Idle. Timer by calling Wdf. Device. Stop. Idle or Wd. Device. Resume. Idle WMI interaction is handled automatically Can be called multiple times to change the settings

Power Policy Event Callbacks WDF_POWER_POLICY_EVENT_CALLBACKS power. Policy. Callbacks; WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&ppc); ppc. Evt. Device. Arm. Wake.

Power Policy Event Callbacks WDF_POWER_POLICY_EVENT_CALLBACKS power. Policy. Callbacks; WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&ppc); ppc. Evt. Device. Arm. Wake. From. S 0 = Pci. Drv. Evt. Device. Wake. Arm. S 0; ppc. Evt. Device. Disarm. Wake. From. S 0 = Pci. Drv. Evt. Device. Wake. Disarm. S 0; ppc. Evt. Device. Wake. From. S 0 Triggered = Pci. Drv. Evt. Device. Wake. Triggered. S 0; ppc. Evt. Device. Arm. Wake. From. Sx = Pci. Drv. Evt. Device. Wake. Arm. Sx; ppc. Evt. Device. Disarm. Wake. From. Sx = Pci. Drv. Evt. Device. Wake. Disarm. Sx; ppc. Evt. Device. Wake. From. Sx. Triggered = Pci. Drv. Evt. Device. Wake. Triggered. Sx; Wdf. Device. Init. Set. Power. Policy. Event. Callbacks(Device, &power. Policy. Callbacks);

Mapping – Wake Callbacks to Power IRPs Suspend or hibernate - goto Sx WDF

Mapping – Wake Callbacks to Power IRPs Suspend or hibernate - goto Sx WDF receives IRP_MN_QUERY_POWER Sx WDF receives IRP_MN_SET_POWER Sx WDF sends IRP_MN_SET_POWER Dx WDF sends IRP_MN_WAIT_WAKE Evt. Device. Arm. Wake. From. Sx Evt. Device. D 0 Exit Resume from Sx due to wake event IRP_MN_WAIT_WAKE (completed by bus) Receives IRP_MN_SET_POWER S 0 – fast resume Sends IRP_MN_SET_POWER D 0 Evt. Device. D 0 Entry Evt. Device. Wake. From. Sx. Triggered Evt. Device. Disarm. Wake. From. Sx Idle-out - goto Dx in S 0 Sends IRP_MN_SET_POWER Dx Sends IRP_MN_WAIT_WAKE Evt. Device. Arm. Wake. From. S 0 Evt. Device. D 0 Exit Resume from Dx in S 0 due to wake event IRP_MN_WAIT_WAKE (completed by bus) Sends IRP_MN_SET_POWER - D 0 Evt. Device. D 0 Entry Evt. Device. Wake. From. S 0 Triggered Evt. Device. Disarm. Wake. From. S 0

Interrupts NTSTATUS Evt. Device. Add( ) { … WDF_INTERRUPT_CONFIG_INIT(&Config, NICInterrupt. Handler, NICDpc. For. Isr);

Interrupts NTSTATUS Evt. Device. Add( ) { … WDF_INTERRUPT_CONFIG_INIT(&Config, NICInterrupt. Handler, NICDpc. For. Isr); Config. Evt. Interrupt. Enable = NICEvt. Interrupt. Enable; Config. Evt. Interrupt. Disable = NICEvt. Interrupt. Disable; status = Wdf. Interrupt. Create(Device, &Config, WDF_NO_OBJECT_ATTRIBUTES, &Interrupt); } WDF_INTERRUPT_CONFIG Size Spin. Lock Share. Vector Floating. Save Queue. Dpc. On. Isr. Success Automatic. Serialization Evt. Interrupt. Isr Evt. Interrupt. Dpc Evt. Interrupt. Enable Evt. Interrupt. Disable Wdf. Interrupt. Queue. Dpc. For. Isr – to manually queue Dpc. For. Isr Register Evt. Device. D 0 Entry. Post. Interrupts. Enabled and Evt. Device. D 0 Exit. Pre. Interrupts. Disabled to be called at PASSIVE_LEVEL

FDO and PDO-Specific Callbacks Register FDO-specific events by calling Wdf. Fdo. Init. Set. Event.

FDO and PDO-Specific Callbacks Register FDO-specific events by calling Wdf. Fdo. Init. Set. Event. Callbacks Evt. Device. Filter. Add. Resource. Requirements ↓IRP_MN_FILTER_RESOURCE_R EQUIREMENTS Evt. Device. Filter. Remove. Resource. Requirements ↑IRP_MN_FILTER_RES OURCE_REQUIREMENTS Evt. Device. Remove. Added. Resources ↓ IRP_MN_START_DEVICE Register PDO-specific events by calling Wdf. Pdo. Init. Set. Event. Callbacks Evt. Device. Resources. Query ↓ IRP_MN_QUERY_RESOURCE Evt. Device. Resource. Requirements. Query ↓IRP_MN_QUERY_RESOURCE_REQUIR EMENTS Evt. Device. Eject ↓ IRP_MN_EJECT Evt. Device. Set. Lock ↓ IRP_MN_SET_LOCK Evt. Device. Enable. Wake. At. Bus ↓ IRP_MN_WAIT_WAKE Evt. Device. Disable. Wake. At. Bus ↑ IRP_MN_WAIT_WAKE

Summary - Callback Order WDF treats Pn. P and Power as a unified model

Summary - Callback Order WDF treats Pn. P and Power as a unified model WDF callbacks are based around primitive operations Order in which the primitives are called is guaranteed Next two slides show the order in which these callback are invoked for start/power-up and remove/suspend You can see the commonalities between pnp & power operation Evt. Device. D 0 Entry Evt. Device. D 0 Exit Evt. Device. Prepare. Hardware Evt. Device. Release. Hardware Evt. Device. Query. Remove Evt. Device. Query. Stop Evt. Device. Surprise. Removal Evt. Device. Self. Managed. Io. Init Evt. Device. Self. Managed. Io. Cleanup Evt. Device. Self. Managed. Io. Suspend Evt. Device. Self. Managed. Io. Restart Evt. Io. Stop Evt. Io. Resume Evt. Interrupt. Enable Evt. Interrupt. Disable Evt. Device. D 0 Entry. Post. Interrupts. Disabled Evt. Device. D 0 Exit. Pre. Interrutps. Disabled Evt. Device. Arm. Wake. From. S 0 Evt. Device. Disarm. Wake. From. S 0 Evt. Device. Arm. Wake. From. Sx Evt. Device. Disarm. Wake. From. Sx Evt. Device. Wake. From. Sx. Triggered Evt. Device. Wake. From. S 0 Triggered Evt. Dma. Enabler. Fill/Flush Evt. Dma. Enabler. Enable/Disable Evt. Dma. Enabler. Self. Managed. Io. Start/Stop

Start/Power Up Path DState = D 3 Final 1 2 SUSPENDED DState = DX

Start/Power Up Path DState = D 3 Final 1 2 SUSPENDED DState = DX STOPPED Add. Device Evt. Device. Remove. Added. Resources Evt. Prepare. Hardware This flow chart shows the order Device, I/O, Interrupt and DMA callbacks are invoked when the device is first started, started from stopped state due to resource rebalance or from a suspended state WDF Evt. Device. D 0 Entry(DState) Evt. Interrupt. Enable Evt. Device. D 0 Entry. Post. Interrupts. Enabled Evt. Dma. Enabler. Fill/Enable Evt. Dma. Enabler. Self. Managed. Io. Start Evt. Device. Wake. Disarm. Sx or S 0 Evt. Io. Resume - on in-flight request Evt. Device. Self. Managed. Io. Restart Were you armed for wake? NO YES First power up? NO Evt. Device. Self. Managed. Io. Init YES STARTED

Remove/Surprise-Remove/Stop/ Power-Down Path WDF YES Stopping or removing? NO YES NO 2 SUSPENDED YES

Remove/Surprise-Remove/Stop/ Power-Down Path WDF YES Stopping or removing? NO YES NO 2 SUSPENDED YES Arm for wake? Power down? STARTED Evt. Device. Self. Managed. Io. Suspend Evt. Io. Stop (Suspend) - on every inflight request Evt. Device. Arm. Wake. From. Sx or S 0 Evt. Dma. Enabler. Self. Managed. Io. Stop Evt. Dma. Enabler. Disable Evt. Dma. Enabler. Flush Evt. Device. D 0 Exit. Pre. Interrupts. Disabled Evt. Interrupt. Disable Evt. Device. D 0 Exit(DState) NO Evt. Release. Hardware 1 STOPPED REMOVED NO YES Remove? Evt. Io. Stop (Purge) - on every in-flight request Evt. Device. Self. Managed. Io. Flush Evt. Device. Self. Managed. Io. Cleanup Evt. Object. Cleanup(Device)

I/O Stage WDFREQUEST Parallel Queue I/O Package Read/Write/IOCTLs// Sequential Queue Create/Close/Cleanup Manual Queue Pn.

I/O Stage WDFREQUEST Parallel Queue I/O Package Read/Write/IOCTLs// Sequential Queue Create/Close/Cleanup Manual Queue Pn. P/Power Events I R P Pn. P/Power Events IRP Dispatcher Pn. P/Power Package Io. Target Next Driver Pn. P/Power/WMI IRPs Pn. P/Power Events WMI Package Hardware Resource Management (DMA, Interrupt, I/O)

Queues Queue object is used to present WDFREQUEST to the driver Only create, read,

Queues Queue object is used to present WDFREQUEST to the driver Only create, read, write, and IOCTL IRPs are converted to WDFREQUEST and presented by queues Delivery of requests is based on the queue type Sequential: Requests are delivered one at a time Parallel: Requests are delivered to the driver as they arrive Manual: Driver retrieves requests from the WDQUEUE at its own pace WDF_EXECUTION_LEVEL and WDF_SYNCHRONIZATION_SCOPE can be used to control serialization and IRQL level of those callbacks WDFQUEUE is more than a list of pending requests!

Creating a Queue WDF_IO_QUEUE_CONFIG Size NTSTATUS Evt. Device. Add( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT

Creating a Queue WDF_IO_QUEUE_CONFIG Size NTSTATUS Evt. Device. Add( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT Device. Init ) { Dispatch. Type Power. Managed Default. Queue Allow. Zero. Length. Requests Evt. Io. Default …. WDF_IO_QUEUE_CONFIG_INIT_DEFUALT_QUEUE( &Config, Wdf. Io. Queue. Dispatch. Parallel ); Config. Evt. Io. Start = Pci. Drv. Evt. Io. Start; Config. Allow. Zero. Length. Requests = TRUE; status = Wdf. Io. Queue. Create( Wdf. Device, &Config, WDF_NO_OBJECT_ATTRIBUTES, &Queue // queue handle ); return status; } Evt. Io. Read Evt. Io. Write Evt. Io. Device. Control Evt. Io. Internal. Device. Control Evt. Io. Stop Evt. Io. Resume typedef enum _WDF_IO_QUEUE_DISPATCH_TYPE { Wdf. Io. Queue. Dispatch. Sequential = 1, Wdf. Io. Queue. Dispatch. Parallel, Wdf. Io. Queue. Dispatch. Manual, Wdf. Io. Queue. Dispatch. Max } WDF_IO_QUEUE_DISPATCH_TYPE;

WDFQUEUE Events Evt. Io. Default – Called for any request that does not have

WDFQUEUE Events Evt. Io. Default – Called for any request that does not have a specific callback registered Evt. Io. Read – Called for IRP_MJ_READ requests Evt. Io. Write – Called for IRP_MJ_WRITE requests Evt. Io. Device. Control – Called for IRP_MJ_DEVICE_CONTROL Evt. Io. Internal. Device. Control – Called for IRP_MJ_INTERNAL_DEVICE_CONTROL requests Evt. Io. Stop – Called for all inflight requests when a power down transition occurs Evt. Io. Resume - Called for all inflight requests when a power up transition occurs

Default Queue Default queue receives all requests that are not configured to go to

Default Queue Default queue receives all requests that are not configured to go to other queues There can be only one default queue per device ead R te & TS S Wri E EQU R Evt. Io. Default F WD Read/W rite/ IOCTLs IRPS Default I/O Package Pnp/Power Events Pn. P/Power Parallel Queue Evt. Io. Device. Control ioct l WD FRE QUE STS

Preconfigured Queue Preconfigure the queue by calling Wdf. Device. Configure. Request. Dispatching to automatically

Preconfigured Queue Preconfigure the queue by calling Wdf. Device. Configure. Request. Dispatching to automatically forward requests based on the I/O type Read/ Write/ IOCTLs IRPS Write & Read WDFREQUESTS Default I/O Package Pn. P/Power Events Parallel Queue Evt. Io. Device. Control IOCTL Parallel Queue Pn. P/Power Evt. Io. Default

Multiple queues Manually forward requests by calling Wdf. Request. Forward. To. Io. Queue WDFREQUEST

Multiple queues Manually forward requests by calling Wdf. Request. Forward. To. Io. Queue WDFREQUEST Parallel - Read/ Write/ IOCTL I/O Package Sequential - Write Pn. P/Power Events Parallel - IOCTL Pn. P/Power Manual Queue

Queue State Queue state is determined by whether it’s accepting and dispatching requests to

Queue State Queue state is determined by whether it’s accepting and dispatching requests to the driver Accept Dispatch Queue Started Accepting – Y Dispatching - Y Stopped Accepting – Y Dispatching - N Draining Accepting – N Dispatching - Y Purging Accepting – N Dispatching - N For non-power managed queue, driver controls the state of the queue Queue can be moved to any state from any state For power managed queue, state change happens due to Pn. P/Power events

DDIs for Changing Queue States Wdf. Io. Queue. Start Accept and dispatch requests Wdf.

DDIs for Changing Queue States Wdf. Io. Queue. Start Accept and dispatch requests Wdf. Io. Queue. Stop Accept and queue requests Wdf. Io. Queue. Stop. Synchronously Accept and queue requests, and wait for the driver-owned request to complete before returning to the caller Wdf. Io. Queue. Drain Fail new requests and dispatch queued requests Wdf. Io. Queue. Drain. Synchronously Fail new requests, dispatch queued requests and wait for all the requests to complete before returning to the caller Wdf. Io. Queue. Purge Fail new requests, cancel queued requests, cancel in-flight requests (if marked cancelable) Wdf. Io. Queue. Purge. Synchronously Fail new requests, cancel queued requests, cancel in-flight requests (if they are marked cancelable), and wait for all the requests to complete before returning to the caller

Power Managed Queue Power State Dispatch Accept Add. Device - Created ON/OFF Accepting -

Power Managed Queue Power State Dispatch Accept Add. Device - Created ON/OFF Accepting - Yes Power State - OFF Dispatching - Yes START_DEVICE REMOVE_DEVICE SET_POWER (D 0) Purge power managed and unmanaged queues SET_POWER (Dx) STOP_DEVICE Accepting - Yes Power State - ON Dispatching - Yes REMOVE_DEVICE Accepting - No Power State - OFF Dispatching - Yes SURPRISE_REMOVAL Deleted

Create/Cleanup/Close Register during device initialization if you are interested in handling Create, Close and

Create/Cleanup/Close Register during device initialization if you are interested in handling Create, Close and Cleanup requests WDF by default succeeds these requests if you don’t register a callback WDF_DEVICE_FILE_OBJECT_INIT( &file. Obj. Config, File. Io. Evt. Device. File. Create, File. Io. Evt. Device. Close, WDF_NO_EVENT_CALLBACK); Size Auto. Forward. Cleanup. Close Evt. Device. File. Create Evt. File. Close Evt. File. Cleanup File. Object. Class Wdf. Device. Init. Set. File. Object. Config(Device. Init, &file. Obj. Config, WDF_NO_OBJECT_ATTRIBUTES); Evt. Device. File. Create( WDFDEVICE Device, WDFREQUEST Request, WDFFILEOBJECT File. Object ) Evt. File. Cleanup(WDFFILEOBJECT File. Object) Evt. File. Close(WDFFILEOBJECT File. Object);

Create/Close/Cleanup Create request You can pend, forward it another queue, send it to an

Create/Close/Cleanup Create request You can pend, forward it another queue, send it to an Io. Target You can configure to auto-dispatch create to a specific queue Evt. Io. Default callback is invoked when a create request is dispatched by a queue Cleanup/Close WDF doesn’t provide a request for these events If you send create requests down the stack, you must set the Auto. Forward. Cleanup. Close property so that WDF can forward Cleanup and Close requests For filters, if the callbacks are not registered, WDF will auto-forward Create, Close and Cleanup

Request Cancellation Requests waiting in the queue to be delivered to the driver are

Request Cancellation Requests waiting in the queue to be delivered to the driver are automatically cancelable In-flight requests cannot be canceled unless explicitly made cancelable by calling Wdf. Request. Mark. Cancelable(Request, Evt. Request. Cancel) A request should be made cancelable by the driver if: The I/O is going to take long time to complete The I/O operation on the hardware can be stopped in mid-operation A cancelable request must be unmarked (Wdf. Request. Unmark. Cancelable) before completion unless it’s completed by the cancel routine These rules are similar to WDM

Read/Write/IOCTL Callbacks VOID Evt. Io. Read( Evt. Io. Write( IN WDFQUEUE Queue, IN WDFQUEUE

Read/Write/IOCTL Callbacks VOID Evt. Io. Read( Evt. Io. Write( IN WDFQUEUE Queue, IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length IN size_t Length ) ) VOID Evt. Io. Device. Control( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Output. Buffer. Length, IN size_t Input. Buffer. Length, IN ULONG Io. Control. Code )

Request Buffers Getting input buffer Wdf. Request. Retrieve. Input. Buffer Wdf. Request. Retrieve. Input.

Request Buffers Getting input buffer Wdf. Request. Retrieve. Input. Buffer Wdf. Request. Retrieve. Input. Memory Wdf. Request. Retrieve. Input. Wdm. Mdl Getting output buffer Wdf. Request. Retrieve. Output. Buffer Wdf. Request. Retrieve. Output. Memory Wdf. Request. Retrieve. Output. Wdm. Mdl ‘Input’ or ‘Output’ denotes the direction of memory access Input: read from memory and write to device Output: read from device and write to memory

Retrieve Buffer of Read Request Function Read - Buffered Read - Direct Wdf. Request.

Retrieve Buffer of Read Request Function Read - Buffered Read - Direct Wdf. Request. Retrieve. O utput. Buffer Return Irp->Associated. Irp. System. Buffer Return System. Address. For. Mdl( Irp->Mdl. Address) Wdf. Request. Retrieve. O utput. Wdm. Mdl Build an MDL for Return Irp->Mdl. Address Irp->Associated. Irp. System. Buffer and return the MDL. Wdf. Request. Retrieve. O uput. Memory Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give you Irp>Associated. Irp. System. Buffer Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give you System. Address. For( Irp->Mdl. Address). Calling Wdf. Request. Retrieve. Input. Xxx functions on Read request will return STATUS_INVALID_DEVICE_REQUEST error.

Retrieve Buffer of Write Request Function Read - Buffered Read - Direct Wdf. Request.

Retrieve Buffer of Write Request Function Read - Buffered Read - Direct Wdf. Request. Retrieve Input. Buffer Return Irp->Associated. Irp. System. Buffer Return System. Address. For. Mdl( Irp->Mdl. Address) Wdf. Request. Retrieve Input. Wdm. Mdl Build an MDL for Return Irp->Mdl. Address Irp->Associated. Irp. System. Buffer and return the MDL. Wdf. Request. Retrieve Input. Memory Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give you Irp>Associated. Irp. System. Buffer Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give you System. Address. For( Irp->Mdl. Address). Calling Wdf. Request. Retrieve. Output. Xxx functions on Write request will return STATUS_INVALID_DEVICE_REQUEST error

Retrieve Buffers of IOCTL Request Function Wdf. Request. Retrieve. Input. Buffer Wdf. Request. Retrieve.

Retrieve Buffers of IOCTL Request Function Wdf. Request. Retrieve. Input. Buffer Wdf. Request. Retrieve. Input. Wdm. Mdl Wdf. Request. Retrieve. Input. Memory Wdf. Request. Retrieve. Output. Buffer Wdf. Request. Retrieve. Output. Wdm. Mdl Wdf. Request. Retrieve. Output. Memory Buffered - IOCTL Return Irp->Associated. Irp. System. Buffer Build an MDL for Irp->Associated. Irp. System. Buffer and return the MDL Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give you Irp->Associated. Irp. System. Buffer

Retrieve Buffers of IOCTL Request (con’t) Function Wdf. Request. Retrieve. Input. Buffer Wdf. Request.

Retrieve Buffers of IOCTL Request (con’t) Function Wdf. Request. Retrieve. Input. Buffer Wdf. Request. Retrieve. Input. Wdm. Mdl Wdf. Request. Retrieve. Input. Memory Wdf. Request. Retrieve. Output. Buffer Wdf. Request. Retrieve. Output. Wdm. Mdl Wdf. Request. Retrieve. Output. Memory Buffered - IOCTL Return Irp->Associated. Irp. System. Buffer Build an mdl for Irp->Associated. Irp. System. Buffer and return the MDL Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give you Irp->Associated. Irp. System. Buffer Return System. Address. For. Mdl(Irp>Mdl. Address ) Return Irp->Mdl. Address Wdf. Memory. Buffer. Get. Buffer on the returned WDFMEMORY will give System. Address. For( Irp->Mdl. Address)

METHOD_NEITHER Requests To handle this type of request, you must register Evt. Io. In.

METHOD_NEITHER Requests To handle this type of request, you must register Evt. Io. In. Caller. Context callback by calling Wdf. Device. Init. Set. Io. In. Caller. Context. Callback is invoked in the calling thread context Retrieve buffers using Wdf. Request. Retrieve. Unsafe. User. Input. Buffer Wdf. Request. Retrieve. Unsafe. User. Output. Buffer Lock using Wdf. Request. Probe. And. Lock. User. Buffer. For. Read/Write Read Input. Buffer Error Output. Buffer Irp->User. Buffer Write Irp->User. Buffer Error IOCTL irp. Stack->Parameters. Device. Io. Control. Type 3 Input. Buffer Irp->User. Buffer

Timer/DPC/Work Item WDFTIMER WDFDPC WDFWORKITEM KTIMER (Ke. Initialize. Timer. Ex) KDPC (Ke. Initialize. Dpc)

Timer/DPC/Work Item WDFTIMER WDFDPC WDFWORKITEM KTIMER (Ke. Initialize. Timer. Ex) KDPC (Ke. Initialize. Dpc) IO_WORKITEM (Io. Allocate. Work. Item) Value add Allows you to synchronize execution with the callback events of a specific queue (by parenting to WDFQUEUE) or all queues (by parenting to WDFDEVICE) Ensures callbacks events are not invoked after the object is deleted – rundown protection Ensures that object is not deleted until the callback has run to completion Enables you to have private context

DPC WDF_DPC_CONFIG NTSTATUS Evt. Device. Add( ) { … WDF_DPC_CONFIG_INIT(&config, Evt. Dpc); Size Evt.

DPC WDF_DPC_CONFIG NTSTATUS Evt. Device. Add( ) { … WDF_DPC_CONFIG_INIT(&config, Evt. Dpc); Size Evt. Dpc. Func Driver. Wdm. Dpc Automatic. Serialization config. Automatic. Serialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes. Parent. Object = device; Wdf. Dpc. Create() status = Wdf. Dpc. Create(&Config, &attributes, &h. Dpc); } Wdf. Dpc. Enqueue() Wdf. Dpc. Cancel(Wait) Wdf. Dpc. Get. Parent. Object() Wdf. Dpc. Wdm. Get. Dpc() Wdf. Object. Delete()

Timer WDF_TIMER_CONFIG NTSTATUS Evt. Device. Add( ) { … WDF_TIMER_CONFIG_INIT(&config, Evt. Timer); Size Evt.

Timer WDF_TIMER_CONFIG NTSTATUS Evt. Device. Add( ) { … WDF_TIMER_CONFIG_INIT(&config, Evt. Timer); Size Evt. Timer. Func Period Automatic. Serialization config. Automatic. Serialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes. Parent. Object = device; status = Wdf. Timer. Create(&Config, &attributes, &h. Timer); } Wdf. Timer. Create() Wdf. Timer. Start() Wdf. Timer. Stop(Wait) Wdf. Timer. Get. Parent. Object() Wdf. Object. Delete()

Work Item WDF_TIMER_CONFIG NTSTATUS Evt. Device. Add( ) { … WDF_WORKITEM_CONFIG_INIT(&config, Evt. Work. Item);

Work Item WDF_TIMER_CONFIG NTSTATUS Evt. Device. Add( ) { … WDF_WORKITEM_CONFIG_INIT(&config, Evt. Work. Item); Size Evt. Work. Item. Func Automatic. Serialization config. Automatic. Serialization = TRUE; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); Wdf. Work. Item. Create() attributes. Parent. Object = device; status = Wdf. Work. Item. Create(&Config, &attributes, &h. Work. Item); } Wdf. Work. Item. Enqueue() Wdf. Work. Item. Flush() Wdf. Work. Item. Get. Parent. Object() Wdf. Object. Delete()

Locks Framework provides two kinds of locks: WDFWAITLOCK Synchronize access to resources at IRQL

Locks Framework provides two kinds of locks: WDFWAITLOCK Synchronize access to resources at IRQL < DISPATCH_LEVEL WDFSPINLOCK – Synchronize access to resources at IRQL <= Mapping WDF Wdf. Wait. Lock. Create WDM Ke. Initialize. Event (Sychronization. Event) Wdf. Wait. Lock. Acquire Ke. Enter. Critical. Region (Optional - Time. Out) Ke. Wait. For. Single. Object Wdf. Wait. Lock. Release Ke. Set. Event Ke. Leave. Critical. Region WDF WDM DISPATCH_LEVEL Value add Has its own deadlock detection support Tracks acquisition history Wait. Lock protects against thread suspension You can have private context specific to lock Wdf. Spin. Lock. Create Ke. Initialize. Spin. Lock Wdf. Spin. Lock. Acquire Ke. Acquire. Spin. Lock Wdf. Spin. Lock. Release Ke. Release. Spin. Lock

Synchronization Scope & Execution Level WDF_EXECUTION_LEVEL Wdf. Execution. Level. Inherit. From. Parent Wdf. Execution.

Synchronization Scope & Execution Level WDF_EXECUTION_LEVEL Wdf. Execution. Level. Inherit. From. Parent Wdf. Execution. Level. Passive Wdf. Execution. Level. Dispatch WDF_SYNCHRONIZATION_SCOPE Wdf. Synchronization. Scope. Inherit. From. Parent Wdf. Synchronization. Scope. Device Wdf. Synchronization. Scope. Object Wdf. Synchronization. Scope. None Wdf. Execution. Level. Passive Callbacks will be invoked at PASSIVE_LEVEL Can be set only on device, queue and fileobject Creation of timer and DPC with Automatic. Serialization won’t be allowed if this attribute is set on its parent which could be device or queue Wdf. Synchronization. Scope. Device Callback events of queue, fileobject, timer, dpc, & workitem will be synchronized by a common lock Choice of lock depends on the execution level (fast mutex or spinlock) Wdf. Synchronization. Scope. Object Can be set only on queue if you want all the callbacks of a queue to be serialized with its own lock

Sample Scenario – Serial Driver. Entry() { WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes. Synchronization. Scope = Wdf. Synchronization.

Sample Scenario – Serial Driver. Entry() { WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes. Synchronization. Scope = Wdf. Synchronization. Scope. Device; status = Wdf. Driver. Create(, , &attributes, , ); } Evt. Device. Add() { WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue. Config, Parallel); queue. Config. Evt. Io. Read = Serial. Evt. Io. Read; queue. Config. Evt. Io. Write = Serial. Evt. Io. Write; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes. Synchronization. Scope = Wdf. Synchronization. Scope. Device; status = Wdf. Io. Queue. Create(, queue. Config, &attributes, ); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes. Parent. Object = Device; WDF_TIMER_CONFIG_INIT(&timer. Config, Serial. Timeout. Xoff); timer. Config. Automatic. Serialization = TRUE; status = Wdf. Timer. Create(&timer. Config, &attributes, ); }

Synchronization Scope & Execution Level - Summary Object Locks: what kind and who provides

Synchronization Scope & Execution Level - Summary Object Locks: what kind and who provides it? WDFDRIVER If you specify Synch. Scope. Object, framework acquires fast mutex when it calls Evt. Device. Add. Since there is no parent for WDFDRIVER, the Synch. Scope. Inherit. From. Parent is same as Synch. Scope. None. If Synch. Scope. Device is used, all the devices will be created with Synch. Scope. Device attributes. WDFDEVICE Depending on the Execution. Level, this object provides a spin lock or fast mutex as the presentation lock to other objects such as WDFQUEUE WDFDPC, WDFTIMER, WDFWORKITEM, WDFFILEOBJECT. Pn. P/Power events do not use this presentation lock. WDFQUEUE If you specify Synch. Scope. Device or Inherit. From. Parent, lock is provided by the device. If you specify Synch. Scope. Object, lock is provided by the queue. Depending on the execution level, the lock is either a spin lock or fast mutex. WDFFILEOBJECT Synch. Scope. Object is not allowed on this object. If you specify Exec. Level. Passive and Synch. Scope. Device or Inherit. From. Parent then the parent device Exec. Level should also be Passive. WDFTIMER/DPC/ WORKITEM By setting Automatic. Serialization property, you can synchronize its events with the parent object’s events

I/O Target WDFREQUEST Parallel Queue I/O Package Read/Write/IOCTLs/ Create/Close/Cleanup Sequential Queue Manual Queue I

I/O Target WDFREQUEST Parallel Queue I/O Package Read/Write/IOCTLs/ Create/Close/Cleanup Sequential Queue Manual Queue I R P Pn. P/Power Events IRP Dispatcher Pn. P/Power Package Pn. P/Power Events Next Driver Io. Target Pn. P/Power Events Hardware Resource Management WMI Package (DMA, Interrupt, I/O)

Sending Request - I/O Target What is an Io. Target? A “target” device object

Sending Request - I/O Target What is an Io. Target? A “target” device object to which you want to send requests This “target” device object can be the next attached device (default target) or can be a device object outside your device stack (remote target) Where would I use it? Instead of Io. Call. Driver() – either forwarding request that you received from driver above or when you are rolling your own request and sending to another driver Io. Target sends I/O in coordination with Pn. P state of the target owner and the target state itself Io. Target provides synchronization of sent I/O with target state changes

Default I/O Target Wdf. Device. Get. Io. Target returns WDFIOTARGET for the next lower

Default I/O Target Wdf. Device. Get. Io. Target returns WDFIOTARGET for the next lower device object Forward. Request( WDFDEVICE Device, WDFREQUEST Request) { BOOLEAN ret; WDFIOTARGET io. Target = Wdf. Device. Get. Io. Target(Device); Wdf. Request. Copy. Current. Stack. Location. To. Next ( Request ); Wdf. Request. Set. Completion. Routine (Request, Completion. Routine, NULL); ret = Wdf. Request. Send (Request, io. Target, NULL); if (!ret) { status = Wdf. Request. Get. Status (Request); Debug. Print( ("Wdf. Request. Send failed: 0 x%xn", status)); Wdf. Request. Complete(Request, status); } }

Remote I/O Target Remote I/O target represents a device object: either part of your

Remote I/O Target Remote I/O target represents a device object: either part of your driver or created by some other driver Replacement for Io. Get. Device. Object. Pointer, Zw. Create. File & Io. Register. Plug. Play. Notification( Event. Category. Target. Device. Change ) status = Wdf. Io. Target. Create(Device, WDF_NO_OBJECT_ATTRIBUTES, &Io. Target); WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE( &open. Params, Wdf. True, Device. Object); status = Wdf. Io. Target. Open(Io. Target, &open. Params); INIT_OPEN_BY_NAME INIT_CREATE_BY_NAME

Send Your Own Request - Synchronous Io. Build. Synchronous. Fsd. Request maps to: Wdf.

Send Your Own Request - Synchronous Io. Build. Synchronous. Fsd. Request maps to: Wdf. Io. Target. Send. Read. Synchronously Wdf. Io. Target. Send. Write. Synchronously Io. Build. Device. Io. Control. Request maps to: Wdf. Io. Target. Send. Ioctl. Synchronously Wdf. Io. Target. Send. Internal. Ioctl. Others. Synchronously

Send Your Own Request - Synchronous Buffers used in synchronous requests can be a

Send Your Own Request - Synchronous Buffers used in synchronous requests can be a PVOID, MDL or WDFMEMORY handle INIT_MDL INIT_HANDLE WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&input. Buf. Desc, &in. Buf, in. Len); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&output. Buf. Desc, out. Buf, out. Len); status = Wdf. Io. Target. Send. Ioctl. Synchronously(io. Target, NULL, // let framework allocate IRP IOCTL_ACPI_ASYNC_EVAL_METHOD, &input. Buf. Desc, &output. Buf. Desc, NULL, // Option NULL); // bytes. Returned Requests may be sent with a combination of the following options Timeout Force Send (override I/O Target’s Dispatching state)

Roll Your Own Request- Asynchronous Io. Build. Asynchronous. Fsd. Request maps to Wdf. Io.

Roll Your Own Request- Asynchronous Io. Build. Asynchronous. Fsd. Request maps to Wdf. Io. Target. Format. Request. For. Write Wdf. Io. Target. Format. Request. For. Read Wdf. Io. Target. Format. Request. For. Ioctl Wdf. Io. Target. Format. Request. For. Internal. Ioctl followed by - Wdf. Request. Send I/O targets exclusively use reference counted memory handles for asynchronous IO The driver cannot use raw pointers!

Send Your Own Request - Asynchronous status = Wdf. Request. Create(WDF_NO_OBJECT_ATTRIBUTES, Io. Target, &Request);

Send Your Own Request - Asynchronous status = Wdf. Request. Create(WDF_NO_OBJECT_ATTRIBUTES, Io. Target, &Request); status = Wdf. Memory. Create(WDF_NO_OBJECT_ATTRIBUTES, Non. Paged. Pool, POOL_TAG, sizeof(struct ABC), &Memory, (PVOID*) &buffer); status = Wdf. Io. Target. Format. Request. For. Read(Io. Target, Request, Memory, //Input. Buffer NULL, // Buffer. Offset NULL); // Device. Offset Wdf. Request. Set. Completion. Routine(Request, Read. Request. Completion, WDF_NO_CONTEXT); if( Wdf. Request. Send(Request, Io. Target, NULL) == FALSE) { status = Wdf. Request. Get. Status(Request); }

Escape to WDM Converting to WDF is an iterative process Do the conversion stage

Escape to WDM Converting to WDF is an iterative process Do the conversion stage by stage PNP/POWER – escape to WDM for other things Request handling I/O Target WDF allows you to get all the underlying WDM objects easily Wdf. Request. Wdm. Get. Irp Wdf. Device. Wdm. Get. Attached. Device Wdf. Device. Wdm. Get. Physical. Device Wdf. Device. Wdm. Get. Device. Object

Great Escape WDFREQUEST Parallel Queue I/O Package Complete IRP Read/Write/IOCTLs Sequential Queue Manual Queue

Great Escape WDFREQUEST Parallel Queue I/O Package Complete IRP Read/Write/IOCTLs Sequential Queue Manual Queue Pn. P/Power Events IRP Dispatcher Preprocessor Forward to Next Driver Pn. P/Power Package Pn. P/Power Events WMI Package Io. Target Hardware Resource Management (DMA, Interrupt, I/O)

Great Escape – Sample Code Evt. Device. Add() { status = Wdf. Device. Init.

Great Escape – Sample Code Evt. Device. Add() { status = Wdf. Device. Init. Assign. Wdm. Irp. Preprocess. Callback( Device. Init, Power. Dispatch. Handler, IRP_MJ_POWER, NULL, 0); } NTSTATUS Power. Dispatch. Handler(WDFDEVICE Device, PIRP Irp) { irp. Stack = Io. Get. Current. Irp. Stack. Location(Irp); irp. String = (irp. Stack->Parameters. Power. Type == System. Power. State) ? "S-IRP" : "D-IRP"; state = irp. Stack->Parameters. Power. State; extension. Header = Get. Device. Context(Device); Debug. Print((0, "%s: %s %s %s: 0 x%x n", (extension. Header->Is. Fdo? "FDO": "PDO"), irp. String, Power. Minor. Function. String(irp. Stack->Minor. Function), power. State. String, Irp)); return Wdf. Device. Wdm. Dispatch. Preprocessed. Irp(Device, Irp); }

Call to Action Work together with us to make WDF successful Consider WDF for

Call to Action Work together with us to make WDF successful Consider WDF for any Windows driver development project Join WDF beta program Use the special guest account (Guest ID: Guest 4 WDF) on http: //beta. microsoft. com Provide feedback Email windf @ microsoft. com - Kernel Mode Driver Framework umdfdbk @ microsoft. com - User Mode Driver Framework drvpft @ microsoft. com - PREfast for Drivers sdvfdbk @ microsoft. com - Static Driver Verifier Newsgroups microsoft. beta. windows. driverfoundation. announcements Web Resources http: //www. microsoft. com/whdc/driver/wdf/default. mspx http: //www. microsoft. com/whdc/Dev. Tools/ddk/default. mspx

Reference Slides

Reference Slides

Sample Scenarios – Callback Order Following slides show in what order all the events

Sample Scenarios – Callback Order Following slides show in what order all the events of device, queue, interrupt and DMA enabler object are triggered by the Pn. P/Power stage for the following scenarios Start device Disable or uninstall the device Surprise-Removal Resource rebalance Failed query-remove or failed query-stop System suspend System resume Slides also show the Pn. P/Power IRP context in which these events are invoked

Start Device Add. Device Evt. Device. Add IRP_MN_START_DEVICE Evt. Device. Prepare. Hardware Evt. Device.

Start Device Add. Device Evt. Device. Add IRP_MN_START_DEVICE Evt. Device. Prepare. Hardware Evt. Device. D 0 Entry Evt. Interrupt. Enable Evt. Device. D 0 Entry. Post. Interrupts. Enabled Evt. Dma. Enabler. Enable Evt. Dma. Enabler. Fill Evt. Dma. Enabler. Self. Managed. Io. Start Evt. Device. Self. Managed. Io. Init

Disable or Uninstall Device IRP_MN_QUERY_REMOVE_DEVICE Evt. Device. Query. Remove IRP_MN_REMOVE_DEVICE Evt. Device. Self. Managed.

Disable or Uninstall Device IRP_MN_QUERY_REMOVE_DEVICE Evt. Device. Query. Remove IRP_MN_REMOVE_DEVICE Evt. Device. Self. Managed. Io. Suspend Evt. Io. Stop – Suspend Evt. Dma. Enabler. Self. Managed. Io. Stop Evt. Dma. Enabler. Disable Evt. Dma. Enabler. Flush Evt. Interrupt. Disable Evt. Device. D 0 Exit - D 3 Final Evt. Device. Release. Hardware Evt. Io. Stop - Purge Evt. Device. Self. Managed. Io. Flush Evt. Device. Self. Managed. Io. Cleanup Evt. Device. Context. Cleanup _WDF_POWER_DEVICE_STATE { Wdf. Power. Device. Unspecified = 0, Wdf. Power. Device. D 1, Wdf. Power. Device. D 2, Wdf. Power. Device. D 3 Final, Wdf. Power. Device. Prepare. For. Hiber, Wdf. Power. Device. Maximum, } WDF_POWER_DEVICE_STATE,

Surprise Remove Device IRP_MN_SURPRISE_REMOVAL Evt. Device. Surprise. Removal Evt. Device. Self. Managed. Io. Suspend

Surprise Remove Device IRP_MN_SURPRISE_REMOVAL Evt. Device. Surprise. Removal Evt. Device. Self. Managed. Io. Suspend Evt. Io. Stop – Suspend Evt. Dma. Enabler. Self. Managed. Io. Stop Evt. Dma. Enabler. Disable Evt. Dma. Enabler. Flush Evt. Interrupt. Disable Evt. Device. D 0 Exit - D 3 Final Evt. Device. Release. Hardware Evt. Io. Stop - Purge Evt. Device. Self. Managed. Io. Flush Evt. Device. Self. Managed. Io. Cleanup IRP_MN_REMOVE_DEVICE Evt. Device. Context. Cleanup

Resource Rebalance IRP_MN_QUERY_STOP_DEVICE Evt. Device. Query. Stop IRP_MN_STOP_DEVICE Evt. Device. Self. Managed. Io. Suspend

Resource Rebalance IRP_MN_QUERY_STOP_DEVICE Evt. Device. Query. Stop IRP_MN_STOP_DEVICE Evt. Device. Self. Managed. Io. Suspend Evt. Io. Stop – Suspend Evt. Dma. Enabler. Self. Managed. Io. Stop Evt. Dma. Enabler. Disable/Flush Evt. Interrupt. Disable Evt. Device. D 0 Exit - D 3 Final Evt. Device. Release. Hardware IRP_MN_START_DEVICE Evt. Device. Prepare. Hardware Evt. Device. D 0 Entry Evt. Interrupt. Enable Evt. Io. Resume Evt. Dma. Enabler. Enable/Fill Evt. Dma. Enabler. Self. Managed. Io. Start Evt. Device. Self. Managed. Io. Restart

Failed Remove or Stop Failed Remove IRP_MN_QUERY_REMOVE_DEVICE Evt. Device. Query. Remove IRP_MN_CANCEL_REMOVE_DEVICE Failed Stop:

Failed Remove or Stop Failed Remove IRP_MN_QUERY_REMOVE_DEVICE Evt. Device. Query. Remove IRP_MN_CANCEL_REMOVE_DEVICE Failed Stop: IRP_MN_QUERY_STOP_DEVICE Evt. Device. Query. Stop IRP_MN_CANCEL_STOP_DEVICE

System Suspend IRP_MN_QUERY_POWER Sx (WDF doesn’t send IRP_MN_QUERY_POWER Dx) IRP_MN_SET_POWER Sx IRP_MN_SET_POWER Dx Evt.

System Suspend IRP_MN_QUERY_POWER Sx (WDF doesn’t send IRP_MN_QUERY_POWER Dx) IRP_MN_SET_POWER Sx IRP_MN_SET_POWER Dx Evt. Device. Self. Managed. Io. Suspend Evt. Io. Stop - Suspend on every in-flight request WDF sends IRP_MN_WAIT_WAKE Evt. Device. Arm. Wake. From. Sx Evt. Dma. Enabler. Self. Managed. Io. Stop Evt. Dma. Enabler. Disable/Flush Evt. Interrupt. Disable Evt. Device. D 0 Exit

System Resume System sends IRP_MN_SET_POWER S 0 WDF completes it first to allow fast

System Resume System sends IRP_MN_SET_POWER S 0 WDF completes it first to allow fast resume Then WDF sends IRP_MN_SET_POWER D 0 WDF cancels IRP_MN_WAIT_WAKE IRP_MN_SET_POWER D 0 Evt. Device. D 0 Entry Evt. Interrupt. Enable Evt. Dma. Enabler. Fill Evt. Dma. Enabler. Enable Evt. Dma. Enabler. Self. Managed. Io. Start Evt. Io. Resume Evt. Device. Self. Managed. Io. Restart Evt. Device. Disarm. Wake. From. Sx

Parsing HW Resources NTSTATUS Pci. Drv. Evt. Device. Prepare. Hardware ( WDFDEVICE Device, WDFCMRESLIST

Parsing HW Resources NTSTATUS Pci. Drv. Evt. Device. Prepare. Hardware ( WDFDEVICE Device, WDFCMRESLIST Resources. Translated ) { PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; for (i=0; i<Wdf. Cm. Resource. List. Get. Count(Resources. Translated); i++) { desc = Wdf. Cm. Resource. List. Get. Descriptor(Resources. Translated, i); switch (desc->Type) { case Cm. Resource. Type. Port: break; case Cm. Resource. Type. Memory: break; } } }

© 2005 Microsoft Corporation. All rights reserved. This presentation is for informational purposes only.

© 2005 Microsoft Corporation. All rights reserved. This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.