How to parse USB instance ID?

I’m wondering about what each component of a USB instance ID means.

I see that when a device has a USB serial number, the instance ID is just the serial number.

But, say I have a composite device with three interfaces. I get this:

5&1d4952dc&0&2

and this:

6&390b9358&2&0005 (for interface 5)

Here’s what I think I know so far:

5/6 – appears to be the number of steps up to the root of the device tree.

1d4952dc/390b9358 – I have no idea. I believe Maxim described this as “some junk” in a post. I don’t know if the parent and child instance IDs are related or not.

0/2 – don’t know.

2/5 – in the former case, don’t know. In the latter case, appears to be the interface number.

Thanks for any information.

-Chris

It is opaque, you are not supposed to parse it at all ;). It is an
undocumented format that can and will change from OS release to release.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Tuesday, December 19, 2006 5:49 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] How to parse USB instance ID?

I’m wondering about what each component of a USB instance ID means.

I see that when a device has a USB serial number, the instance ID is
just the serial number.

But, say I have a composite device with three interfaces. I get this:

5&1d4952dc&0&2

and this:

6&390b9358&2&0005 (for interface 5)

Here’s what I think I know so far:

5/6 – appears to be the number of steps up to the root of the device
tree.

1d4952dc/390b9358 – I have no idea. I believe Maxim described this as
“some junk” in a post. I don’t know if the parent and child instance
IDs are related or not.

0/2 – don’t know.

2/5 – in the former case, don’t know. In the latter case, appears to
be the interface number.

Thanks for any information.

-Chris


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Doron Holan wrote:

It is opaque, you are not supposed to parse it at all ;). It is an
undocumented format that can and will change from OS release to release.

Although it hasn’t yet…


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> ----------

From: xxxxx@lists.osr.com[SMTP:xxxxx@lists.osr.com] on behalf of Tim Roberts[SMTP:xxxxx@probo.com]
Reply To: Windows System Software Devs Interest List
Sent: Wednesday, December 20, 2006 3:29 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] How to parse USB instance ID?

Doron Holan wrote:
> It is opaque, you are not supposed to parse it at all ;). It is an
> undocumented format that can and will change from OS release to release.
>

Although it hasn’t yet…

And it won’t but if we had to use convoluted Setup API code to get info contained within HW ID, why should others have it easier? :wink:

Best regards,

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

Doron Holan wrote:

It is opaque, you are not supposed to parse it at all ;). It is
an undocumented format that can and will change from OS
release to release.

Ok. Well, pretend I’m writing my own generic parent driver. (Remember, we’re just pretending.) What instance ID (and in particular, the hex value in the middle) would I assign to my child PDOs when there is no serial number available?

The XP SP2 usbccgp seems to come up with the one I gave above, but I don’t understand where it got it from.

Another generic parent driver that I’m looking at seems to use the parent’s instance ID >> 3.

Ah, I see where the confusion is. Usbgccp does not create this instance
ID. If the bus does not report that it has unique IDs for its devices,
the pnp subsystem creates the instance ID. This is why every bus driver
in the system can “create” these opaque instance IDs.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Tuesday, December 19, 2006 6:54 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] How to parse USB instance ID?

Doron Holan wrote:

It is opaque, you are not supposed to parse it at all ;). It is
an undocumented format that can and will change from OS
release to release.

Ok. Well, pretend I’m writing my own generic parent driver. (Remember,
we’re just pretending.) What instance ID (and in particular, the hex
value in the middle) would I assign to my child PDOs when there is no
serial number available?

The XP SP2 usbccgp seems to come up with the one I gave above, but I
don’t understand where it got it from.

Another generic parent driver that I’m looking at seems to use the
parent’s instance ID >> 3.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Doron Holan wrote:

Ah, I see where the confusion is. Usbgccp does not create
this instance ID. If the bus does not report that it has unique
IDs for its devices, the pnp subsystem creates the instance ID.
This is why every bus driver in the system can “create” these
opaque instance IDs.

How exactly is this accomplished? The docs say “The driver must call WdfPdoInitAssignInstanceID before calling WdfDeviceCreate.”

Is it just a matter of omitting that call and then tweaking another call earlier in the process? I’m looking at the KMDF toaster busenum.c/buspdo.c but the answer is not jumping out at me (probably because toaster assumes serial numbers).

You provide it either way, it depends on if you specify UniqueId or not, from the WDF_DEVICE_PNP_CAPABILITIES docs

