Writing Lower Filter driver for UVC (Usbvideo.sys)

Hi All,

I wanted to develop a lower filter driver for UVC Inbox driver (Usbvideo,sys), please see the below image.

The filter driver is to help overcome the hardware function limitation.
in my case it will help in holding/masking of USB disconnect and connect which can happen in our hardware during a mode switch.

I would like to get your input's in designing the lower filter driver and also WHQL certification for the filter driver. I'm not sure if Microsoft allows to implement filter driver for inbox Usbvideo.sys and certify it.
Thank's in advance for your suggestions and input.

Regards,
Prasad

if the USB disconnect on mode switch causes the device to be surprise removed (fall off the bus) there is nothing your lower filter can do to prevent this from happening. the surprise remove occurs lower in the stack.

What do you mean by "mode switch"? Do you mean selecting an alternate setting? If your hardware is dropping off of the bus during a setting change, that's happening at a hardware level. That can't be compensated for in software. Your device is broken and needs to be fixed.

Thanks for the replies,

Mode switch is bit file update for the FPGA during which the USB H/W device disconnect/reconnect basically it re-enumerates again. After the mode switch and the device is re-enumerated, there is a certain time delay for the FPGA to be ready to accept the USB commands, during this time delay I want to have a lower UVC filter driver to queue and hold the commands until the FPGA is ready.

Nope, that is simply impossible. When your device drops off of the wire, the device is considered to have been unplugged, and driver stack will be unloaded. When your device reappears, you'll get a brand new physical device object, and a new set of drivers will be loaded. There's no way to transfer a device from one stack to another.

The USB spec has some very rigid timing requirements for device enumeration. Once you chirp that you are present on the bus, you have a limited amount of time to accept and respond to commands. If you take too long, that's a protocol violation, and you'll error out. The best plan is not to turn on the USB engine until you're pretty much ready.

Thanks Tim,

If I understand correctly from your replay the USB UVC driver stacks (including any filter driver) gets unloaded when the device on the USB bus disconnects and reloads when re-connected during mode switch.

During re-enumeration of USB when UVC USB stack is loaded will the filter driver attached previously to UVC stack is loaded?

Other question i have is on how the filter driver loading works.

Thanks for your reply, I'm currently doing a feasibility study on adding Lower filter driver for Microsoft UVC (UsbVideo.sys) Inbox driver.

All the information i can get here will be very helpful.

This is all fundamental to how a Windows device gets it drivers. I think this is a very useful diagram:

When a device is plugged in, the bottom level bus driver (the USB hub driver in this case) creates a PDO that has a device identifier. It notifies PnP that its PDOs have changed, then it's job is done.

Now, PnP takes the device identifier, and looks in the registry to see if there is a driver registered for this device identifier. Assuming there is, it loads each service from the LowerFilters key in turn. It hands the first one the original PDO, and that filter creates a FiDO. It hands that FiDO to the next LowerFilters service, etc. Then, it loads the main service for the device (the function driver), and hands it topmost lower filter FiDO. That service creates its FDO (functional devobj). PnP then loads the UpperFilters one by one, and each one the device object from the previous one. Only then is the whole device ready to handle commands.

When your device unplugs, the USB hub driver drops your PDO and sends a notification to PnP that its collection of child PDOs has changed. PnP travels to the very top of the driver stack and sends a surprise removal IRP, then a remove device IRP. Each driver, from the top down, releases its resources and deletes its device object, until the whole thing gets torn down, clear down to the USB hub driver. It is described here:

When your device arrives again, it's a clean slate. All records of the previous instantiation are gone. The whole process starts over again.

Thanks, Tim for the reply.

In one of the posts about USBVideo Lower Filter driver I noticed adding the lower filter driver can be done by adding a registry string "LowerFilters" under the HKLM\System\CurrentControlSet\Enum\USB, in the subkey that matches your camera’s VID and PID.

Can I add the Registry Key through the INF file of the filter driver? by using the AddReg Install Section.

There is a LowerFilters directive that will do this for you

What kind of an INF? If this is the INF for the camera device, then you can absolutely add LowerFilters and UpperFilters in the INF file. If you are JUST installing a filter, then you don't really need an INF at all.

Yes, the INF File is for lower filter driver for camera device.

You can't really have an INF file for a lower filter. You can have an INF for the whole camera that installs usbvideo and INCLUDES a lower filter, or you can have a fake "DefaultInstall" INF that manipulates the registry.

Thanks Tim,

When you say we can have the INF File for filter driver, does this mean we don't need the INF file for the filter driver?

I have created a Lower Filter Driver for the UVC camera device, created a service and updated the registry following the steps your mentioned in a different post.

here are two parts to this. First, you have to create a service for
your driver. You can do that using the “sc” tools. Copy your binary
into \Windows\System32\Drivers, then run:
sc create yourservicename type= kernel start= demand binPath=
system32\drivers\yourbinary.sys

Then, you have to install that service as a lower filter for the
device. That’s done via the registry. If you are on XP, you can modify
the registry by hand. You would find the entry in
HKLM\System\CurrentControlSet\Enum\USB, in the subkey that matches your
camera’s VID and PID. You would add a new entry called LowerFilters of
type REG_MULTI_SZ, and enter your service name. Then, plug in the device.

