the subclass and protocol interface descriptor fields must both be 1.
If
The
UsbKbd does need to store the pipe handle for the HID keyboard's interrupt pipe. For a HID USB keyboard, this is the first and only pipe in the USBD_INTERFACE_INFORMATION structure. UsbKbd makes
Listing 21.5 Selecting a configuration and interface
NTSTATUS UsbSelectConfiguration(IN PUSBKBD_DEVICE_EXTENSION dx) {
dx->UsbPipeHandle = NULL;
// Get all first configuration descriptors
PUSB_CONFIGURATIONDESCRIPTOR Descriptors = NULL;
ULONG size;
NTSTATUS status = UsbGetConfigurationDescriptors(dx, Descriptors, 0, size);
if (!NT_SUCCESS(status)) {
DebugPrint('UsbGetConfigurationDescriptors failed %x', status);
FreeIfAllocated(Descriptors);
return status;
}
// Search for an interface with HID keyboard device class
PUSB_INTERFACE_DESCRIPTOR id = USBD_ParseConfigurationDescriptorEx(Descriptors, Descriptors,
-1, –1, // Do not search by InterfaceNumber or AlternateSetting
3, 1, 1); // Search for a HID device, boot protocol, keyboard
if (id==NULL) {
DebugPrintMsg('No matching interface found');
FreeIfAllocated(Descriptors);
return STATUS_NO_SUCH_DEVICE;
}
// Build list of interfaces we are interested in
USBD_INTERFACE_LIST_ENTRY ilist[2];
ilist[0].InterfaceDescriptor = id;
ilist[0].Interface = NULL; // Will point to
// urb->UrbUsbSelectConfiguration.Interface
ilist[1].InterfaceDescriptor = NULL;
// Create select configuration URB
PURB urb = USBD_CreateConfigurationRequestEx(Descriptors, ilist);
// Call the USB driver
DebugPrintMsg('Select ing configuration');
status = CallUSBDI(dx, urb);
// Check statuses
if (!NT_SUCCESS(status) || !USBD_SUCCESS( urb->UrbHeader.Status)) {
DebugPrint('status %x URB status %x', status, urb->UrbHeader.Status);
status = STATUS_UNSUCCESSFUL;
} else {
// Select config worked
DebugPrintMsg('Select configuration worked');
dx->UsbConfigurationHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
// Find pipe handle of first pipe,
// ie interrupt pipe that returns input HID reports
PUSBD_INTERFACE_INFORMATION InterfaceInfo = &urb->UrbSelectConfiguration.Interface;
DebugPrint('interface Class %d NumberOfPipes %d', InterfaceInfo->Class, InterfaceInfo->NumberOfPipes);
if (InterfaceInfo->NumberOfPipes>0) {
PUSBD_PIPE_INFORMATION pi = &InterfaceInfo->Pipes[0];
dx->UsbPipeHandle = pi->PipeHandle;
DebugPrint('PipeHandle = %x', dx->UsbPipeHandle);
DebugPrint('Pipes[0] EndpointAddress %2x'
'Interval %dms PipeType %d MaximumTransferSize %c',
pi->EndpointAddress, pi->Interval, pi->PipeType, pi->MaximumTransferSize);
}
if (dx->UsbPipeHandle==NULL) status = STATUS_UNSUCCESSFUL;
}
FreeIfAllocated(urb);
FreeIfAllocated(Descriptors);
return status;
}
As mentioned earlier, having selected your configuration and interface, there may be some more steps needed to initialize your USB peripheral. You may want to read other descriptors. The UsbKbd Create IRP handler shows how this might be done by getting the first string descriptor. This in fact just returns the language ID that the device supports. You will have to issue further
The UsbKbd Create IRP handler,
Most USB device drivers will now want to talk to their devices over control or other pipes. Shortly, I describe how to perform such transfers.
When a driver wants to stop accessing its device, it should deselect its configuration. In UsbKbd, the Close file handle IRP handler does this job. The
The specification for UsbKbd says that it reports raw keyboard data in response to
Before I describe how to handle the Read IRPs, I must discuss how a USB HID keyboard produces data. The keyboard responds to USB Interrupt transfers with an 8-byte data report. The exact format of this block is discussed in the next chapter on Human Input Devices (HID).
A keyboard report is produced whenever a keypress or release occurs. A report is also produced regularly even if no keypresses occur. This is what happens on the USB bus. The USB class drivers initiate an Interrupt transfer regularly. My USB keyboard specifies that interrupt transfers should occur every 8ms. However, USB HID keyboards implement an idle rate. If there are no state changes during the idle period, the keyboard NAKs each Interrupt request. At the end of the idle period (every 500ms or so), the keyboard returns data regardless. The idle rate can be read and changed using class specific control transfers on the default pipe[53].
UsbKbd issues a