UniqueID
A WDF_TRI_STATE-typed value that indicates, if set to WdfTrue, that the device’s instance ID is unique to the entire system. If UniqueID is set to WdfFalse, the instance ID is unique only to the device’s bus. For more information about instance IDs, see Device Identification Strings.

http://msdn2.microsoft.com/en-us/library/ms791083.aspx has more details

d

Ok…please bear with me for a second. So say I set UniqueId to WdfFalse. The link you gave says “…If UniqueID is FALSE, the bus-supplied instance ID for a device is unique only to the device’s bus. The PnP manager modifies the bus-supplied instance ID, and combines it with the corresponding device ID, to create a device instance ID that is unique in the system.”

This seems to say that I still need to call WdfPdoInitAssignInstanceId, which unfortunately leads me back to my original problem: what value am I supposed to provide for the instance ID?

Even assuming it is going to be altered significantly or perhaps thrown away entirely, I presumably have to provide a consistent and quasi-unique value each time, so I can’t just choose a constant or random value.

Is the path here to issue IRP_MN_QUERY_ID to the original device’s PDO and then modify the result, like I’ve observed one driver doing? (I’m hoping this isn’t necessary as it seems I would need to drop down to WDM to do such a thing).

Or, assuming each instance of my generic parent is a “bus”, can I just choose strings like “0”, “1”, “2”, etc. for each interface, and then let the PNP manager do the rest?

Yes, you need to create an instance ID for your device if you choose not to expose the ability to create devices w/a unique identifier. Each bus does this in its own way. You can choose numerically increasing numbers, it really can be anything you want (getting the lower layer’s instance ID and modifying is OK as long you are the only child of that lower layer who is doing this). The heart of the matter is that you want to be consistent and give the device the same instance id so that the next time it is “plugged” into the bus, it will be an already installed device.

d

Ok. Well, I still don’t really understand exactly how to “choose the ability [of the system?] to create unique identifiers [for me]”, but I think I’m just going to have to play with it more and ask a better question later on.

Perhaps I can pose a different question for the moment. In the context of this exercise (a USB generic parent), I’m coming to the conclusion that I can actually use static child lists, because the number of USB interfaces/interface collections/child devices is going to be constant throughout the lifetime of the device.

Then, either in the parent’s EvtDeviceD0Exit or EvtCleanupCallback, I go and mark all the PDOs as missing with WdfPdoMarkMissing(). Is that right, or should I/do I need to use dynamic child lists?

Since it is static you don’t really need to ever mark them as missing since they will never disappear. if you mark them as missing during D0Exit(), the stacks will be surprise removed and not come back until you enumerate them again. Create a PDO for each function in PrepareHardware() and that’s it. The rest will be taken care of for you. No need to use a dynamic WDFCHILDLIST since functions to not come and go at runtime.

why are you writing your own usb generic parent? what does the inbox version lack?

As for bus instance IDs, think of it this way. It always identify the device.

If UniqueId is false (which is the default), this means that the instance id is relative to your bus driver, so if there were 2 instances of your driver and both enumerated a device with the same instance ID there would be 2 instances of the child stack without a problem. In this case the Pnp subsystem takes your instance ID and munges it through an opaque algorithm to create a system wide unique ID whose uniqueness is dependant on the entire pnp subtree above your child device (which is why if it shows up on another bus instance, the munged instanced would be different and hence treated as a new device).

If UniqueId is TRUE, then the instance ID is unique on the *entire* machine. The pnp subsystem will not munge the instance ID since it trusts you as the driver to make sure it is globally unique. No munging here. if 2 instnaces of your bus driver each enumerate a PDO with the same instance id and both report that the ID is unqiue, you will get a bugcheck (CA).

d

Doron Holan wrote:

Since it is static you don’t really need to ever mark them as missing
since they will never disappear. if you mark them as missing during
D0Exit(), the stacks will be surprise removed and not come back until
you enumerate them again. Create a PDO for each function in
PrepareHardware() and that’s it.

Ok. I noticed that when I did delete the WDFDEVICE for the PDO or marked the PDO as missing, I got “KMDF has detected some potentially bad behavior, turn on WDF verifier” in my DebugView log. So, I actually don’t touch it at all after creation, and it seems to like this just fine.

why are you writing your own usb generic parent? what does the
inbox version lack?

Hey, I’m just pretending, remember? Ok, I’m not pretending. I just remember some post from Oney a few years ago saying “you have no business making your own generic parent…”

