USB Alternate Setting in WDF

I am having trouble getting interface 0/alternate 1 to be selected. I have set up my descriptors as follows:

interface 0/alternate 0:
ep 1 isoch in / 0 bytes
ep 2 int in / 32 bytes
ep 3 int out / 32 bytes
ep 4 isoch out / 0 bytes

interface 0/alternate 1:
ep 1 isoch in / 16 bytes
ep 2 int in / 32 bytes
ep 3 int in / 32 bytes
ep 4 isoch out / 16 bytes

Using a software bus analyzer called USBTrace, I was able to prove to myself that the continuous endpoint reader from the osrusbfx2 WDF sample worked as advertised on interface 0/alternate 0. I set up a 16 bit incrementing counter on the endpoint and dumped out 32 bytes at a time and it never had a gap in the data.

Switching to alternate setting 1 on interface 0 has been giving me some trouble:

Here is the code snippet I have been using (in the SelectedInterfaces routine in Device.c):

WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams;
NTSTATUS status;
PDEVICE_CONTEXT pDeviceContext;
WDF_USB_INTERFACE_SELECT_SETTING_PARAMS selectSettingParams;
WDFUSBPIPE pipe;
WDF_USB_PIPE_INFORMATION pipeInfo;
UCHAR index;
UCHAR numberConfiguredPipes;
WDFUSBINTERFACE UsbInterface;

pDeviceContext = GetDeviceContext(Device);

WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams,1);
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&configParams, 1, selectSettingParams);
status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams);
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfUsbTargetDeviceSelectConfig failed %!STATUS!\n”, status);
return status;
}

pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface;
UsbInterface = WdfUsbTargetDeviceGetInterface(pDeviceContext->UsbDevice, 0);
status = WdfUsbInterfaceSelectSetting(UsbInterface,WDF_NO_OBJECT_ATTRIBUTES,&selectSettingParams);
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfUsbInterfaceSelectSetting failed %!STATUS!\n”, status);
return status;
}

numberConfiguredPipes = WdfUsbInterfaceGetNumEndpoints(UsbInterface,0);

//
// Get pipe handles
//

Now this line: configParams.Types.SingleInterface.ConfiguredUsbInterface;
is probably killing me, but I couldn’t find an equivalent union value that returns a ConfiguredUsbInterface for multiple endpoints.

In the Kernel-Mode Driver Framework .chm file, the entry for WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES in the sample code snippet refers to a user created function, InitSettingPairs, which is not defined anywhere else in the manual. I think that would be useful to flesh out on that page, as I am not certain how I would create it myself. Any help would be appreciated.

Once you have configured the device using WdfUsbTargetDeviceSelectConfig(), you can select the alternate interface setting using WdfUsbInterfaceSelectSetting().

For you device, you have only one interface. So, you can select a config using WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE and then use configParams.Types.SingleInterface.ConfiguredUsbInterface to get the interface. By using WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES, you must use configParams.Types.MultiInterface.Pairs and iterate over the array (this is the same pointer as the selectSettingParams you passed in, so you could just use selectSettingParams to get the WDFUSBINTERFACE).

These 2 are functionally the same

WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&configParams, 1, selectSettingParams);
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams);

WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE() is a shortcut for the multi interface case and returns the ony and only WDFUSBINTERFACE in the structure itself vs requiring the caller to provide an array of settings.

D

Thanks for your quick response Doron, but I am still not getting it. Here is what I have done after your advice. Side Note: the USB analyzer it claims Device Address is 3 and four open pipes when the default (alternate 0) is in affect and the debugger spits out the trace messages for the continuous reader as set up in the osrusbfx2 sample; which is what I would expect.

