Virtual Device Descriptors

I am launching a couple of virtual devices from a Bus Driver (launched from USB Device).
How can I supply virtual Device and Configuration Descriptors for these virtual devices from the Bus Driver?

xxxxx@gmx.com wrote:

I am launching a couple of virtual devices from a Bus Driver (launched
from USB Device).
How can I supply virtual Device and Configuration Descriptors for
these virtual devices from the Bus Driver?

I should think this was rather obvious. The virtual devices will be
sending URB_GET_DESCRIPTOR_FROM_DEVICE requests to you. You just need
to respond.


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

>xxxxx@gmx.com wrote: >> >> I am launching a couple of virtual devices from a Bus Driver (launched >> from USB Device). >> How can I supply virtual Device and Configuration Descriptors for >> these virtual devices from the Bus Driver? >> > I should think this was rather obvious. The virtual devices will be > sending URB_GET_DESCRIPTOR_FROM_DEVICE requests to you. You just need > to respond. > – > Tim Roberts, xxxxx@probo.com > Providenza & Boekelheide, Inc. > – Thanks for the reply. I was hoping that there was an easier method. For reference I am using WDF Bus Driver. Tell me if I am handling this correctly: 1) I handle the IOCTL_INTERNAL_USB_SUBMIT_URB in the EVT_WDFDEVICE_WDM_IRP_PREPROCESS handler. 2) I assign pUrb = (PURB)irpStack->Parameters.Others.Argument1 3) I test if URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE == pUrb->UrbHeader.Function. If it is not, I send the Irp down the stack and return. 4) First I test irpStack->DeviceObject->DeviceType value for values of
drivers that I have launched. For example: if (FILE_DEVICE_MASS_STORAGE == irpStack->DeviceObject->DeviceType) If I find a unique one that I have launched, I return the appropriate virtual Descriptor. 5) Then I test irpStack->DeviceObject->DriverObject->DriverName for names of drivers that I have launched. If I find one that I have launched, I return the appropriate virtual Descriptor. 6) At this point, I didn’t find one of the drivers that I have launched so I pass the IRP down the stack and return. Is there a better way to test which virtual device the Descriptor is for?

xxxxx@gmx.com wrote:

> Thanks for the reply. I was hoping that there was an easier method.
> For reference I am using WDF Bus Driver.
>
> Tell me if I am handling this correctly:
>
> 1) I handle the IOCTL_INTERNAL_USB_SUBMIT_URB in the EVT_WDFDEVICE_WDM_IRP_PREPROCESS handler.
>
> 2) I assign pUrb = (PURB) irpStack->Parameters.Others.Argument1
>
> 3) I test if URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE == pUrb->UrbHeader.Function.
> If it is not, I send the Irp down the stack and return.

Well, that step isn’t that easy. More in a bit…

> 4) First I test irpStack->DeviceObject->DeviceType value for values of drivers that I have launched.
> For example: if (FILE_DEVICE_MASS_STORAGE == irpStack->DeviceObject->DeviceType)
> If I find a unique one that I have launched, I return the appropriate virtual Descriptor.
>
> 5) Then I test irpStack->DeviceObject->DriverObject->DriverName for names of drivers that I have launched.
> If I find one that I have launched, I return the appropriate virtual Descriptor.
>
> 6) At this point, I didn’t find one of the drivers that I have launched so I pass the IRP down
> the stack and return.

If you are a bus driver (and not a filter), then every request you get
will be from a device that you reported in your child device list. You
cannot get requests from any device you did not create yourself.

However, there are more complexities here. Let’s say you return a faked
set of descriptors to a device. That device, sooner or later, is going
to do a USB_FUNCTION_SELECT_CONFIGURATION to try to configure the
endpoints for all of its interfaces. The endpoint and interface numbers
in that request are all going to come from your fake descriptors. You
can’t just hand those down to the real USB stack, because the numbers
won’t match up.

For example, usbccgp.sys does what you are describing. It creates a
child device for each interface in a multiple-interface device, and
chops up the descriptor into separate descriptors so that each child
device thinks it has one interface. Each of the faked descriptors it
hands out has “interface #0”, even though the hardware has interface #0,
#1, #2, #3, etc. So, every time usbccgp.sys gets a request that
includes an interface number, it has to rewrite that request before it
submits it so that it uses the REAL interface number.

> Is there a better way to test which virtual device the Descriptor is for?

Well, you created the child devices. When you get a request, you KNOW
it will be from one of those devices. Since you created the list to
begin with, you can just look up the PDO in your list of PDOs and know
where it came from.


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

there is no need for a preprocess routine and never a need to look at the DeviceType or the DriverName. Each child you enumerate will have its own WDFDEVICE. that WDFDEVICE contains all of the information you need to report descriptors and know which device the request came in for.

