<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>A Hole In My Head : Design Patterns</title><link>http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx</link><description>Tags: Design Patterns</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>WDFREQUESTs are for sharing in KMDF v1.9</title><link>http://blogs.msdn.com/doronh/archive/2009/03/05/wdfrequests-are-for-sharing-in-kmdf-v1-9.aspx</link><pubDate>Fri, 06 Mar 2009 00:48:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9460771</guid><dc:creator>doronh</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/doronh/comments/9460771.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=9460771</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=9460771</wfw:comment><description>&lt;p&gt;In my last &lt;a href="http://blogs.msdn.com/doronh/archive/2009/03/04/wdfrequests-are-not-for-sharing.aspx" target="_blank"&gt;post&lt;/a&gt; I described why a WDFREQUEST is unique to a particular WDFDEVICE.&amp;#160; There is one particular programming pattern where this is not the behavior you want.&amp;#160; This pattern is when you have each PDO accepting IO requests which it then forwards on to the parent WDFDEVICE for processing. One great in box example of this is usbhub.sys.&amp;#160; Each usbhub PDO receives URBs which are then forwarded to the parent FDO and the FDO is where all IO processing occurs.&amp;#160; &lt;/p&gt;  &lt;p&gt;If you want to apply this pattern to a KMDF driver written to a v1.7 or earlier and take advantage of WDFQUEUEs you had to send the requests from the PDO to the FDO with WdfRequestSend so that they were represented to the FDO. The easiest way to do this is to create a WDFIOTARGET for the FDO itself and then have each PDO send IO to that WDFIOTARGET as shown in the following 3 code snippets. &lt;/p&gt;  &lt;h3&gt;EvtDriverDeviceAdd for the FDO&lt;/h3&gt;  &lt;pre&gt;NTSTATUS EvtDriverDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit) 
{
   WDFDEVICE device;

   WDF_OBJECT_ATTRIBUTES woa;
   WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&amp;amp;woa, FDO_EXTENSION);

   // ...initialize the DeviceInit...
   status = WdfDeviceCreate(&amp;amp;DeviceInit, &amp;amp;woa, &amp;amp;device);

   if (!NT_SUCCESS(status)) {
      return status;
   }

   PFDO_EXTENSION pFdoExt = GetFdoExt(device);
   status = WdfIoTargetCreate(device, WDF_NO_OBJECT_ATTRIBUTES, &amp;amp;pFdoExt-&amp;gt;SelfTarget);
   if (!NT_SUCCESS(status)) {
      return status;
   }

   // open the WDFIOTARGET to point our own PDEVICE_OBJECT
   WDF_IO_TARGET_OPEN_PARAMS openParams;
   WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(openParams, WdfDeviceWdmGetDeviceObject(device));

   status = WdfIoTargetOpen(pFdoExt-&amp;gt;SelfTarget, &amp;amp;openParams);
   if (!NT_SUCCESS(status)) {
      return status;
   }
   ...
   return status;
}&lt;/pre&gt;

&lt;h3&gt;EvtChildListCreateDevice for the PDO&lt;/h3&gt;

&lt;pre&gt;NTSTATUS EvtChildListCreateDevice(
    WDFCHILDLIST ChildList, 
    PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription,
    PWDFDEVICE_INIT ChildInit
    )
{
   WDFDEVICE pdo;
   NTSTATUS status;

   WDF_OBJECT_ATTRIBUTES woa;
   WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&amp;amp;woa, PDO_EXTENSION);

   status = WdfDeviceCreate(&amp;amp;ChildInit, &amp;amp;woa, &amp;amp;device);
   if (!NT_SUCCESS(status)) {
      return status;
   }

   PPDO_EXTENSION pPdoExt = GetPdoExt(device);
   PFDO_EXTENSION pFdoExt = GetFdoExt(WdfPdoGetParent(device));

   pPdoExt-&amp;gt;ParentTarget = pFdoExt-&amp;gt;SelfTarget;
   ...
   return status;
}&lt;/pre&gt;

&lt;h3&gt;EvtIoDefault for the PDO&lt;/h3&gt;

&lt;pre&gt;typedef
VOID EvtIoDefault(WDFQUEUE Queue, WDFREQUEST Request)&lt;/pre&gt;

&lt;pre&gt;{
    // ...  extract Request type ...
    if (&lt;i&gt;RequestShouldBeSentToParent&lt;/i&gt;()) {
       WdfRequestFormatRequestUsingCurrentType(Request);
       WdfRequestSend(Request, GetPdoExt(WdfIoQueueGetDevice(Queue))-&amp;gt;ParentTarget);
    }
}&lt;/pre&gt;

&lt;p&gt;As you can see, this is a bit cumbersome!&amp;#160; While it works, it is not ideal.&amp;#160; The KMDF team addressed this issue in v1.9 by adding 2 new DDIs that must be used together&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd434715.aspx" target="_blank"&gt;WdfPdoInitAllowForwardingRequestToParent&lt;/a&gt; which tells KMDF that you will be forwarding IO from a PDO to the parent FDO.&amp;#160; Internally this sets up some bookkeeping and, more importantly, sets the PDO’s PDEVICE_OBJECT’s StackSize to the FDO’s PDEVICE_OBJECT StackSize+1 so that there will be enough stack locations in the underlying PIRP for both the parent and child stacks &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd434849.aspx" target="_blank"&gt;WdfRequestForwardToParentDeviceIoQueue&lt;/a&gt; which removes the need for the custom WDFIOTARGET and WdfRequestSend and directly presents the PDO’s WDFREQUEST to the FDO’s WDFQUEUE &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s now rewrite the 3 code snippets to make use of these new DDIs, new code in &lt;font color="#ff0000"&gt;red&lt;/font&gt;&lt;/p&gt;

&lt;h3&gt;NEW EvtDriverDeviceAdd for the FDO&lt;/h3&gt;

