Welcome to MSDN Blogs Sign in | Join | Help

My travels with WDF

The continuing story of a boy, his dog and their discovery of the world outside...of WDM.
And here you thought I had a cloaking device

Got a good one to share with the group;

Q: Can I make a kernel mode driver that opens a handle and talks to a UMDF based driver in another device stack?

A: Why yes you can!  Quite simply done provide you follow all the rules. This is a variant of the UMDF initiated cross stack communication we talked about a while ago, but KMDF, being a DF (driver framework) supports essentially the same IoTarget model that UMDF does.

Now Playing – Rush Far Cry

We’re gonna need a bigger stick!

So, some of you may recognize Eliyas’ name from WinHECs and various other driver dev presentations, but guess what he’s done now?!  He’s become a blogger.

Go on feel free to hound him about your USB driver problems. :)

We’ve got more bloggers than we can shake a stick at!

Welcome to the blog-o-sphere Neslihan.  She’s our resident WLK guru, so you guys and gals can go pester here with all your WDF logo questions. :)

I/O Queues and You

I got an interesting question via mail recently, “Do I really need to create a queue object in my UMDF driver?”  Well, this is another one of those, “only if” type questions.

For instance - Only if your driver is not handling any I/O from a top edge method which results in the I/O manager being involved in talking to the UMDF driver for those operations.  At that point you don’t need to create a queue object. 

Example -

The UMDF driver wants to send I/O to a KM driver in another stack based on some form of simple event being raised and consumed by the UMDF device.  Provided you have a handle open to that KM stack and have created the I/O target object (all shown here) you can simply create and format a request, and then send that request to the target.

Should you want to send requests asynchronously and need a completion callback, you can still do so with out requiring a queue.  The driver will have to implement a IRequestCallbackRequestCompletion::OnCompletion method.  And during the packing of the request to submit, invoke the request’s SetCompletionCallback prior to invoking the FormatRequestxxx method.

Once the lower driver has completed the request, the OnCompletion method will be invoked.  Voilà.

There’s one little caveat around UMDF completion routines that I talked about a while ago and I should bring it up here; you can only define one OnCompetion method per device object.

Cross stack communications

The subject of how to talk to another device stack has come up again, and since I only briefly touched on it a year ago, I thought it would be good provide some code snippets and a little more background on how to accomplish such a feat.  The gist of what we are trying to do here is load a UMDF based driver for one device, open a handle to a different device stack and submit I/O to that stack.  To do that in UMDF we need to establish a UMDF I/O target and the foundation of that I/O target object is a file handle.

So the basic building blocks are as follows;

    //
    // Add these to your base class
    //
    IWDFIoTarget m_ExternalTarget;
    HANDLE m_ExternalHandle;

You can add these to any of your existing classes, but it probably serves best to house these elements in your Device or Queue classes.  They are tied to the lifetime of the I/O you are sending to the external target, so where you house them is really down to your design and implementation.

Based on your needs and how you design your driver, you will need to determine when you proceed with the following sections.  For simplicity, I’ll establish the connection to the remote stack in the Device Initialization routine, but the same can be done at just about any other point of initialization or even during a later phase of driver operations.

    IWDFFileHandleTargetFactory * pFileHandleTargetFactory = NULL;

   // .......
   // abstracted device init code for brevity
   // ........

    if (SUCCEEDED (hr)) 
    {
        m_FxDevice = fxDevice;

        //
        // We can release the reference as the lifespan is tied to the 
        // framework object.
        //
        fxDevice->Release();
    }

    // Open the device and get the handle.

    m_ExternalHandle = CreateFile (
        DeviceStack,  // path device stack to open
        GENERIC_READ | GENERIC_WRITE, // these flags are driven more by the target stack.
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL,         
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED, // You must open the handle with this flag
        NULL);        



    if (INVALID_HANDLE_VALUE == m_ExternalHandle) 
    {
        DWORD err = GetLastError();

        TraceEvents(
            TRACE_LEVEL_ERROR, 
            TEST_TRACE_DEVICE, 
            "%!FUNC! Cannot open handle to device %!winerr!",
            err);

        hr = HRESULT_FROM_WIN32(err);
    }

    if (SUCCEEDED(hr)) 
    {
        hr = m_FxDevice->QueryInterface(IID_PPV_ARGS(&pFileHandleTargetFactory));

        if (FAILED(hr))
        {
            TraceEvents(
                TRACE_LEVEL_ERROR, 
                TEST_TRACE_DEVICE, 
                L"ERROR: Unable to obtain target factory for creating FileHandle based I/O target %!hresult!",
                hr);
        }
    }

    if (SUCCEEDED(hr)) 
    {
        hr = pFileHandleTargetFactory->CreateFileHandleTarget(m_ExternalHandle, &m_ExternalTarget);
    }