After putting in the lines of code (those that have // * at then end) and running it, the USB analyzer tells me that I have a device address of 0 and no pipes open, i.e. I am not configured. Here is my updated snippet:

pDeviceContext = GetDeviceContext(Device);
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams);
status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams);
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfUsbTargetDeviceSelectConfig failed %!STATUS!\n”, status);
return status;
}
pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface;
UsbInterface = WdfUsbTargetDeviceGetInterface(pDeviceContext->UsbDevice, 0); // * Should this be used instead of pDC->UsbInterface?
WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams,1); // *
status = WdfUsbInterfaceSelectSetting(pDeviceContext->UsbInterface,WDF_NO_OBJECT_ATTRIBUTES,&selectSettingParams); //*
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfUsbInterfaceSelectSetting failed %!STATUS!\n”, status);
return status;
}

numberConfiguredPipes = WdfUsbInterfaceGetNumEndpoints(pDeviceContext->UsbInterface,0);

BTW, I stepped through this section in WinDBG and everything seems OK, structures and values
seemed to be set with I would say are reasonable looking values, and the last line numberConfiguredPipes has 4 which would be correct. I don’t get bug checks but I also don’t get int in reads either.

Sorry for my ignorance if I am missing something trivial, but am I new to the WDF and windows drivers in general.

Some additional information. Again referencing the osrusbfx2 WDF sample:

My slightly modified DEVICE_CONTEXT:

typedef struct _DEVICE_CONTEXT
{
WDFUSBDEVICE UsbDevice;
WDFUSBINTERFACE UsbInterface;
WDFUSBPIPE IsoReadPipe;
WDFUSBPIPE IntReadPipe;
WDFUSBPIPE IntWritePipe;
WDFUSBPIPE IsoWritePipe;
UCHAR CurrentSwitchState;
// WDFUSBPIPE BulkReadPipe;
// WDFUSBPIPE BulkWritePipe;
// WDFUSBPIPE InterruptPipe;
} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext)
extern ULONG DebugLevel;

If I comment out the following lines in the routine OsrFxEvtDeviceD0Entry (in Device.c)
status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->IntReadPipe));

and in OsrFxEvtDeviceD0Exit (in Device.c)
WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(pDeviceContext->IntReadPipe), WdfIoTargetCancelSentIo);

The interface does show as selected with Device Address 3 and 4 open pipes (isoch in 16 bytes, int in 32 bytes, int out 32 bytes and isoch out 16 bytes) in the USB analyzer, which is correct.

Here is my complete modified SelectInterfaces routine:
{

WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams;
NTSTATUS status;
PDEVICE_CONTEXT pDeviceContext;
WDFUSBPIPE pipe;
WDF_USB_PIPE_INFORMATION pipeInfo;
UCHAR index;
UCHAR numberConfiguredPipes;
WDF_USB_INTERFACE_SELECT_SETTING_PARAMS selectSettingParams; // *
WDFUSBINTERFACE UsbInterface; // *

pDeviceContext = GetDeviceContext(Device);
WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams);
status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams);
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfUsbTargetDeviceSelectConfig failed %!STATUS!\n”, status);
return status;
}
pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface;
UsbInterface = WdfUsbTargetDeviceGetInterface(pDeviceContext->UsbDevice, 0); // * Should this be used instead of pDC->UsbInterface?
WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams,1); // *
status = WdfUsbInterfaceSelectSetting(pDeviceContext->UsbInterface,WDF_NO_OBJECT_ATTRIBUTES,&selectSettingParams); //*
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “WdfUsbInterfaceSelectSetting failed %!STATUS!\n”, status);
return status;
}

numberConfiguredPipes = WdfUsbInterfaceGetNumEndpoints(pDeviceContext->UsbInterface,0);

//
// Get pipe handles
//
for(index=0; index < numberConfiguredPipes; index++) {

WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);