&lt;pre&gt;NTSTATUS EvtDriverDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit) 
{
   WDFDEVICE device;

   WDF_OBJECT_ATTRIBUTES woa;
   WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&amp;amp;woa, FDO_EXTENSION);

   // ...initialize the DeviceInit...
   status = WdfDeviceCreate(&amp;amp;DeviceInit, &amp;amp;woa, &amp;amp;device);

   if (!NT_SUCCESS(status)) {
      return status;
   }

   PFDO_EXTENSION pFdoExt = GetFdoExt(device);
&lt;strike&gt;
   status = WdfIoTargetCreate(device, WDF_NO_OBJECT_ATTRIBUTES, &amp;amp;pFdoExt-&amp;gt;SelfTarget);
   if (!NT_SUCCESS(status)) {
      return status;
   }

   // open the WDFIOTARGET to point our own PDEVICE_OBJECT
   WDF_IO_TARGET_OPEN_PARAMS openParams;
   WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(openParams, WdfDeviceWdmGetDeviceObject(device));

   status = WdfIoTargetOpen(pFdoExt-&amp;gt;SelfTarget, &amp;amp;openParams);
   if (!NT_SUCCESS(status)) {
      return status;
   }
&lt;/strike&gt;

&lt;font color="#ff0000"&gt;
   // initialize a WDF_IO_QUEUE_CONFIG to your needs
   status = WdfIoQueueCreate(device, ..., &amp;amp;pFdoExt-&amp;gt;&amp;gt;ChildProcessingQueue);
   if (!NT_SUCCESS(status)) {
      return status;
   }
&lt;/font&gt;
   ...
   return status;
}&lt;/pre&gt;

&lt;h3&gt;NEW EvtChildListCreateDevice for the PDO&lt;/h3&gt;

&lt;pre&gt;NTSTATUS EvtChildListCreateDevice(
    WDFCHILDLIST ChildList, 
    PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription,
    PWDFDEVICE_INIT ChildInit
    )
{
   WDFDEVICE pdo;
   NTSTATUS status;

   WDF_OBJECT_ATTRIBUTES woa;
   WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&amp;amp;woa, PDO_EXTENSION);

&lt;font color="#ff0000"&gt;
   WdfPdoInitAllowForwardingRequestToParent(ChildInit);
&lt;/font&gt;   

   status = WdfDeviceCreate(&amp;amp;ChildInit, &amp;amp;woa, &amp;amp;device);
   if (!NT_SUCCESS(status)) {
      return status;
   }

&lt;strike&gt;   PPDO_EXTENSION pPdoExt = GetPdoExt(device);
   PFDO_EXTENSION pFdoExt = GetFdoExt(WdfPdoGetParent(device));

   pPdoExt-&amp;gt;ParentTarget = pFdoExt-&amp;gt;SelfTarget;&lt;/strike&gt;
   ...
   return status;
}&lt;/pre&gt;

&lt;h3&gt;NEW EvtIoDefault for the PDO&lt;/h3&gt;

&lt;pre&gt;VOID EvtIoDefault(WDFQUEUE Queue, WDFREQUEST Request)&lt;/pre&gt;