d

Thanks. I have added a PDO record in the child list of the virtual devices I have launched to determine which device the descriptor is for. For some reason I thought that the requests could also come from other sources. Now all I have to do is search through the list. Your help has been greatly appreciated. I will maintain the same endpoint designations. There will be only 1 Configuration for the device. I trust that it will be alright to only expose the specific Bulk OUT and Bulk IN pipes (using the same endpoint numbers) to the Mass Storage Driver while exposing only the specific Interrupt IN pipe to the HID Driver (etc).

Doran,

Thanks for the reply. I agree, looking at DriverType and/or DriverName are a bad way of testing which driver is making the request. However, I’m a bit confused that I don’t need a preprocess routine. I don’t seem to be receiving some of the IOCTL requests in my regular IO Handler routines. The WDF driver that wraps my Bus Driver appears to want to handle some of these requests. For example, the IOCTL_HID_READ_REPORT was not being passed to the Bus Driver so I had to add the preprocess handler to capture it. Although the new device will send actual HID Reports in the normal way (INT IN Pipe), the reason *had been* that the Bus Driver was creating the HID Reports from data that had originated as Fingerprint images sent from the device. I was left with the impression that I would still need to capture some IOCTL requests in the preprocess routine. Are you saying that IOCTL_INTERNAL_USB_SUBMIT_URB requests will be sent to the EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL routines? If so, I’ll add the IOCTL case to the routine. How about IOCTL_HID_READ_REPORT requests? Will the Bus Driver receive them as well or will they be sent to the device by the WDF Wrapper?

xxxxx@gmx.com wrote:

I will maintain the same endpoint designations. There will be only 1 Configuration for the device. I trust that it will be alright to only expose the specific Bulk OUT and Bulk IN pipes (using the same endpoint numbers) to the Mass Storage Driver while exposing only the specific Interrupt IN pipe to the HID Driver (etc).

That’s silly. The RIGHT way to do this is to group your endpoints into
two different interfaces. That way, you wouldn’t need a driver at all.
There would be no functional difference in the device (interfaces are
just a convention for grouping). The only change would be in the
descriptors.


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

Tim,

Yes, it’s silly if all drivers are intended to be launched. However, that is not my case. Some drivers that can be launched are for special customers only. As such, the interface to the device for these functions needs to be kept hidden and/or obscure.

xxxxx@gmx.com wrote:

Yes, it’s silly if all drivers are intended to be launched. However, that is not my case. Some drivers that can be launched are for special customers only. As such, the interface to the device for these functions needs to be kept hidden and/or obscure.

How is that enabled? If you can send a “magic unlock” sequence to the
device that gets saved in EEPROM, for example, you could have the device
choose which interfaces to include in the descriptor. You could even do
that as a boot-time software decision – expose one simple interface
that loads your first driver, which sends a code and triggers a
re-enumeration with the appropriate setup.

This is more or less what multiple configurations were designed to
handle, although they have always been somewhat problematic.


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

xxxxx@gmx.com wrote:

Thanks for the reply. I agree, looking at DriverType and/or DriverName are a bad way of testing which driver is making the request. However, I’m a bit confused that I don’t need a preprocess routine. I don’t seem to be receiving some of the IOCTL requests in my regular IO Handler routines. The WDF driver that wraps my Bus Driver appears to want to handle some of these requests.

What do you mean by “wraps”? Your bus driver IS a WDF driver, right?
So there’s only one driver here?

For example, the IOCTL_HID_READ_REPORT was not being passed to the Bus Driver so I had to add the preprocess handler to capture it.

As a USB driver, you will never see IOCTL_HID_READ_REPORT. That’s a
message sent to HID drivers. The usbhid.sys driver accepts
IOCTL_HID_READ_REPORT requests and turns them into interrupt pipe
reads. That’s what you will see.

Are you saying that IOCTL_INTERNAL_USB_SUBMIT_URB requests will be sent to the EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL routines?

Yes.

How about IOCTL_HID_READ_REPORT requests? Will the Bus Driver receive them as well or will they be sent to the device by the WDF Wrapper?

Neither. Your bus driver will see an URB with
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER.


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

how do you launch a mass storage driver from a bus driver? don’t you need a vid/pid or something to identify the “virtual” device?

xxxxx@myemail.com wrote:

how do you launch a mass storage driver from a bus driver? don’t you need a vid/pid or something to identify the “virtual” device?

Yes. You don’t really “launch a mass storage driver”. Instead, your
bus driver creates a child device, using a PnP identifier. PnP then
goes out to find an appropriate driver for that device, based on the
identifier. The identifier then needs to be matched by an INF file that
loads a mass storage driver.


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