pipe = WdfUsbInterfaceGetConfiguredPipe(pDeviceContext->UsbInterface,
index, //PipeIndex,
&pipeInfo
);
//
// Tell the framework that it’s okay to read less than
// MaximumPacketSize
//
WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe);
if(WdfUsbPipeTypeIsochronous == pipeInfo.PipeType)
{
if(WdfUsbTargetPipeIsInEndpoint(pipe))
{
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, “IsoInput Pipe is 0x%p\n”, pipe);
pDeviceContext->IsoReadPipe = pipe;
}
else
{
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, “IsoOutput Pipe is 0x%p\n”, pipe);
pDeviceContext->IsoWritePipe = pipe;
}

}

if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType)
{
if(WdfUsbTargetPipeIsInEndpoint(pipe))
{
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, “IntInput Pipe is 0x%p\n”, pipe);
pDeviceContext->IntReadPipe = pipe;
}
else
{
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, “IntOutput Pipe is 0x%p\n”, pipe);
pDeviceContext->IntWritePipe = pipe;
}

}

}

//
// If we didn’t find all the 4 pipes, fail the start.
//

if(!(pDeviceContext->IsoReadPipe && pDeviceContext->IsoWritePipe && pDeviceContext->IntReadPipe && pDeviceContext->IntWritePipe))
{
status = STATUS_INVALID_DEVICE_STATE;
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, “Device is not configured properly %!STATUS!\n”, status);
return status;
}

return status;
}

The alternate interface switch is happening before the assigned of the USBPIPE values. Doron mentioned in an earlier post that Isochronous transfer cannot be done using the continuous reader and read/write pipe routines, do I even need them in the context definition?

So some how after the alternate 1 is selected and during the set up of the continuous reader something is going wrong.

in the single interface case, these 2 handles
configParams.Types.SingleInterface.ConfiguredUsbInterface;
WdfUsbTargetDeviceGetInterface(pDeviceContext->UsbDevice, 0);

you should use the !wdfusbinterface extension in wdfkd. it will show you all of the possible settings and the current selected setting. You should run the extension after the select config call and then immediate after the select interface call.

after all of this, i am not sure what is going wrong with your driver. if you could just state what is going wrong w/out code, that would help out…it looks like the interfaces are being selected properly. are you not getting data from your pipes? after you configure a continuous reader on a int/bulk pipe you must then call WdfIoTargetStart to start the reader. You cannot use a continuous reader on an isoch endpoint, but it is pretty easy to fmt your own URB and continuously send your own URB(s) to the device.

Sorry to belabor this, but the problem appears to be, when I select alternate interface 1, the continuous reader does not work for the int in endpoint. When stepping through the code with windbg there doesn’t appear to be anything wrong. I am using the default code with the osrusbfx2 WDF sample (with the exception of changing the one byte transfer to a 32 byte transfer in the appropriate places). They use the continuous reader to update the status of an 8-bit mechanical switch on their demo board.

If I don’t select the alternate 1 interface the reader works properly. I get a continuous stream on ep1 (32 bytes at a time). I have an LED on my dev board that fires if an INT in token triggers the USB ISR on the my dev board (my own, not OSRs). When not selecting alternate 1, the LED glows and data flows.

If I select alternate 1 (using the code you helped me with, thank you) and don’t execute WdfIoTargetStart to start the continuous reader, my usb analyzer states that alternate 1 has been chosen with device address 3 and 4 open pipes.

If I execute WdfIoTargetState after selecting alternate 1, I get in my USB analyzer an USBD status in the URB of USBD_STATUS_INVALID_PARAMETER (0x80000300) and the USB analyzer claims the device has address 0 (which is unconfigured) and 0 open pipes. But if I set breakpoints in windbg around before and after WdfIoTargetStart and execute the !wdfusbinterface, I get the following dump:

!wdfusbinterface 0x7dac9fb0
WDFUSBINTERFACE 7dac9fb0
Interface Number 0x00 Class 0xff, SubClass 0x00, Protocol 0x00
Alt Setting 0, Num Endpoints 4, Interface Desc 825e7619
Alt Setting 1, Num Endpoints 4, Interface Desc 825e763e, Selected
!WDFUSBPIPE 7d9fb1f0 Type UsbdPipeTypeIsochronous, Dir In, MaxPacket 0x10, MaxXfer 0x0
!WDFUSBPIPE 7da77e50 Type UsbdPipeTypeInterrupt, Dir In, MaxPacket 0x20, MaxXfer 0x0, Cont Reader
!WDFUSBPIPE 7da9abf0 Type UsbdPipeTypeInterrupt, Dir Out, MaxPacket 0x20, MaxXfer 0x0
!WDFUSBPIPE 7da4d430 Type UsbdPipeTypeIsochronous, Dir Out, MaxPacket 0x10, MaxXfer 0x0

Which the driver is saying has successfully changed to alternate 1.

ah, i see the problem. when you select another setting, all the previous WDFUSBPIPE endpoints are destroyed. even though there may be matching endpoint types in the new setting, they are represented by a new WDFUSBPIPE handle. this means that after selecting the new setting on the interface you will need to create a new continuous reader on the new WDFUSBPIPE and then call WdfIoTargetStart on the newly selected WDFUSBPIPE.

d

Interesting idea. In EvtDevicePrepareHardware, I am doing all the interface/alternate selection in a routine called SelectInterfaces. The alternate 1 selection has been set (and I confirm this with !wdfusbinterface in windbg), before calling code that sets up the continuous reader. I checked the values in the device context, everything seems correct. Also I never call WdfUsbInterfaceGetConfiguredPipe until after I make the alternate 1 switch in SelectInterfaces and then I assigned the pipe values to the context variables, IsoRead,IntRead, etc. In other words there shouldn’t ever be alternate 0 values for the pipes.

Since I want to do an isochronous continuous reader also, would it make sense to skip the built-in continuous reader for the int and do the custom reader by submitting URBs you mention before for both ischron and int?

after initializing and starting the continuous reader on your WDFUSBPIPE, run

!wdfkd.wdfusbpipe 0xFF

against the handle value, it should show you all pending i/o on the pipe. you should see N number of WDFREQUESTs where N is the number of readers you specified on the cont reader (2 by default if you didn’t configure it explicitly)

I would use built in functionality wherever i could, so i would use the cont reader on the int pipe.

d

OK. I did this.

Before the continuous reader is set up:

WDFUSBPIPE 7da79ab0

State: WdfIoTargetStarted

Requests waiting: 0

Requests sent: 0

Requests sent with ignore-target-state: 0

Type UsbdPipeTypeInterrupt
Direction In
MaxPacket 0x20, Max Transfer 0x0
Endpoint Address 0x82
USBD_PIPE_HANDLE 82544f3c

!WDFUSBDEVICE 7da77e70
!WDFUSBINTERFACE 7d9393b0

After the continuous reader is initialized (also checked in D0Entry routine where WdfIoTargetStart is called):

WDFUSBPIPE 7da79ab0

State: WdfIoTargetStarted

Requests waiting: 0

Requests sent: 0

Requests sent with ignore-target-state: 0

Type UsbdPipeTypeInterrupt
Direction In
MaxPacket 0x20, Max Transfer 0x0
Endpoint Address 0x82
USBD_PIPE_HANDLE 82544f3c

Continuous Reader (825db0f0):
Number of readers: 2
Repeaters are not submitted, either cancelled or not sent.
Read completion routine: mydriver!EvtUsbInterruptPipeReadComplete (eb719580)
Context 82509fd0
Repeater 825db128: WDFREQUEST 7dabb1b0 !irp 0x8235e008
Repeater 825db164: WDFREQUEST 7d9b90b0 !irp 0x825c1968

!WDFUSBDEVICE 7da77e70
!WDFUSBINTERFACE 7d9393b0

I set a breakpoint in the completion routine EvtUsbInterruptPipeReadComplete, it it never gets hit.

BTW, I noticed the state is “WdfIoTargetStarted”, something I never set until the D0Entry routine.