&lt;pre&gt;{
    // ...  extract Request type ...
    if (&lt;i&gt;RequestShouldBeSentToParent&lt;/i&gt;()) {
&lt;strike&gt;
       WdfRequestFormatRequestUsingCurrentType(Request);
       WdfRequestSend(Request, GetPdoExt(WdfIoQueueGetDevice(Queue))-&amp;gt;ParentTarget);
&lt;/strike&gt;
&lt;font color="#ff0000"&gt;
       WDF_REQUEST_FORWARD_OPTIONS options;
       WDF_REQUEST_FORWARD_OPTIONS_INIT(&amp;amp;options);
       options.Flags = WDF_REQUEST_FORWARD_OPTIONS_FLAGS;&lt;/font&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;font color="#ff0000"&gt;
       status = WdfRequestForwardToParentDeviceIoQueue(
           Request, 
           GetFdoExt(WdfPdoGetParent(WdfIoQueueGetDevice(Queue)))-&amp;gt;ChildProcessingQueue,
           &amp;amp;options);
&lt;/font&gt;
    }
}&lt;/pre&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9460771" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx">Design Patterns</category></item><item><title>Using KeAcquireSpinLockAtDpcLevel is only a perf gain if you know you are DISPATCH_LEVEL</title><link>http://blogs.msdn.com/doronh/archive/2008/03/28/using-keacquirespinlockatdpclevel-is-only-a-perf-gain-if-you-know-you-are-dispatch-level.aspx</link><pubDate>Sat, 29 Mar 2008 01:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8342502</guid><dc:creator>doronh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/doronh/comments/8342502.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=8342502</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=8342502</wfw:comment><description>&lt;P&gt;Well, that is certainly a long title ;). &lt;/P&gt;
&lt;P&gt;First, let us look at an approximate implementation of &lt;A href="http://msdn2.microsoft.com/en-us/library/ms801656.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms801656.aspx"&gt;KeAcquireSpinLock&lt;/A&gt; and &lt;A href="http://msdn2.microsoft.com/en-us/library/ms801898.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms801898.aspx"&gt;KeRaiseIrql&lt;/A&gt; (and yes I know that KeRaiseIrql is really a #define to KfRaiseIrql, but it is the same thing that happens in the end…) &lt;/P&gt;&lt;PRE&gt;KIRQL KeAcquireSpinLock(PKSPIN_LOCK SpinLock, PKIRQL PreviousIrql)
{
    KeRaiseIrql(DISPATCH_LEVEL, PreviousIrql);
    &lt;EM&gt;[spin on the lock until it has been acquired]&lt;/EM&gt;
}

VOID KeRaiseIrql(KIRQL NewIrql, PKIRQL, PKIRQL OldIrql)
{
    OldIrql = KeGetCurrentIrql();
&lt;EM&gt;    [raise IRQL to NewIrql]&lt;/EM&gt;
}
&lt;/PRE&gt;
&lt;P&gt;What I want to emphasize is that KeAcquireSpinLock will retrieve the current IRQL (to know what to restore the IRQL to when the lock is released) as a part of acquiring the spin lock. Retrieving the current irql is a relatively expensive operation. Enter &lt;A href="http://msdn2.microsoft.com/en-us/library/ms801669.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms801669.aspx"&gt;KeAcquireSpinLockAtDpcLevel&lt;/A&gt;. KeAcquireSpinLockAtDpcLevel does away with the IRQL change and just implements &lt;EM&gt;[spin on the lock until it has been acquired]&lt;/EM&gt;, but it does this with a large caveat…you must be running at DISPATCH_LEVEL (in reality it requires IRQL &amp;gt;= DISPATCH_LEVEL, but that is another discussion for another day) . It requires DISPATCH_LEVEL or higher so that you do not deadlock. Another caveat to effectively use KeAcquireSpinLockAtLevel you must know 100% that you are at DISPATCH_LEVEL. Naively, one could think that the following code optimizes for both cases &lt;/P&gt;&lt;PRE&gt;if (KeGetCurrentIrql() &amp;lt; DISPATCH_LEVEL) {
    KeAcquireSpinLock(&amp;amp;lock, &amp;amp;oldIrql);
}
else {
    KeAcquireSpinLockAtDpcLevel(&amp;amp;lock);
}
&lt;/PRE&gt;
&lt;P&gt;But the problem here is that in the case of the current IRQL &amp;lt; DISPATCH_LEVEL, the current IRQL is being retrieved twice (once in your code, once in KeAcquireSpinLock), so this relatively expensive operation is being performed twice when it should be performed only once. What all of this boils down to is that you must know with 100% certainty that the current IRQL is DISPATCH_LEVEL before you can use KeAcquireSpinLockAtDpcLevel effectively. Here are a couple of contexts here you can know for certain that the IRQL is DISPATCH_LEVEL. &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;In a DPC (for ISR, for a timer, your own) &lt;/LI&gt;
&lt;LI&gt;After you have acquired a spin lock. In the case where you have nested locked being acquired (first A, then B), after you have called KeAcquireSpinLock(&amp;amp;A) you can then call KeAcquireSpinLockAtDpcLevel(&amp;amp;B) &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Notice that a completion routine is not guaranteed to be called at IRQL == DISPATCH_LEVEL! While you may see that it is called at dispatch, it is not something that you can rely on 100% of the time. For instance, the lower driver could complete the IRP at passive level in an error condition.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8342502" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx">Design Patterns</category></item><item><title>Returning failure from DriverEntry</title><link>http://blogs.msdn.com/doronh/archive/2008/03/17/returning-failure-from-driverentry.aspx</link><pubDate>Tue, 18 Mar 2008 02:56:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8298729</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/8298729.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=8298729</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=8298729</wfw:comment><description>&lt;P&gt;One thing that is easily overlooked about &lt;A href="http://msdn2.microsoft.com/en-us/library/ms794742.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms794742.aspx"&gt;implementing&lt;/A&gt; &lt;A href="http://msdn2.microsoft.com/en-us/library/ms795702.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms795702.aspx"&gt;DriverEntry&lt;/A&gt; is that upon return !NT_SUCCESS, DriverUnload is not called.&amp;nbsp; I mentioned this anecdotally in a previous &lt;A href="http://blogs.msdn.com/doronh/archive/2006/10/23/hindsight-is-20-20-evtdriverunload-should-have-not-been-in-kmdf.aspx" target=_blank mce_href="http://blogs.msdn.com/doronh/archive/2006/10/23/hindsight-is-20-20-evtdriverunload-should-have-not-been-in-kmdf.aspx"&gt;post&lt;/A&gt;, but it is worth expanding on.&amp;nbsp; I was bit by this oversight when I was working on the Bluetooth stack.&amp;nbsp; Driver verifier&amp;nbsp; correctly identified that my driver had leaked pool.&amp;nbsp; The code looked something like this&lt;/P&gt;&lt;PRE&gt;// Globals
UNICODE_STRING gRegistryPath = { 0 };

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;

    DriverObject-&amp;gt;DriverUnload = DriverUnload;

    gRegistryPath.Length = RegistryPath-&amp;gt;Length;
    gRegistryPath.MaximumLength = RegistryPath-&amp;gt;MaximumLength;
    gRegistryPath.Buffer = (PWCHAR) ExAllocatePoolWithTag(PagedPool, gRegistryPath.MaximumLength, [tag]);
    if (gRegistryPath.Buffer == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }
    RtlCopyMemory(gRegistryPath.Buffer, RegistryPath-&amp;gt;Buffer, gRegistryPath.Length);

    status = RegisterWithPortDriver(DriverObject, ...);
    if (!NT_SUCCESS(status)) { return status; } &amp;lt;== leak right here!

    // ... other init ...

    return status;
}