I was able to install the filter driver, confirmed this by DbgPrint message from DriverEntry and AddDevice Routine. I have also added Internal DeviceIoControl method to filter and handle the URB request for a particular control Function. I'm not seeing the debug prints from the DeviceIoControl Method indicating it is not getting called.
Not sure what is the reason?

How did you set up the callback? internal ioctls get a different callback from regular ioctls.

Created the Queue Config DeviceIoControl callback in the Add Device routine. below is the code.
//
// Configure the default queue to be Parallel.
//
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,
WdfIoQueueDispatchParallel);

ioQueueConfig.EvtIoDeviceControl = UVCIoDeviceControl;

WDF_OBJECT_ATTRIBUTES_INIT(&deviceAttributes);

DbgPrint("%s: Line %d \n", FUNCTION, LINE);

__analysis_assume(ioQueueConfig.EvtIoStop != 0);
status = WdfIoQueueCreate(device,
&ioQueueConfig,
&deviceAttributes,
&queue // pointer to default queue
);
__analysis_assume(ioQueueConfig.EvtIoStop == 0);
if (!NT_SUCCESS(status)) {
DbgPrint("WdfIoQueueCreate failed %x ", status);
goto End;
}

In the DeviceIoControl Function Trying to get the URB from the IRP.
Forward the request with the IoCompletion routine.
VOID
UVCIoDeviceControl(
In WDFQUEUE Queue,
In WDFREQUEST Request,
In size_t OutputBufferLength,
In size_t InputBufferLength,
In ULONG IoControlCode
)
{
WDFDEVICE device;
PIRP wdmIrp;
WDF_REQUEST_PARAMETERS params;
PURB pUrb;

UNREFERENCED_PARAMETER(Queue);
UNREFERENCED_PARAMETER(InputBufferLength);
UNREFERENCED_PARAMETER(OutputBufferLength);

DbgPrint("UVCIoDeviceControl: Entry %d\n" ,__LINE__);
DbgPrint("%s: Line %d \n", __FUNCTION__, __LINE__);
//
// Get the WDM IRP
//
wdmIrp = WdfRequestWdmGetIrp(Request);
WDF_REQUEST_PARAMETERS_INIT(&params);
WdfRequestGetParameters(Request, &params);

DbgPrint("UVCIoDeviceControl: IoControlCode %x\n", IoControlCode);

pUrb = URB_FROM_IRP(wdmIrp);
if ((pUrb->UrbHeader.Function == URB_FUNCTION_CONTROL_TRANSFER)
    || (pUrb->UrbHeader.Function == URB_FUNCTION_CONTROL_TRANSFER_EX))
{
    DbgPrint("URB.Header.Status %x, \n", pUrb->UrbHeader.Status);
}

device = WdfIoQueueGetDevice(Queue);
FilterForwardRequestWithCompletion(Request, WdfDeviceGetIoTarget(device),
    InternalIOCompletionRoutine, WDF_NO_CONTEXT);

return;

}
VOID
FilterForwardRequestWithCompletion(
IN WDFREQUEST Request,
IN WDFIOTARGET Target,
IN PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine,
IN WDFCONTEXT CompletionContext
)
{
NTSTATUS status;

DbgPrint("%s: Entry %d\n", __FUNCTION__, __LINE__);

WdfRequestFormatRequestUsingCurrentType(Request);
WdfRequestSetCompletionRoutine(Request, CompletionRoutine, CompletionContext);

if (!WdfRequestSend(Request, Target, WDF_NO_SEND_OPTIONS)) {
    status = WdfRequestGetStatus(Request);

    DbgPrint("WdfRequestSend failed - 0x % x\n", status);

    WdfRequestComplete(Request, status);
}
return;

}

Setting up the IoInternalDeviceControl Method worked.
//ioQueueConfig.EvtIoDeviceControl = UVCIoDeviceControl;
ioQueueConfig.EvtIoInternalDeviceControl = UVCIoInternalDeviceControl;

Question How can i retry the IRP request from the InternalIoCompletion Routine.
I'm trying to implement this the UVC Lower Filter Driver for hardware scenario which requires some time to recover from a FW switch.

Didn't you say your device drops off the bus when you update the firmware? If that's the case, then the question is not sensible. The device object you're driving becomes an orphan -- it's no longer connected to any hardware. A new device stack with new device objects will be built when your device re-appears.

Yes Tim, but wanted to do fesability check and POC of implementing filter driver which can hold off completion of request which is cancelled during the switching and retry it again.
Your saying that when the HW switch happens the camera device disappears and reappears which is notified to the UVC driver stack and causes driver to disappear and reappear with new device objects. Does this happen with out filter driver getting some kind of notification?

Yes, you get a notification, but what are you going to do with it? When the device drops out, the device objects below you go dead, and they will not get revived. The new device brings in a NEW set of device objects, unrelated to the old ones. You can't "retry", because there is no longer anyone listening below you. The new device gets a brand new set of device objects, which will be initialized as a brand new device. Any applications that were connected to the previous instances will have to close those files and open new ones.