Basically, I need to support what I suppose are now called “interface collections” all the way back to Win2K to 1) support devices already in the field, 2) support new devices that are perceived to be too fragile to touch and just expose a configuration that wouldn’t require collections, 3) possibly use it for testing of our function drivers, 4) to gain the experience of making a bus driver, and 5) we have an issue with our existing one and our vendor isn’t writing me back :slight_smile:

Thanks for the more detailed explanation about instance IDs. I’m fairly certain I get it now, after reading what you wrote and playing with it a little. I’m using uniqueID == false and the CreatePdo() function inside the toaster sample.

If I pass “01” to WdfPdoInitAssignInstanceID(), I get 6&3549e63&1&01. If I pass “hello”, I get 6&3549e63&1&hello. Incidentally, the 3549e63 is what I was seeing the other day from our existing bus driver (the parent’s hex value >> 3). It doesn’t match what usbccgp is doing, but since it’s supposed to be opaque, I’m fully content to leave that topic alone.

I’m thinking the only thing I’ll really need to do here is watch for USB serial numbers, and then flag UniqueId to TRUE and use the serial number for the instance ID. Otherwise I’ll get reinstallations (of the child devices only, I suppose) as I move the device from port to port. Yes?

You are never allowed to delete a pnp WDFDEVICE. why? becuase KMDF owns the lifetime of the device through the pnp state machine, which means the pnp manager owns the lifetime of the device. There is one exception. A static PDO that you successfully created but did not report via WdfFdoAddStaticChild yet can be deleted manually (since pnp has not been notified of its existance as a PDO yet). Once you call WdfFdoAddStaticChild, hands off though.

as for the serial number, i don’t think you need to do that b/c you are below a uniquely identified device and I think that property is applied to the entire pnp subtree below the device. for what its worth, the generic parent driver doesn’t care. it just uses the function’s index in the list of functions as the instance ID. since the list of functiosn doesn’t change, the instance ID will be the same from plug in to plug in.

d

That makes sense about deleting WDFDEVICEs. Speaking of WdfFdoAddStaticChild, I didn’t see this call in the static Toaster sample after the call to create the child device PDO. It might have been from KMDF 1.1 though. Once I added it to my driver, though, I got the new hardware arrival.

Also, based on your advice, I won’t pay any attention to serial numbers then. Obviously easy enough to test if it’s really working correctly much later on.

Now, for my next challenge, I set up a default queue to handle internal IOCTLs (which just completes them as failure synchronously) and then generated a child PDO with a hardware ID that matched one of my installed function drivers.

It enumerated as I expected and failed out (also as expected), but when I checked the traces, I didn’t see any internal IOCTLs (such as IOCTL_INTERNAL_USB_SUBMIT_URB) arrive at my driver. The call to WdfUsbTargetDeviceCreate() (in my function driver, on top of the child PDO) is failing with “invalid device request”.

Is there something I need to explicitly do to enable the I/O path between my child devices and my parent driver? Or maybe to just deliver internal IOCTLs to the queue that I set up?

By the way, I thought it might be because I didn’t name my PDO (although later learning that the framework names PDOs for you automatically).

So I called WdfDeviceInitAssignName(), and it succeeded, but after it was done I didn’t see my named object when using WinObj. Is that right?

I think what you are saying is that you created a WDFQUEUE on the parent FDO and you are asking why you are not seeing I/O sent to the children PDOs forwarded to your FDO queue. It doesn’t work that way (nor does WDM). You have to create a separate WDFQUEUE for each PDO and then handle the I/O there. Right now you cannot fwd requests to a FDO’s WDFQUEUE that were received on a PDO’s WDFQUEUE, but in this case I don’t think you need to do that, you just need to process the request and send it down the FDO’s stack.

As for the naming of the PDO, let KMDF autogenerate a name for you (actually the i/o manager does this). As for not being able to see it in WinObj, that might have to do with the pnp state. I don’t use WinObj so I don’t know how it gets the list of devices. !devstack will give you the name though.

d

Of course! I hooked up my queue to my child WDFDEVICE PDO this time (not my bus driver FDO, you were right) and got my first internal IOCTL right away.

As for the object naming, I won’t worry about it since I don’t need it, just thought it was odd since I explicitly chose a name and it never showed up. When I plugged in my device I did get three automatically named objects in \Device – I’m assuming these were device PDO (from usbhub), the bus driver FDO, and then the child PDO, but don’t really know.