Trouble using WdfDeviceInitAssignName()

I’d like to name the PDOs that my bus driver creates. That is, instead of (say) using \Device\000000fb, I’d like \Device\MyDevice-0, MyDevice-1, and so on.

I took this code straight from the KMDF documentation:

DECLARE_CONST_UNICODE_STRING(MyDeviceName, L"\Device\MyDevice-0") ;
status = WdfDeviceInitAssignName(DeviceInit, &MyDeviceName);
if (!NT_SUCCESS(status)) return status;

If I attempt to create one child device, the code above itself succeeds. Further, the call to IoGetDeviceProperty() in my function driver on the new stack also succeeds, but the returned data size from IoGetDeviceProperty() is zero bytes. The output buffer doesn’t contain \Device\MyDevice-0.

If I skip calling WdfDeviceInitAssignName() in my bus driver, everything works normally. The call to IoGetDeviceProperty() in my function driver succeeds and I see \Device\000000fb or whatever. Am I missing something?

Are you calling IoGetDeviceProperty immediately after creating the device? If so, that won’t work. A PDO is not really a PDO until after it is created, returned in QDR and then a bunch of PNP irps have been sent to it. If you want to poke at the name, then EvtDevicePrepareHardware would be a good spot. Furthermore, giving your PDOs fixed names is not a great idea since you cannot guarantee a 1:1 mapping between function and name since the following can happen

  1. you enumerate and start function A with name 1
  2. function A is surprise remove, but not removed
  3. function A is inserted again. Name 1 still exists for the previous instance, so you cannot use it. This means that function A now has Name 2.

But, you might think that b/c you are writing a generic parent that has software functions and not any physical functions that cannot be removed and that this does not apply. Not so. The parent is still a piece of hw that can be surprise removed so the same thing can happen one level up and still force the functions to remain the surprise removed state.

Why do you want the PDOs to have specific names? What are you going to do with that piece of information?

d

Let me explain in a little more detail.

In my bus driver’s EvtDevicePrepareHardware routine, I parse my (real/hardware) USB device’s config descriptor and create child devices. In here, I call WdfPdoInitAllocate(), followed by WdfDeviceInitAssignName(), followed by a ton of the other functions that you would expect.

Then I create the device with WdfDeviceCreate(), and then make it a child with WdfFdoAddStaticChild(). Then that part is done…this has always worked normally.

After that, the new device that I just created loads up, and I load my function driver on top of it. Inside my *function driver*'s EvtDevicePrepareHardware routine (in other words, this is fairly far removed from when I called WdfDeviceinitAssignName() in my *bus driver*), I call IoGetDeviceProperty(), and I get the results that I described above.

I understand your argument about why naming the PDO’s is a bad idea, but I saw the kernel doing it (\Device\USBPDO-7?) so I thought I could emulate.

I’m doing this to propagate information about a faulty host controller card which goes berserk if you pend more than one bulk URB at it (sigh). \Device\XXXCCGP-0 would mean a normal card, \Device\XXXCCGPF-0 (or whatever) would mean a “faulty” card. If my function driver detects a faulty card, it knows to only use one pending URB in its continuous reader.

I realize there are other ways of doing this, such as implementing an internal IOCTL that returns a boolean or something, but this seemed easiest.

My main concern, if only for future reference, is why I can’t seem to assign a name to my PDO. I tried doing this when I initially wrote this driver and it didn’t work then either, but I gave up on it back then…but now I sort of needed it again.

You can assign a name to your PDO, KMDF takes no different action then if you let the OS assign a name on its own. What does !devstack say for your PDO? does it report your custom name? Notice that the USB core’s PDO name does not remain constant for the device, it is incremented on every device plug in. Since it is not constant, I don’t see how any USB driver can rely on the format, so I don’t see why you would even introduce this obstacle in writing your driver.

Encoding an attribute in a name is easier then implementing an IOCTL? You have *GOT* to be kidding me. One involves rather simple logic and processing, the other creates an unholy dependency between the 2 drivers and involves string parsing (a very likely candidate for bugs and buffer overflows). If the IOCTL route is somehow not feasible, just add a value to the devnode that reflects this property. Add the property in the PDO’s EvtDeviceResourceRequirementsQuery callback (since it is called before the FDO’s EvtDriverDeviceAdd). and then query for it in the FDO’s EvtDriverDeviceAdd. This way your property set can scale (e.g. add more values) and does not depend on the lower bus’s naming patterns (just imagine encoding an open ended property set in the device’s name).

As for IoGetDeviceProperty failing, are you implementing the 2 passes? The first to get the size, the second to get the buffer? Remember that the returned buffer is PWSTR, not a PUNICODE_STRING.

d

I haven’t run !devstack in the debugger yet (and, if I’m not going to go this route, probably won’t), but I can tell you that the named object that I request never shows up in WinObj.

The main drawback to doing an internal IOCTL, at least in my mind and where I work (where all the hardware and third-party software is totally screwed up), is that issuing such a request to host controller X might cause what you call “unholy” behavior (I wouldn’t be surprised if for some controller somewhere, any IOCTL besides SUBMIT_URB, etc. just blue screened.)

I wanted some way to propagate the information to the child devices without them doing any traffic on the stack. This exposes me to the least risk. I thought of adding a bogus compatible ID, or maybe I can use your idea about adding a property to the devnode.

I’m calling IoGetDeviceProperty just once with a ~500-byte buffer. It works fine when I don’t name my PDO (I see \Device\000000xx). When I do name the PDO, the function *succeeds* (it doesn’t fail, as you say – the return is STATUS_SUCCESS), but the output size of the buffer is set to zero bytes. The buffer that I passed in just contains random data.