UMDF - USB I/O for multiple interfaces/EPs

Hi all,

I’m fairly new to Windows driver development and I have a question. I’ve been using the fx2_driver example provided with the WinDDK along with a USB device I have to get up and running. So far I’ve been able to install the driver and establish communication between the driver/device and multiple user apps. Previously, we’ve used WinUSB, but need to overcome the limitation of 1 application per device.

I’ve been able to do some Control I/O operations, and I’ve been able to get the target device WinUSB handle to directly use WinUSB functions.

My question is regarding how to address endpoints in different interfaces. I may want application 1 to communicate with EP1 in IF1, and application 2 to communicate with EP2 in IF2.

The UMDF examples seem to have a single input pipe and a single output pipe. When ReadFileEx or WriteFileEx is used, OnRead or OnWrite simply fetch the input or output pipe from the device pointer and do I/O.

With ReadFileEx, there’s just an output buffer pointer and some number of bytes to be read. So, how do you choose to read from a particular endpoint? Is there some ability to use different file handles from the two different applications for different endpoints? Or some other trick?

Thanks,

Don

xxxxx@gmail.com wrote:

I’ve been able to do some Control I/O operations, and I’ve been able to get the target device WinUSB handle to directly use WinUSB functions.

My question is regarding how to address endpoints in different interfaces. I may want application 1 to communicate with EP1 in IF1, and application 2 to communicate with EP2 in IF2.

Are the interfaces otherwise identical? You wouldn’t really need two
interfaces in that case – you can put both endpoints in one interface.
Interfaces are usually used to separate different functions, say one for
audio and one for video.

If you DO need multiple interfaces, you can have a separate WinUSB
instance for each interface. You specify that in the PnP identifier.
Instead of just USB\VID_1234&PID_5678, you say
USB\VID_1234&PID_5678&MI_00. That’s interface 0 for that device.

The UMDF examples seem to have a single input pipe and a single output pipe. When ReadFileEx or WriteFileEx is used, OnRead or OnWrite simply fetch the input or output pipe from the device pointer and do I/O.

With ReadFileEx, there’s just an output buffer pointer and some number of bytes to be read. So, how do you choose to read from a particular endpoint? Is there some ability to use different file handles from the two different applications for different endpoints? Or some other trick?

If you need to specify an endpoint number, then you can’t use the
ReadFile/WriteFile model. You will have to use DeviceIoControl. That
allows you to pass two buffers. You can put the endpoint number in the
first, and have the second be used for the data transfer.

Or, I suppose you could use an ioctl to pass an endpoint number, and
remember that in the file handle context for later.


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

I had thought about using DeviceIoControl exclusively, but wasn’t sure it was the best idea / approach. The more I think it about it, it seems perfectly fine.

One other question though, regarding the same multiple EPs topic. After posting this thread, I came across a section of the UMDF reference relating to IWDFIoRequest::Get____Parameters, and searched around about pulKey, because it sounded like a great possible solution, and I found this:

http://www.osronline.com/showThread.CFM?link=125584

So it sounds like pulKey is a no go, and I shouldn’t use overlapping either. What about the namespace solution you mentioned? I see that it’s possible to obtain an IWDFFile OnCreateFile and from any IWDFIoRequest, and from that a pointer comparison can be done, since the same IWDFFile is used for all Requests after CreateFile, or a string comparison could be done. It seems that this would require multiple device paths, one for each endpoint, to be created.

Any comments on this solution in comparison to using DeviceIoControl?

If you DO need multiple interfaces, you can have a separate WinUSB
instance for each interface. You specify that in the PnP identifier.
Instead of just USB\VID_1234&PID_5678, you say
USB\VID_1234&PID_5678&MI_00. That’s interface 0 for that device.

Interesting. So would a driver stack / environment be created for each interface? I.e. are they treated like separate devices by UMDF? Or would I need to go through IWDFUsbInterface::GetWinUsbHandle to get the two different handles?

Thanks,

Don

xxxxx@gmail.com wrote:

One other question though, regarding the same multiple EPs topic. … What about the namespace solution you mentioned? I see that it’s possible to obtain an IWDFFile OnCreateFile and from any IWDFIoRequest, and from that a pointer comparison can be done, since the same IWDFFile is used for all Requests after CreateFile, or a string comparison could be done. It seems that this would require multiple device paths, one for each endpoint, to be created.