You’ll need to release the reference to the pFileHandleTargetFactory object, either by a SAFE_RELEASE macro, direct call to the Release(); method, or by using a CComPtr /CComQIPtr  class wrapper on the object on declaration.  You’ll also need to clean up the Windows file handle when it is no longer needed.  And IF the IWDFIoTarget object's lifetime scope is narrower than the device object's lifetime, you will need to call DeleteWdfObject method on m_ExternalTarget.

At this point, you have your remote target object to use in sending I/O to that secondary device stack.

What I’ll cover next is going to be some hefty theory on when you should and don’t need to use queue objects and how to send I/O to an external stack based on whether you have a queue or not.  Fun! ;)

The feline, it has escaped the fabric based containment pouch!

One of the things I’ve been wanting to do for a while is put Isochronous transfer support back in to the 1394 Hybrid sample.  Now that Windows 7 has shipped and we’re picking up projects we want to do during this period of product transitions, I felt the time was right to start this up.  All happened to dove tail nicely with the implementation of Direct I/O support which was added to UMDF 1.9 in the end, allowing me to essentially kill two birds with one stone.  What we’ll end up with is a demonstration for various methods of I/O flow through this hybrid driver stack as well as having another demonstration of Isochronous transfers for 1394 devices again.  Hooray us!

So, I’m happy to report that work has begun on said project, and as a result I’ll have some tidbits, details and follies to present to you along this path of coding fun in the coming weeks.

Now PlayingGeddy Lee My Favorite Headache

Standing by for Eagle

Two things are celebrating 40th anniversaries this year.  One is me (okay it’s not until October) and the more significant thing is Apollo 11 landing on the moon. :)

Like any of you really needed to be reminded. 

Still to this day, my favorite bit of trivia from Apollo 11 is that none of the Astronauts names appear on the mission patch.  And it was the only Apollo mission to have such a patch.

I didn’t have anything else of driver value for you today other than a Happy Anniversary Apollo 11.  I’ll be back later with some driver related stuff later.

 

Currently playing; “Live” restream of Apollo 11 mission. 

House cleaning

The fourth part of Abhishek’s online UMDF debugging tutorials is up now. :)

http://www.microsoft.com/whdc/devtools/debugging/umdftraining.mspx

Next up, those of you playing with Windows 7 may have noticed that the “Found New Hardware” wizard is gone!  This in itself is not that big a deal, but it does mean that some of the WDK sample installation instructions are no longer valid. 

Simple fix at the end of the day, the device will come up as an “Unknown Device” within Device Manager, choose “Update Driver” from the right click context menu for that device and then follow the directions to point it to the driver(s) you need!

That’s all for today, those of you in the U.S. enjoy your 4th of July weekend.  And just remember, light fuse then run away.

 

*Currently Playing - Dream Theater Light Fuse and Get Away

Intellisense, the Musical part 3

Like all good stories, sometimes the 2nd act is the hardest to follow.  In this case it was simply a matter of other things coming up rather than writers block. :)

What kicked me in the rump to get this next part up was a few more questions about driver writing, WDK integration into Visual Studio and Intellisense.  One of the very cool features of Visual Studio 2008 is the ability to make a project from existing code.

The end result can look something like this (warning, this is a 1920x1200 resolution PNG *g*)

teaser

I’ll walk you through this using the “a picture is worth a thousand words” mentality;

Part1

part2

Select “Next”

Then point it to the root of the WDK installation.  Pointing it to the root rather than right at the src folder will save you some intellsense headaches later on, sure you’ll get inclusion of all the WDK folders, but it’s actually not a bad thing in the end;