void DriverUnload(PDRIVER_OBJECT DriverObject)
{
    ExFreePool(gRegistryPath.Buffer);
    RtlZeroMemory(&amp;amp;gRegistryPath, sizeof(gRegistryPath));
}&lt;/PRE&gt;
&lt;P&gt;While many WDM drivers do very little outside of initializing the dispatch table and other fields in their DriverObject, a miniport driver or a KMDF driver must register with their port driver (like &lt;A href="http://msdn2.microsoft.com/en-us/library/ms805428.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms805428.aspx"&gt;ScsiPortInitialize&lt;/A&gt;) or framework (&lt;A href="http://msdn2.microsoft.com/en-us/library/aa491318.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa491318.aspx"&gt;WdfDriverCreate&lt;/A&gt;) and this registration can introduce failure in DriverEntry (just like in my code sample above).&amp;nbsp; What to do?&amp;nbsp; &lt;/P&gt;
&lt;P&gt;In a WDM driver you have to be very careful and manage this manually.&amp;nbsp; Either you have a common error exit path out of DriverEntry which performs the cleanup (or manually calls your DriverUnload routine) or cleanup on each possible point of error.&amp;nbsp; This pattern is very easy to get wrong and is not very maintainable, it is quite easy to add a new allocation and forget to cleanup it up later.&lt;/P&gt;
&lt;P&gt;In a KMDF driver things are a bit easier to manage if you follow a particular pattern.&amp;nbsp; While &lt;A href="http://msdn2.microsoft.com/en-us/library/aa491324.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa491324.aspx"&gt;EvtDriverUnload&lt;/A&gt; has the same problems as the WDM DriverUnload, the EvtObjectCleanup routine registered on the WDFDRIVER is called in both scenarios.&amp;nbsp; To re-emphasize, the EvtObjectCleanup registered on WDFDRIVER will be called when either DriverEntry returns !NT_SUCCESS or if your driver is gracefully unloaded later.&amp;nbsp; This means that if you put all of your cleanup in the cleanup routine your DriverEntry implemention becomes much simpler.&amp;nbsp; The one caveat is that the call to WdfDriverCreate must come before any allocations in your driver or state chaning APIs.&amp;nbsp; &lt;A href="http://msdn2.microsoft.com/en-us/library/ms793144.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms793144.aspx"&gt;WPP_INIT_TRACING&lt;/A&gt;&amp;nbsp;is one such state changing API where you must undo its effects by calling &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/ms793159.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms793159.aspx"&gt;WPP_CLEANUP&lt;/A&gt;.&amp;nbsp; Quite a few WDK samples show this pattern (although suprisingly to me, not all!), let us look at the nonpnp sample (%wdk%\src\kmdf\nonpnp\sys\nonpnp.c) &lt;/P&gt;&lt;PRE&gt;NTSTATUS
DriverEntry(
    IN OUT PDRIVER_OBJECT   DriverObject,
    IN PUNICODE_STRING      RegistryPath
    )
{
    NTSTATUS                       status;
    WDF_DRIVER_CONFIG              config;
    WDFDRIVER                      hDriver;
    PWDFDEVICE_INIT                pInit = NULL;
    WDF_OBJECT_ATTRIBUTES          attributes;

    WDF_DRIVER_CONFIG_INIT(&amp;amp;config, WDF_NO_EVENT_CALLBACK);

    // Tell the framework that this is non-pnp driver so that it doesn't set the default AddDevice routine.
    config.DriverInitFlags |= WdfDriverInitNonPnpDriver;

    // NonPnp driver must explicitly register an unload routine for the driver to be unloaded.
    config.EvtDriverUnload = NonPnpEvtDriverUnload;

&lt;FONT color=#ff0000&gt;    &lt;/FONT&gt;&lt;B&gt;&lt;FONT color=#ff0000&gt;// Register a cleanup callback so that we can call WPP_CLEANUP when
    // the framework driver object is deleted during driver unload.&lt;/FONT&gt;&lt;/B&gt;
    WDF_OBJECT_ATTRIBUTES_INIT(&amp;amp;attributes);
    attributes.EvtCleanupCallback = NonPnpEvtDriverContextCleanup;

    status = WdfDriverCreate(DriverObject,
                            RegistryPath,
                            &amp;amp;attributes,
                            &amp;amp;config,
                            &amp;amp;hDriver);
    if (!NT_SUCCESS(status)) {
        KdPrint (("NonPnp: WdfDriverCreate failed with status 0x%x\n", status));
        return status;
    }

&lt;FONT color=#ff0000&gt;    &lt;/FONT&gt;&lt;B&gt;&lt;FONT color=#ff0000&gt;// Since we are calling WPP_CLEANUP in the DriverContextCleanup
    // callback we should initialize WPP Tracing after WDFDRIVER
    // object is created to ensure that we cleanup WPP properly
    // if we return failure status from DriverEntry. This
    // eliminates the need to call WPP_CLEANUP in every path
    // of DriverEntry.&lt;/FONT&gt;&lt;/B&gt;
    WPP_INIT_TRACING( DriverObject, RegistryPath );

    ...

    return status;
}