when targets are created, they are in the started state by default which is why you see WdfIoTargetStarted even though you never called WdfIoTargetStart. Once a cont reader is created, you need to call WdfIoTargetStart again, regardless of the current target’s state. Does !wdfusbpipe still say “Repeaters are not submitted, either cancelled or not sent.” after you call WdfIoTargetStart() in EvtDeviceD0Entry?

It says: “Repeaters are submitted and active” after executing WdfIoTargetStart.

The dump details follow:

Break point stopped on WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->IntReadPipe))
here is dump:
WDFUSBPIPE 7da69850

===========================
State: WdfIoTargetStarted

Requests waiting: 0

Requests sent: 0

Requests sent with ignore-target-state: 0

Type UsbdPipeTypeInterrupt
Direction In
MaxPacket 0x20, Max Transfer 0x0
Endpoint Address 0x82
USBD_PIPE_HANDLE 8255df3c

Continuous Reader (824f9430):
Number of readers: 2
Repeaters are not submitted, either cancelled or not sent.
Read completion routine: mydriver!EvtUsbInterruptPipeReadComplete (eb7d9580)
Context 826718b0
Repeater 824f9468: WDFREQUEST 7dc82c70 !irp 0x82543528
Repeater 824f94a4: WDFREQUEST 7da65c30 !irp 0x825d6348

!WDFUSBDEVICE 7da43710
!WDFUSBINTERFACE 7d9e1550

Push F10 to execute WdfIoTargetStart

Here is dump:
WDFUSBPIPE 7da69850

State: WdfIoTargetStarted

Requests waiting: 0

Requests sent: 0

Requests sent with ignore-target-state: 0

Type UsbdPipeTypeInterrupt
Direction In
MaxPacket 0x20, Max Transfer 0x0
Endpoint Address 0x82
USBD_PIPE_HANDLE 8255df3c

Continuous Reader (824f9430):
Number of readers: 2
Repeaters are submitted and active.
Read completion routine: mydriver!EvtUsbInterruptPipeReadComplete (eb7d9580)
Context 826718b0
Repeater 824f9468: WDFREQUEST 7dc82c70 !irp 0x82543528
Repeater 824f94a4: WDFREQUEST 7da65c30 !irp 0x825d6348

!WDFUSBDEVICE 7da43710
!WDFUSBINTERFACE 7d9e1550

Let me say I am doing all of this on Win2K with KDMF 1.1 if that helps

ah, the one thing i forgot to ask. there is a bug in KMDF v1.0 and 1.1 where we don’t set the Max Transfer size on alternate settings. this affects win2k only. If you can get KMDF v1.5 through the WDK beta, this problem has been fixed…or test on XP if you can.

d

Not really set up for XP for driver testing and windbg. I will get beta to get 1.5. Do I simply change the inf(inx) KmdfLibraryVersion to 1.5 and change all references from wdfcoinstaller01001 to wdfcoinstaller01005? Should I uninstall the device and reinstall with 1.5 or can I simply copy the new wdfcoinstaller into the appropriate directory after updating my inf?

Doron, thank you for all your help. I watched your channel 9 video and I say: those state machines!

Next up, trying to set up that continuous isochronous reader. You haven’t seen the last of me! :wink:

yes, you need to change both of those reference. then, you must unistall your driver and then reinstall using the new INF (make sure to pick the new INF and not the old one used to install v1.1).

glad you liked the video :wink:

d

I got the 5483 WDK installed on win2k. I had to use setup.exe, because I keep getting "The ordinal 6928 could not be found in mfc42u.dll mesage when running the installer.exe.

I noticed a) are no symbols for wdfcoinstaller01005 and b) there doesn’t appear to be a free version, it appears to be only a checked version, because I am getting the same error i got when I accidentally installed the checked version of 1.1 before.

I am not running a checked version of Win2k, so I it doesn’t run. Is there a x86fre version floating around on that DVD somewhere? Or can I download a couple of checked components and get around this? Or I am missing something?

I get a "This device is not configured correctly. (Code 1) on the final page of the Hardware install wizard.