part3

 

 

Select “Next”

Then;

part4 

Select “Finish” from here.  We’re still not going to use Visual Studio to do any building for now, partly because I refuse to give up all command windows in my life and also because I’m still tinkering with all the settings required to use the WDK build environments under Visual Studio.

Now your Solution Explorer will probably look like a mess of files listed alphabetically.  Simply hover over the “Show All Files” button at the top and toggle it until you get an Explorer like layout of the samples sources structure.

part6

 

Now you have pointer to the first picture in the blog post. :)

As a side note to any Microsoft Employees who may actually read my blog – Yes, you can do the same thing with our Source Control Enlistments (I have a VS project for each branch I work out of).  And if you have one of the Source Control plugs in for Visual Studio, you can also have all the check in / check out / history that our source control provides.

UMDF Debugging talks online

Our wondrous Abhishek did a series of Debugging UMDF driver talks and I’m happy to say we now have the first three live on line!

In these he covers some of the basics; where to find and how to use WDFVerifier, how to use some of the UMDF Debugger extensions and some basic debugging UMDF scenarios.

http://www.microsoft.com/whdc/devtools/debugging/umdftraining.mspx

As always, any feedback or questions you guys may have, feel free to ping me!

Double filtered for added UMDF flavor.

In my previous post about Filter Drivers, I mentioned that this time I would focus on a more UMDF centric stack.  This one is pretty simple.

For UMDF only based driver stacks, the single most important directive is the UmdfServiceOrder INF directvie.  As I mentioned last post, that directive is a left to right list determining load order for the drivers contained in the device stack.  With the right most element in that list being the the lowest driver loaded.

Here are two examples – First a UMDF two driver stack with an upper filter;

[<mydriver>_Install.NT.Wdf]
UmdfService=UMDFFunction,WUDFFuncDriver_Install
UmdfService=UMDFFilter,UMDFFilter_Install
UmdfServiceOrder=UMDFFilter, UMDFFunction

Now to install a lower filter, simply flip the order in that directive;

[<mydriver>_Install.NT.Wdf]
UmdfService=UMDFFunction,WUDFFuncDriver_Install
UmdfService=UMDFFilter,UMDFFilter_Install
UmdfServiceOrder=UMDFFunction, UMDFFilter

The last tidbits here are; for a device stack that only contains UMDF drivers, there is no need to add any of these settings in the INF;

[<mydriver>_Device_AddReg]
; Load the redirector as an upperfilter on this specific device.
; 0x00010008 - FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND
HKR,,"UpperFilters",0x00010008,"WUDFRd" 

And also as before, the filter driver needs to be a good citizen on the stack, pass on requests it does not own to the next driver and don’t touch anything unless you must.  The previous code samples I’ve posted all still apply, but the basics are; GetDefaultIoTarget, FormatUsingCurrentType and Send.

There’s no need to change any code for a basic filter driver based on its load order (upper or lower filter).  As you get in to more advanced driver functionality you may find a need to change default behaviors.  For those cases, you can always send us mail. :)

There was also some questions about why would you want or need to be an upper or lower filter driver.  That one gets in to a bit more of a “it’s up to you”  but the core logic that applies to WDM / KMDF drivers applies to UMDF drivers (save the parts about bus drivers *g*).

There goes the Sun...there goes the sun and I say...

Oracle Buys Sun - Gearlog

I’m not sure how to feel about this.  I know it probably went under a lot of people’s radar, but it almost feels like the passing of a rival.  Something you wished would happen earlier, but not something you really wanted to happen because they made life interesting.  Scott McNealy’s keynote blastings of Microsoft were legendary and at times very humorous.  The “we’re the dot, in dot com” ads always gave me a chuckle.  Yup, they part of what made being an employee of Microsoft during the late 90s and early 2000s fun.

It wasn’t all about the products, they made hockey interesting as well.  There were a few charity Sun v. Microsoft hockey games played through the early part of this decade.  They ended up being events all to themselves.  A good way to let out some frustrations and have some fun with your rivals at the same time. 