VOID NonPnpEvtDriverContextCleanup(WDFDRIVER Driver)
{
    WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver));
}&lt;/PRE&gt;
&lt;P&gt;The red comments show what is going on.&amp;nbsp; Hopefully the code is self explanatory.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Incidentally, another pattern you can use for global memory allocations is to allocate the memory with &lt;A href="http://msdn2.microsoft.com/en-us/library/aa491566.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa491566.aspx"&gt;WdfMemoryCreate&lt;/A&gt; without specifying a parent object.&amp;nbsp; The WDFDRIVER will be the parent object by default and since all child objects are destroyed when the parent is destroyed, all of your allocations will be destroyed after EvtDriverUnload has been called when the WDFDRIVER is destroyed in the unload path.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8298729" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx">Design Patterns</category></item><item><title>How to share HW resources with another driver not in the same PnP hierarchy</title><link>http://blogs.msdn.com/doronh/archive/2007/10/24/how-to-share-hw-resources-with-another-driver-not-in-the-same-pnp-hierarchy.aspx</link><pubDate>Thu, 25 Oct 2007 01:56:23 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5657859</guid><dc:creator>doronh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/doronh/comments/5657859.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=5657859</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=5657859</wfw:comment><description>&lt;p&gt;First, I have to say that I don't agree with this design pattern &lt;em&gt;at all&lt;/em&gt;.&amp;nbsp; I think it leads to too many problems and complications that are not worth the pain.&amp;nbsp; The only reason I am writing this entry is that I have seen so many people get this wrong or not account for some details and I want to make sure that if such a driver is installed, the stability of the system is not compromised.&amp;nbsp; The scenario I am covering is not the case where you are enumerating child devices and want to share resources assigned to the parent amongst the children.&amp;nbsp; Rather, this is sharing HW resources assigned to your device (device A) with another device (device B).&amp;nbsp; Device B can be a legacy NT4 style device or another PnP device stack, it doesn't matter.&lt;/p&gt; &lt;p&gt;There are&amp;nbsp;3 aspects to the issue that you must solve:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Handing off the resources to device B.&amp;nbsp; This means that device B will open a handle against device A and send an internal IOCTL (e.g. IOCTL_INTERNAL_GET_RESOURCES) which device A completes with the appropriate values.&amp;nbsp; If the number of resources is fixed, this is easy.&amp;nbsp; If the number of resources varies, this can get complicated.  &lt;li&gt;Coordinating access to the resources between device A and device B.&amp;nbsp; If both drivers want to touch the resources at the same time, you now have to synchronize between 2 components and that can get very complicated, especially if there are callbacks involved.  &lt;li&gt;Only touching the resources when the device has power.&amp;nbsp; This is easy for device A to do since it is the power policy owner for the device and sees pnp state changing and device power irps.&amp;nbsp; This is not easy for device B to do though.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Aspects number 1 and 2 I will leave for you to solve.&amp;nbsp; Number 3 is where things get interesting.&amp;nbsp; There are scenarios where the device can lose power:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;font color="#80ff00"&gt;PnP graceful remove (query remove, remove) &lt;/font&gt; &lt;li&gt;&lt;font color="#80ff00"&gt;PnP surprise removal&lt;/font&gt;  &lt;li&gt;PnP stop  &lt;li&gt;System power state change (e.g. a standby or hibernate)&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&amp;nbsp;The first 2 scenarios in &lt;font color="#80ff00"&gt;green &lt;/font&gt;are easily solved.&amp;nbsp; Device B registers for PnP notifications on the file handle that it opens and it will be told when a PnP remove or surprise removal occurs.&amp;nbsp; If you are using KMDF, the WDFIOTARGET automatically does this for you.&amp;nbsp; But there is a catch to the surprise removal notification...it is sent to device B after device A has already processed the PnP IRP.&amp;nbsp; This means that there is a window where device B thinks it has valid resources, but in reality it does not.&amp;nbsp; File handle notifications do not solve the last 2 scenarios though and the surprise removal case does not work well, so it would be nice if there was one solution for all 4 scenarios.&lt;/p&gt; &lt;p&gt;The solution is that device B must register 2 callbacks with device A, a power up and power down callback (they can be condensed to one callback with an additional passed in parameter indicating power state if you want).&amp;nbsp; These callbacks should be set at the same time that the resources are acquired so that there is no window where the resources have been acquired, the device loses power and the callback has not yet been set notifying device B of the power state change.&amp;nbsp; These callbacks can be passed from device B to device in any number of ways.&amp;nbsp; Two traditional ways are&lt;/p&gt; &lt;ul&gt; &lt;li&gt;To pass the callbacks in a buffer in an internal IOCTL (you can overload IOCTL_INTERNAL_GET_RESOURCES if you want)  &lt;li&gt;To send a IRP_MN_QUERY_INTERFACE with these callbacks as input values in the INTERFACE based structure as I describe in &lt;a href="http://blogs.msdn.com/doronh/archive/2007/03/06/interfaces-can-contain-both-input-and-output-parameters-and-not-just-function-pointers.aspx" target="_blank"&gt;this post&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Once the callbacks have been set, device A must call them at the right time.&amp;nbsp; In a KMDF driver, it is a very simple implementation.&amp;nbsp; You call device B's power up callback in &lt;a href="http://msdn2.microsoft.com/en-us/library/aa490952.aspx" target="_blank"&gt;EvtDeviceSelfManagedIoRestart&lt;/a&gt;&amp;nbsp;and device B's power down routine in &lt;a href="http://msdn2.microsoft.com/en-us/library/aa490940.aspx" target="_blank"&gt;EvtDeviceSelfManagedIoSuspend&lt;/a&gt;.&amp;nbsp; This covers all cases because KMDF treats PnP state changes as implicit power changes, powering down the device and using the same callbacks for all cases.&amp;nbsp; This also covers the surprise removal window because device B is now notified at the beginning of device A's power down instead of after it.&amp;nbsp; One final thing to consider is what device B thinks the initial power state of device A is in.&amp;nbsp; Ideally, device B should assume device A is in low power and should not touch the retrieved resources until its power up callback has been invoked.&amp;nbsp; This would mean that the initial call to device B's power up call might occur outside of EvtDeviceSelfManagedIoRestart, perhaps immediately after completing the IOCTL_INTERNAL_GET_RESOURCES request.&lt;/p&gt; &lt;p&gt;If you are writing a WDM driver, well, I will leave that implementation up to you ;).&amp;nbsp; &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5657859" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/doronh/archive/tags/WDM/default.aspx">WDM</category><category domain="http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx">Design Patterns</category></item><item><title>Supporting query interface in KMDF</title><link>http://blogs.msdn.com/doronh/archive/2007/03/12/supporting-query-interface-in-kmdf.aspx</link><pubDate>Mon, 12 Mar 2007 21:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1840938</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/1840938.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=1840938</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=1840938</wfw:comment><description>&lt;P&gt;In my last &lt;A href="http://blogs.msdn.com/doronh/archive/2007/03/06/interfaces-can-contain-both-input-and-output-parameters-and-not-just-function-pointers.aspx" target=_blank mce_href="http://blogs.msdn.com/doronh/archive/2007/03/06/interfaces-can-contain-both-input-and-output-parameters-and-not-just-function-pointers.aspx"&gt;post&lt;/A&gt; I talked about bidirectional interfaces which can have both input and output parameters. KMDF supports both unidirectional and bidirectional interfaces. As is the case with many KMDF APIs and behaviors, we allow you to implement the easy pattern with little to no work and let you opt in to more complicated functionality as needed. Query interface support follows this philosophy. &lt;/P&gt;
&lt;P&gt;If you want to support a unidirectional interface which only contains output parameters, you have very little code to write. First, declare and initialize the interface as you would want it to be returned to the requestor.&amp;nbsp; Second, declare and initialize a WDF_QUERY_INTERFACE_CONFIG structure with your interface.&amp;nbsp; Finally, you call &lt;A href="http://msdn2.microsoft.com/en-us/library/aa490707.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa490707.aspx"&gt;WdfDeviceAddQueryInterface&lt;/A&gt;(). Here is a snippet from the WDK KMDF toaster bus sample which demonstrates how easy this is &lt;/P&gt;&lt;PRE&gt;WDF_QUERY_INTERFACE_CONFIG  qiConfig;
TOASTER_INTERFACE_STANDARD  ToasterInterface;