That’s another option. The old bulkusb sample used this kind of
scheme. If your driver’s symbolic link was “bulkusb”, you could do
CreateFile on “\\.\bulkusb\pipe_01” and “\\.\bulkusb\pipe_02”.

Any comments on this solution in comparison to using DeviceIoControl?

It’s just two ways to solve the same problem. You should use the model
that makes sense to you. ReadFile and WriteFile are really just special
cases of DeviceIoControl. Using DeviceIoControl would give you
flexibility in the future, in case you need to supply more additional
data with the request. If you’re confident that will never happen, and
you happen to like the ReadFile abstraction, then use it.

Interesting. So would a driver stack / environment be created for each interface? I.e. are they treated like separate devices by UMDF? Or would I need to go through IWDFUsbInterface::GetWinUsbHandle to get the two different handles?

It creates a separate driver stack for each interface. This is very,
very common. When you plug in a web camera with a microphone, for
example, it has one audio interface, and one video interface, and each
is loaded with a separate driver. That’s all done automatically.
(Well, okay, technically it has two audio interfaces and two video
interfaces, but that’s just a detail of the USB specs.)


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

Tim’s advice here has been excellent.

Just to be entirely clear: The actual names you use within your device’s name space (“pipe_01” and “pipe_02” in the example Tim provided, above) are entirely arbitrary and are parsed by your driver during Create processing.

So, you COULD have namespace names that were user-friendly, such as \.\MyRadio\IChannel and \.\MyRadio\QChannel – or \.\MyDevice\Data and \.\MyDevice\Audio – or whatever you want.

I, personally, love this feature (device name spaces) and think it’s used far too little by Windows driver writers. Instead, people opt for IOCTLs with InBuffers that contains data structures that describe the channel/info/connection they want. When, in fact, Windows already HAS this feature “built in” in the form of device name spaces on Create.

Peter
OSR

Thanks for the responses guys. They have been quite helpful.

I have a question about the device path of IAD devices. In the past, when not using IADs, my devices would show up as:

##?#USB#VID_xxxx&PID_xxxx#SN1234#{GUID}

Some portion of code uses the device path to obtain the serial number of a device – SN1234. Now with IADs, this path has turned into:

##?#USB#VID_xxxx&PID_xxxx&MI_xx#6&somehex&08&00xx#{GUID}

MI_xx corresponds to the IAD bFirstInterface, as does the final &00xx. It seems like what used to be the serial number portion is now completely different.

I want to be able to display the serial number of a IAD/device even if it is in use by another application. That’s why previous devices that didn’t use IAD would just look at the path serial number. WinUSB won’t let me connect to a device path that is already opened, so I don’t think I could just query the device descriptor.

Is there something I can do in the INF file, create a registry key, or some other way to do this with IADs?

Thanks.

You should never be parsing the device path, it needs to be treated as an opaque string. The fact that the SN was present and is no longer present is an implementation detail that you should not and cannot depend on.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Wednesday, March 16, 2011 3:30 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] UMDF - USB I/O for multiple interfaces/EPs

Thanks for the responses guys. They have been quite helpful.

I have a question about the device path of IAD devices. In the past, when not using IADs, my devices would show up as:

##?#USB#VID_xxxx&PID_xxxx#SN1234#{GUID}

Some portion of code uses the device path to obtain the serial number of a device – SN1234. Now with IADs, this path has turned into:

##?#USB#VID_xxxx&PID_xxxx&MI_xx#6&somehex&08&00xx#{GUID}

MI_xx corresponds to the IAD bFirstInterface, as does the final &00xx. It seems like what used to be the serial number portion is now completely different.

I want to be able to display the serial number of a IAD/device even if it is in use by another application. That’s why previous devices that didn’t use IAD would just look at the path serial number. WinUSB won’t let me connect to a device path that is already opened, so I don’t think I could just query the device descriptor.

Is there something I can do in the INF file, create a registry key, or some other way to do this with IADs?

Thanks.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

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

I just saw that in MSDN. Thanks for confirming. I’m guessing I should use WinUsb_GetDescriptor instead. I can get iSerialNumber from the device descriptor, and then get the string descriptor corresponding to that index.

Maybe I can just do that once, and store it in the registry at DeviceClasses/{GUID}/Device/SomeKey. That way I could look up the S/N string in the registry as my default operation.