All in all it was a good little feud, some barbs, a little blood (very little at a hockey game) and a lawsuit here and there.  But as a good feud should do, it drove of us to make our products better in the end.

Bon chance Sun.

That said, ol’ Larry Ellison has never been a close friend of Microsoft either. :)

I’ll have the next part in the UMDF Filter series later this week.

Genuine UMDF filtered drivers

Filter drivers have come up in conversations recently (both internal and external), so I wanted to take some time here to address some of the issues that were brought up with regards to UMDF filter drivers and how to make them.  Note: I’m not going to cover all the configuration dynamics available for UMDF filter drivers in this one post simply to avoid the risk information overload and clutter, so expect a couple of posts on this subject.

Let’s start with some basics, we’ll simply demonstrate how to configure and load a UMDF Filter as an upper filter driver to a kernel mode driver (KMDF or WDM) in the same INF-

As some of you may remember from my earlier posts, a UMDF filter driver should use the SetFilter(); property in the DeviceInitialization routine. This tells the Framework to do a couple of things for us automatically:

  1. Send I/O for which the Filter has not registered a callback for to the next logical driver in the stack.  Example: Your filter driver registers a DeviceIoctl callback method, but not read or write.  As a result your filter driver will only see IOCTLs
  2. Automatically forward file create cleanup and close so there is no need to invoke the AutoForwardCreateCleanupClose method.

That covers the really basic code required at driver / device initialization time.  Now we need to add the pertinent sections to the INF file.  As we’re going to focus on being an upper filter for this example, you need to make the following modifications to your INF (in addition to the normal UMDF specific sections);

[<mydriver>.NT.Wdf]
UmdfService = "<mydriver>", <mydriver>_Install
UmdfServiceOrder = <mydriver>

[<mydriver>_Device_AddReg]
; Load the redirector as an upperfilter on this specific device.
; 0x00010008 - FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND
HKR,,"UpperFilters",0x00010008,"WUDFRd" 

So a couple of things to note here -

One is the UmdfServiceOrder directive, this is load order specific.   I’ll address a more UMDF centric stack in the next post, but for those of you who like to work ahead, this is a left to right reading list to determine stack order.

Second thing is the registry key addition section.  As WUDFRd is the kernel mode transport service for UMDF drivers, WUDFRd is the upper level filter driver to a kernel mode driver.

Now that your driver is loaded as an upper filter, what should your driver do in order to be a good citizen in the stack?  Short answer is, as little as possible.  You perform the same steps for handling PnP and Power as you would for any basic UMDF driver (one that lets the framework handle the heavy lifting for those two).  You register your I/O callback routines and build your queues just like any normal UMDF driver, the only additional requirement here is to forward I/O requests as required.

For this example, let’s just demonstrate using a fairly simple pass through driver.  How you actually implement this is up to you, but the basic requirements here are - as your driver receives the request on the queue, it needs to pas pass it on to the next driver in the stack.  So first you need to get the default I/O target (next driver in the stack).  Next, format the request using the same type and then finally, send the request.  A condensed version would be something along these lines;

    IWDFIoTarget * kmdfIoTarget = NULL;
    
    this->GetFxDevice()->GetDefaultIoTarget (&kmdfIoTarget);

    Request->FormatUsingCurrentType();

    hr = Request->Send (
        kmdfIoTarget, 
        0,  // 0 Submits Asynchronous else use WDF_REQUEST_SEND_OPTION_SYNCHRONOUS
        0);

I also have some more basic code here for you to peruse.

So now we have a basic UMDF upper filter driver on top of a kernel mode driver.

Now Playing Capitals v. Rangers

Okay I know I said I was going to have a &quot;tech&quot; post next...

But this is too Astro-cool. :)

Kepler spacecraft open for business: Scientific American Blog

It's full of stars...

 

Yes, I'm alive, and in perfect hibernation, well not even in the same time zone as hibernation, but you get the joke hopefully. :)

I just had to share this little ditty with you all because it's very cool.

Microsoft, NASA put universe back on the Web | Webware - CNET

I will resume regular technical type blogging shortly.  Enjoy!

*Currently playing - Porcupine Tree Signify

More Posts Next page »
Page view tracker