//
// Create a copy of the interface that the framework will use when
// completing the query interface request.
//
RtlZeroMemory(&amp;amp;ToasterInterface, sizeof(ToasterInterface));

ToasterInterface.InterfaceHeader.Size = sizeof(ToasterInterface);
ToasterInterface.InterfaceHeader.Version = 1;
ToasterInterface.InterfaceHeader.Context = (PVOID) hChild;

//
// Let the framework handle reference counting.
//
ToasterInterface.InterfaceHeader.InterfaceReference =
    WdfDeviceInterfaceReferenceNoOp;
ToasterInterface.InterfaceHeader.InterfaceDereference =
    WdfDeviceInterfaceDereferenceNoOp;

ToasterInterface.GetCrispinessLevel  = Bus_GetCrispinessLevel;
ToasterInterface.SetCrispinessLevel  = Bus_SetCrispinessLevel;
ToasterInterface.IsSafetyLockEnabled = Bus_IsSafetyLockEnabled;

WDF_QUERY_INTERFACE_CONFIG_INIT(&amp;amp;qiConfig,
                                (PINTERFACE) &amp;amp;ToasterInterface,
                                &amp;amp;GUID_TOASTER_INTERFACE_STANDARD,
                                NULL);

status = WdfDeviceAddQueryInterface(hChild, &amp;amp;qiConfig);
if (!NT_SUCCESS(status)) {
    return status;
}
&lt;/PRE&gt;
&lt;P&gt;But what about other scenarios? There are 3 other patterns that apply to handling a query interface request: &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;You want to selectively succeed, fail, or pass down the query interface request based on state or previous requests &lt;/LI&gt;
&lt;LI&gt;You want to capture input parameters in the request and optionally set output parameters &lt;/LI&gt;
&lt;LI&gt;You want forward the request down to the parent stack (PDO only) &lt;/LI&gt;&lt;/OL&gt;
&lt;H3&gt;Selectively succeed, fail, or pass down the request &lt;/H3&gt;
&lt;P&gt;Typically a query interface request is processed regardless of the previous queries or device state, but not always. For instance, let's say you want to only handle out the interface to one requestor (it would be available once it is dereferenced). Another example might be that you want to determine the status of the query interface request based on the capabilities exposed lower in the device stack. Finally, to process the query interface, you might be required to allocate memory (which could lead to failure if you cannot allocate the required buffer). To allow your driver to determine the status, check state, perform your custom action, etc. you specify a &lt;A href="http://msdn2.microsoft.com/en-us/library/aa490711.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa490711.aspx"&gt;&lt;SPAN style="FONT-FAMILY: Courier New"&gt;EvtDeviceProcessQueryInterfaceRequest&lt;/SPAN&gt;&lt;/A&gt; function pointer in your &lt;SPAN style="FONT-FAMILY: Courier New"&gt;WDF_QUERY_INTERFACE_CONFIG&lt;/SPAN&gt; structure after calling &lt;SPAN style="FONT-FAMILY: Courier New"&gt;WDF_QUERY_INTERFACE_CONFIG_INIT()&lt;/SPAN&gt;. To succeed the query interface request, return a value which is NT_SUCCESS(), likewise to fail a request, return a value which is !NT_SUCCESS(). To instruct the framework to pass down the request to the lower stack, you return a special value, STATUS_NOT_SUPPORTED. &lt;/P&gt;
&lt;H3&gt;Capturing input parameters in the request &lt;/H3&gt;
&lt;P&gt;There is a field in &lt;SPAN style="FONT-FAMILY: Courier New"&gt;WDF_QUERY_INTERFACE_CONFIG&lt;/SPAN&gt; which controls how the framework treats the interface buffer itself. If &lt;A href="http://msdn2.microsoft.com/en-us/library/aa490706.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa490706.aspx"&gt;&lt;SPAN style="FONT-FAMILY: Courier New"&gt;ImportInterface&lt;/SPAN&gt;&lt;/A&gt; is FALSE (the default value), the interface buffer is treated as a pure output buffer and the framework will copy over the interface to return directly into the requestor's buffer (and subsequently overwriting any values the requestor initialized the buffer with). If ImportInterface is TRUE, the framework does not touch the requestor's buffer. This allows you to inspect the requestor's buffer first and copy data from it. By setting ImportInterface to TRUE, there are two direct side effects that you must deal with. First, you must specify a EvtDeviceProcessQueryInterfaceRequest function when adding the interface. Second, and most importantly, &lt;STRONG&gt;&lt;EM&gt;your driver must now copy all output values&lt;/EM&gt;&lt;/STRONG&gt; into the requestor's buffer because the framework no longer does this for you! &lt;/P&gt;
&lt;H3&gt;Forwarding the request to the parent's stack &lt;/H3&gt;
&lt;P&gt;There are some query interface requests that must be forwarded from the PDO down to the parent's stack (and most likely to be completed by the parent's own PDO). For example, look at usbccgp (the USB generic parent driver). This driver does not support every single USBHUB interface, yet it must maintain compatibility with the hub's supported interfaces. To do this, it forwards all unhandled requests down from the PDO it created down the parent's stack. The framework can automatically provide this functionality to your driver if you set &lt;SPAN style="FONT-FAMILY: Courier New"&gt;SendQueryToParentStack&lt;/SPAN&gt; to TRUE.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1840938" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx">Design Patterns</category></item><item><title>INTERFACEs can contain both input and output parameters…and not just function pointers</title><link>http://blogs.msdn.com/doronh/archive/2007/03/06/interfaces-can-contain-both-input-and-output-parameters-and-not-just-function-pointers.aspx</link><pubDate>Wed, 07 Mar 2007 09:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1825050</guid><dc:creator>doronh</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/doronh/comments/1825050.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=1825050</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=1825050</wfw:comment><description>&lt;P&gt;When you look at the documentation for an &lt;A href="http://msdn2.microsoft.com/en-us/library/aa491658.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa491658.aspx"&gt;INTERFACE&lt;/A&gt; and &lt;A href="http://msdn2.microsoft.com/en-us/library/ms806486.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms806486.aspx"&gt;IRP_MN_QUERY_INTERFACE&lt;/A&gt;, it mentions that the INTERFACE structure is the input provided to the interface provider (set the by the driver querying for the interface) and the remainder of the interface structure is considered output (set by the driver completing the query interface request). What it doesn't says is that the interface can contain more input parameters then just the INTERFACE related fields. Furthermore, the interface can contain additional datatypes other then function pointers. This can be a very powerful design pattern, the querying driver can provide the implementer of the interface its own callbacks and data in addition to acquiring functions and data from the interface implementer. &lt;/P&gt;
&lt;P&gt;First, let's take a previous &lt;A href="http://blogs.msdn.com/doronh/archive/2007/01/23/reenumerate-self-interface-standard-did-not-make-it-into-the-wdk-docs.aspx" target=_blank mce_href="http://blogs.msdn.com/doronh/archive/2007/01/23/reenumerate-self-interface-standard-did-not-make-it-into-the-wdk-docs.aspx"&gt;example&lt;/A&gt; of REENUMERATE_SELF_INTERFACE_STANDARD which is a classic example of input and output parameters in an interface. In this case the structure reflects what the documentation says. The querying driver fills in the INTERFACE related fields and the bus driver fills in the SurpriseRemoveAndReenumerateSelf field. &lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="FONT-FAMILY: Courier New"&gt;typedef struct _REENUMERATE_SELF_INTERFACE_STANDARD {&lt;BR&gt;    //&lt;BR&gt;    // generic interface header&lt;BR&gt;    //&lt;BR&gt;    USHORT Size; &lt;BR&gt;    USHORT Version; &lt;BR&gt;    PVOID Context; &lt;BR&gt;    PINTERFACE_REFERENCE InterfaceReference; &lt;BR&gt;    PINTERFACE_DEREFERENCE InterfaceDereference; &lt;BR&gt;    //&lt;BR&gt;    // Self-reenumeration interface&lt;BR&gt;    //&lt;BR&gt;    PREENUMERATE_SELF SurpriseRemoveAndReenumerateSelf; &lt;BR&gt;} REENUMERATE_SELF_INTERFACE_STANDARD, *PREENUMERATE_SELF_INTERFACE_STANDARD;
&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Next, let's look at an interface which has additional input parameters. I will try to put this into a real world context so that it is more concrete then creating fictional interfaces. Let's say that you have a piece of hardware that has multiple functions which share a common set of hardware resources (registers, interrupts, DMA, etc) between all of the functions. The shared hardware resources must be managed by an entity other then each function (which means that you cannot use mf.sys to split the functions apart). In this scenario, you would write a bus driver and enumerate a child PDO stack for every function on the device. But now you have a couple of design problems that you must solve: &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;How is the parent FDO going to notify a function that something asynchronous occurred (like an interrupt for a specific function)? &lt;/LI&gt;
&lt;LI&gt;How is each child going to know what hardware resources to use? &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;An interface which contains both input and output parameters can solve both problems. I will first present the data structures and types and then explain them in detail &lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="FONT-FAMILY: Courier New"&gt;typedef PVOID INTERRUPT_CONTEXT;&lt;BR&gt;typedef VOID (*PFN_MY_ACQUIRE_INTERRUPT_LOCK)(INTERRUPT_CONTEXT Context);&lt;BR&gt;typedef VOID (*PFN_MY_RELEASE_INTERRUPT_LOCK)(INTERRUPT_CONTEXT Context);

typedef BOOLEAN (*PFN_FUNCTION_ISR)(PVOID Context);
&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;SPAN style="FONT-FAMILY: Courier New"&gt;&lt;BR&gt;typedef struct _MY_RESOURCES_INTERFACE {&lt;BR&gt;    //&lt;BR&gt;    // generic interface header&lt;BR&gt;    //&lt;BR&gt;    USHORT Size; &lt;BR&gt;    USHORT Version; &lt;BR&gt;    PVOID Context; &lt;BR&gt;    PINTERFACE_REFERENCE InterfaceReference; &lt;BR&gt;    PINTERFACE_DEREFERENCE InterfaceDereference; &lt;BR&gt;&lt;BR&gt;    //&lt;BR&gt;    // Additional input parameters&lt;BR&gt;    //&lt;BR&gt;    // ISR routine for this function.  The FDO will call this routine when the ISR&lt;BR&gt;    // fires for this function.&lt;BR&gt;    //&lt;BR&gt;    PFN_FUNCTION_ISR IsrRoutine;&lt;BR&gt;    PVOID IsrRoutineContext;&lt;BR&gt;&lt;BR&gt;    //&lt;BR&gt;    // Output parameters&lt;BR&gt;    //&lt;BR&gt;    // The start and length of the assigned resources for this function.  These &lt;BR&gt;    // resources are exclusive to the function and are not shared&lt;BR&gt;    //&lt;BR&gt;    PUCHAR ResourcesStart;&lt;BR&gt;    ULONG ResourcesLength;&lt;BR&gt;&lt;BR&gt;    PFN_MY_ACQUIRE_INTERRUPT_LOCK AcquireInterruptLock;&lt;BR&gt;    PFN_MY_RELEASE_INTERRUPT_LOCK ReleaseInterruptLock;&lt;BR&gt;    INTERRUPT_CONTEXT InterruptContxt&lt;BR&gt;&lt;BR&gt;} MY_RESOURCES_INTERFACE, *P MY_RESOURCES_INTERFACE;
&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"&gt;&lt;BR&gt;&lt;/SPAN&gt;The "additional" input parameters answer the first question of how is the FDO going to notify the function's stack that an interrupt occurred. The FDO for the function provides the IsrRoutine and IsrRoutineContext values and the bus driver stores these values away in the bus driver FDO context. For instance, the function's FDO code to initialize the structure before sending it down the stack would look like this &lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;BOOLEAN FunctionIsr(PVOID Context)&lt;BR&gt;{&lt;BR&gt;    WDFDEVICE device = (WDFDEVICE) Context;&lt;BR&gt;    //...&lt;BR&gt;    return TRUE;&lt;BR&gt;}&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;CODE&gt;MY_RESOURCES_INTERFACE interface;&lt;BR&gt;PDEVICE_CONTEXT pDevContext = GetDevExt(Device);&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;CODE&gt;&lt;BR&gt;&lt;/CODE&gt;&lt;CODE&gt;RtlZeroMemory(&amp;amp;interface, sizeof(inteface));&lt;BR&gt;interface.Size = sizeof(interface);&lt;BR&gt;interface.Version = 1;&lt;BR&gt;&lt;BR&gt;interface.IsrRoutine = FunctionIsr;&lt;BR&gt;interface.IsrRoutineContext = Device;&lt;BR&gt;&lt;/PRE&gt;&lt;/CODE&gt;
&lt;P&gt;After the query interface request has been successfully sent down the stack synchronously, the function's FDO can retrieve the output parameters. &lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;pDevExt-&amp;gt;ResourcesStart = interface.ResourcesStart;&lt;BR&gt;pDevExt-&amp;gt;ResourcesLength = interface.ResourcesLength;&lt;BR&gt;&lt;BR&gt;pDevExt-&amp;gt;AcquireInterruptLock = interface.AcquireInterruptLock;&lt;BR&gt;pDevExt-&amp;gt;ReleaseInterruptLock = interface.ReleaseInterruptLock;&lt;BR&gt;pDevExt-&amp;gt;InterruptContext = interface.InterruptContext;&lt;BR&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The output parameters answer the second question of "how is the function going to know which resources to use? In this example, there is only one set of registers. You could easily add more fields or additional functions to provide a richer interface to retrieve a dynamic set of registers if needed. When the bus driver processes this query interface request in its PDO, it will store the input parameters IsrRoutine and IsrRoutineContext in its extension and assign values to all of the output parameters &lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;VOID ParentAcquireInterruptLock(INTERRUPT_CONTEXT Context) { WdfInterrupteAcquireLock((WDFINTERRUPT) Context); }&lt;BR&gt;VOID ParentReleaseInterruptLock(INTERRUPT_CONTEXT Context) { WdfInterrupteReleaseLock((WDFINTERRUPT) Context); }&lt;BR&gt;&lt;/CODE&gt;&lt;CODE&gt;&amp;nbsp;&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;CODE&gt;PPDO_EXTENSION pPdoExt = GetPdoExt(Device);&lt;BR&gt;PPARENT_EXTENSION pParentDevExt = GetParentExt(WdfPdoGetParent(Device));&lt;BR&gt;&lt;/CODE&gt;&lt;CODE&gt;&amp;nbsp;&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;CODE&gt;// store input parameters&lt;BR&gt;pParentDevExt-&amp;gt;Functions[pPdoExt-&amp;gt;FunctionIndex].IsrRoutine = pInterface-&amp;gt;IsrRoutine;&lt;BR&gt;pParentDevExt-&amp;gt;Functions[pPdoExt-&amp;gt;FunctionIndex].IsrRoutineContext = pInterface-&amp;gt;IsrRoutineContext;&lt;BR&gt;&lt;/CODE&gt;&lt;CODE&gt;&amp;nbsp;&lt;/CODE&gt;&lt;/PRE&gt;&lt;PRE&gt;&lt;CODE&gt;// set output parameters&lt;BR&gt;pInterface-&amp;gt;AcquireInterruptLock = ParentAcquireInterruptLock;&lt;BR&gt;pInterface-&amp;gt;ReleaseInterruptLock = ParentReleaseInterruptLock;&lt;BR&gt;pInterface-&amp;gt;InterruptContext = (INTERRUPT_CONTEXT) pParentDevExt-&amp;gt;Interrupt;&lt;BR&gt;&lt;BR&gt;pInterface -&amp;gt;ResourcesStart = pParentExt-&amp;gt;Functions[pPdoExt-&amp;gt;FunctionIndex].ResourcesStart;&lt;BR&gt;pInterface -&amp;gt;ResourcesLength = pParentExt-&amp;gt;Functions[pPdoExt-&amp;gt;FunctionIndex].ResourcesLength;&lt;BR&gt;&lt;/PRE&gt;&lt;/CODE&gt;So, hopefully this gives you a glimpse of what you can do with an interface between drivers in a device stack. It can be a very powerful design pattern that can solve some difficult problems. Could you have done this with a more private mechanism like an internal IOCTL? Yes, you could, but it would be more work and it is much easier to use the existing mechanism rather than invent your own.&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1825050" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WDM/default.aspx">WDM</category><category domain="http://blogs.msdn.com/doronh/archive/tags/Design+Patterns/default.aspx">Design Patterns</category></item></channel></rss>