You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1741 lines
53 KiB
1741 lines
53 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
config.c
|
|
|
|
Abstract:
|
|
|
|
handles configuration and interface URBs
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
6-20-99 : created
|
|
|
|
--*/
|
|
|
|
#include "common.h"
|
|
|
|
// paged functions
|
|
#ifdef ALLOC_PRAGMA
|
|
//#pragma alloc_text(PAGE, USBPORT_SelectInterface)
|
|
#pragma alloc_text(PAGE, USBPORT_SelectConfiguration)
|
|
#pragma alloc_text(PAGE, USBPORT_InitializeConfigurationHandle)
|
|
#pragma alloc_text(PAGE, USBPORT_InternalOpenInterface)
|
|
#pragma alloc_text(PAGE, USBPORT_InternalCloseConfiguration)
|
|
#pragma alloc_text(PAGE, USBPORT_InternalParseConfigurationDescriptor)
|
|
#pragma alloc_text(PAGE, USBPORT_InternalGetInterfaceLength)
|
|
#endif
|
|
|
|
// non paged functions
|
|
|
|
USBD_PIPE_TYPE PipeTypes[4] = {UsbdPipeTypeControl, UsbdPipeTypeIsochronous,
|
|
UsbdPipeTypeBulk, UsbdPipeTypeInterrupt};
|
|
|
|
|
|
NTSTATUS
|
|
USBPORT_SelectInterface(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PIRP Irp,
|
|
PURB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select an alternate interface for a USB device. The orginal
|
|
USBD code only supported selecting a single alternate interface
|
|
so we will as well.
|
|
|
|
Client will(should) pass in a URB buffer that looks like this:
|
|
|
|
+------------------------------+
|
|
|Hdr |
|
|
|(_URB_HEADER) |
|
|
| - <caller inputs> |
|
|
| Function |
|
|
| Length |
|
|
| UsbdDeviceHandle |
|
|
| |
|
|
| - <port outputs> |
|
|
| Status |
|
|
+------------------------------+
|
|
| - <caller inputs> |
|
|
| ConfigurationHandle |
|
|
+------------------------------+
|
|
|Interface |
|
|
|(USBD_INTERFACE_INFORMATION) |
|
|
| - <caller inputs> |
|
|
| Length |
|
|
| InterfaceNumber |
|
|
| AlternateSetting |
|
|
| |
|
|
| - <port outputs> |
|
|
| InterfaceHandle |
|
|
| NumberOfPipes |
|
|
| SubClass |
|
|
| Class |
|
|
| Protocol |
|
|
+------------------------------+
|
|
|Pipes[0] | one of these for each pipe in the
|
|
|(USBD_PIPE_INFORMATION) | interface
|
|
| - <caller inputs> |
|
|
| PipeFlags |
|
|
| MaximumPacketSize (opt) |
|
|
| |
|
|
| - <port outputs> |
|
|
+------------------------------+
|
|
|Pipes[1] |
|
|
+------------------------------+
|
|
|.... |
|
|
+------------------------------+
|
|
|Pipes[n] |
|
|
+------------------------------+
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PUSBD_CONFIG_HANDLE configHandle = NULL;
|
|
ULONG i;
|
|
PDEVICE_EXTENSION devExt;
|
|
PUSBD_DEVICE_HANDLE deviceHandle;
|
|
PUSBD_INTERFACE_INFORMATION interfaceI;
|
|
PUSBD_INTERFACE_HANDLE_I iHandle, iHandleNew;
|
|
USHORT tmp;
|
|
USBD_STATUS usbdStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_HANDLE(deviceHandle, Urb);
|
|
LOCK_DEVICE(deviceHandle, FdoDeviceObject);
|
|
|
|
// validate the configuration handle input
|
|
configHandle = Urb->UrbSelectInterface.ConfigurationHandle;
|
|
ASSERT_CONFIG_HANDLE(configHandle);
|
|
|
|
//
|
|
// will are interested in the alt setting of a specific
|
|
// interface based on the interface number.
|
|
//
|
|
|
|
iHandle = NULL;
|
|
interfaceI = &Urb->UrbSelectInterface.Interface;
|
|
|
|
// validate the Length field in the Urb header, we can
|
|
// figure out the correct value based on the interface
|
|
// information passed in
|
|
tmp = interfaceI->Length + sizeof(struct _URB_HEADER)
|
|
+ sizeof(configHandle);
|
|
|
|
if (tmp != Urb->UrbHeader.Length) {
|
|
// client passed in bogus total length, warn if in
|
|
// 'verifier' mode.
|
|
|
|
USBPORT_DebugClient(
|
|
("client driver passed invalid Urb.Header.Length\n"));
|
|
|
|
// generally cleints mess up the header length so
|
|
// we will override with the length we calculated
|
|
// from the interface-information.
|
|
|
|
Urb->UrbHeader.Length = tmp;
|
|
}
|
|
|
|
// validate the interfaceI structure passed to us by the client
|
|
usbdStatus = USBPORT_InitializeInterfaceInformation(FdoDeviceObject,
|
|
interfaceI,
|
|
configHandle);
|
|
|
|
if (usbdStatus == USBD_STATUS_SUCCESS) {
|
|
|
|
// find the interface handle for the interface we are
|
|
// interested in, if it is currently open we will need
|
|
// to close it.
|
|
|
|
iHandle = USBPORT_GetInterfaceHandle(FdoDeviceObject,
|
|
configHandle,
|
|
interfaceI->InterfaceNumber);
|
|
|
|
if (iHandle != NULL) {
|
|
|
|
// unlink this handle
|
|
RemoveEntryList(&iHandle->InterfaceLink);
|
|
|
|
// we have a handle
|
|
|
|
ASSERT_INTERFACE(iHandle);
|
|
|
|
// close the pipes in this interface, note that we
|
|
// force the pipes closed unlike past versions of
|
|
// USBD and force the client driver to deal with the
|
|
// consequences if it has transfers outstanding.
|
|
|
|
// attempt to close all endpoints in this interface
|
|
for (i=0; i < iHandle->InterfaceDescriptor.bNumEndpoints; i++) {
|
|
|
|
USBPORT_ClosePipe(deviceHandle,
|
|
FdoDeviceObject,
|
|
&iHandle->PipeHandle[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now open the new interface with the new alternate setting
|
|
//
|
|
|
|
iHandleNew = NULL;
|
|
usbdStatus = USBPORT_InternalOpenInterface(Urb,
|
|
deviceHandle,
|
|
FdoDeviceObject,
|
|
configHandle,
|
|
interfaceI,
|
|
&iHandleNew,
|
|
TRUE);
|
|
}
|
|
|
|
if (usbdStatus == USBD_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// successfully opened the new interface,
|
|
// we can free the old handle now if we
|
|
// had one.
|
|
//
|
|
if (iHandle != NULL ) {
|
|
#if DBG
|
|
// all pipes should be closed
|
|
for (i=0; i < iHandle->InterfaceDescriptor.bNumEndpoints; i++) {
|
|
USBPORT_ASSERT(iHandle->PipeHandle[i].ListEntry.Flink == NULL &&
|
|
iHandle->PipeHandle[i].ListEntry.Blink == NULL);
|
|
}
|
|
#endif
|
|
FREE_POOL(FdoDeviceObject, iHandle);
|
|
iHandle = NULL;
|
|
}
|
|
|
|
// return the 'new' handle
|
|
interfaceI->InterfaceHandle = iHandleNew;
|
|
|
|
// associate it with this configuration
|
|
InsertTailList(&configHandle->InterfaceHandleList,
|
|
&iHandleNew->InterfaceLink);
|
|
|
|
} else {
|
|
|
|
//
|
|
// selecting the aternate interface failed.
|
|
// Possible reasons:
|
|
//
|
|
// 1. we didn't have enough BW
|
|
// 2. the device stalled the set_interface request
|
|
// 3. The set_interface request failed because the
|
|
// device is gone
|
|
// 4. USBPORT_InitializeInterfaceInformation() failed due
|
|
// bad parameters.
|
|
|
|
// attempt to re-open the original alt-interface so that
|
|
// the client still has the bandwidth
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'slI!',
|
|
usbdStatus,
|
|
0,
|
|
0);
|
|
|
|
if (usbdStatus == USBD_STATUS_NO_BANDWIDTH) {
|
|
|
|
// HISTORICAL NOTE:
|
|
// The 2k USBD driver attempted to re-open the original
|
|
// alt-setting on a failure to allocate bw. This would
|
|
// leave the client with the bw it had when calling in
|
|
// to select the new interface.
|
|
//
|
|
// I don't beleive that any drivers use this feature
|
|
// and many drivers attempt to allocate BW in a loop
|
|
// until they succeed.
|
|
//
|
|
// So as a performance optimization we will return
|
|
// with no bandwidth allocated to the caller -- the
|
|
// pipe handles will be invalid.
|
|
// This should speed things up since the realloc of
|
|
// the old bandwidth takes time.
|
|
interfaceI->InterfaceHandle = USBPORT_BAD_HANDLE;
|
|
|
|
} else {
|
|
// case 2,3 we just fail the request and set the interface
|
|
// handle to 'bad handle'
|
|
interfaceI->InterfaceHandle = USBPORT_BAD_HANDLE;
|
|
}
|
|
|
|
// client has no reference to it and we closed it
|
|
// free the structure here
|
|
if (iHandle != NULL ) {
|
|
#if DBG
|
|
// all pipes should be closed
|
|
for (i=0; i < iHandle->InterfaceDescriptor.bNumEndpoints; i++) {
|
|
USBPORT_ASSERT(iHandle->PipeHandle[i].ListEntry.Flink == NULL &&
|
|
iHandle->PipeHandle[i].ListEntry.Blink == NULL);
|
|
}
|
|
#endif
|
|
FREE_POOL(FdoDeviceObject, iHandle);
|
|
iHandle = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
UNLOCK_DEVICE(deviceHandle, FdoDeviceObject);
|
|
|
|
ntStatus = SET_USBD_ERROR(Urb, usbdStatus);
|
|
|
|
return ntStatus;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
USBPORT_SelectConfiguration(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PIRP Irp,
|
|
PURB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open a configuration for a USB device.
|
|
|
|
Client will(should) pass in a URB buffer that looks like this:
|
|
|
|
+------------------------------+
|
|
|Hdr |
|
|
|(_URB_HEADER) |
|
|
| - <caller inputs> |
|
|
| Function |
|
|
| Length |
|
|
| UsbdDeviceHandle |
|
|
| |
|
|
| - <port outputs> |
|
|
| Status |
|
|
+------------------------------+
|
|
| - <caller inputs> |
|
|
| ConfigurationDescriptor |
|
|
| - <port outputs> |
|
|
| ConfigurationHandle |
|
|
+------------------------------+
|
|
|Interface(0) |
|
|
|(USBD_INTERFACE_INFORMATION) |
|
|
| - <caller inputs> |
|
|
| Length |
|
|
| InterfaceNumber |
|
|
| AlternateSetting |
|
|
| |
|
|
| - <port outputs> |
|
|
| InterfaceHandle |
|
|
| NumberOfPipes |
|
|
| SubClass |
|
|
| Class |
|
|
| Protocol |
|
|
+------------------------------+
|
|
|Pipes[0] | one of these for each pipe in the
|
|
|(USBD_PIPE_INFORMATION) | interface
|
|
| - <caller inputs> |
|
|
| |
|
|
| - <port outputs> |
|
|
+------------------------------+
|
|
|Pipes[1] |
|
|
+------------------------------+
|
|
|.... |
|
|
+------------------------------+
|
|
|Pipes[n] |
|
|
+------------------------------+
|
|
| Interface(1) | one of these for each interface in
|
|
| | the configuration
|
|
+------------------------------+
|
|
|Pipes[1] |
|
|
+------------------------------+
|
|
|.... |
|
|
+------------------------------+
|
|
|Pipes[n] |
|
|
+------------------------------+
|
|
|
|
On input:
|
|
The ConfigurationDescriptor must specify the number of interfaces
|
|
in the configuration.
|
|
|
|
The InterfaceInformation will specify a specific alt setting to be
|
|
selected for each interface.
|
|
|
|
1. First we look at the configuration descriptor for the
|
|
requested configuration and validate the client
|
|
input buffer agianst it.
|
|
|
|
2. We open the interfaces for the requested configuration
|
|
and open the pipes within those interfaces, setting
|
|
alt settings were appropriate.
|
|
|
|
3. We set the configuration for the device with the
|
|
appropriate control request.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
Irp - IO request block
|
|
|
|
Urb - ptr to USB request block
|
|
|
|
IrpIsPending -
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PUSBD_CONFIG_HANDLE configHandle = NULL;
|
|
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
|
|
PUSBD_INTERFACE_INFORMATION interfaceInformation;
|
|
PUCHAR pch;
|
|
ULONG i;
|
|
PDEVICE_EXTENSION devExt;
|
|
ULONG numInterfaces;
|
|
PUCHAR end;
|
|
PUSBD_DEVICE_HANDLE deviceHandle;
|
|
USBD_STATUS usbdStatus;
|
|
USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
|
|
|
|
PAGED_CODE();
|
|
USBPORT_KdPrint((2, "' enter USBPORT_SelectConfiguration\n"));
|
|
|
|
GET_DEVICE_EXT(devExt, FdoDeviceObject);
|
|
ASSERT_FDOEXT(devExt);
|
|
|
|
GET_DEVICE_HANDLE(deviceHandle, Urb);
|
|
LOCK_DEVICE(deviceHandle, FdoDeviceObject);
|
|
|
|
ntStatus = STATUS_BOGUS;
|
|
|
|
// BUGBUG
|
|
// flush all current transfers or fail?
|
|
|
|
//
|
|
// dump old configuration data if we have any
|
|
//
|
|
|
|
if (deviceHandle->ConfigurationHandle) {
|
|
|
|
// This is where we close the old configuration
|
|
// handle, all pipes and all interfaces.
|
|
|
|
USBPORT_InternalCloseConfiguration(deviceHandle,
|
|
FdoDeviceObject,
|
|
0);
|
|
}
|
|
|
|
// now set up the new configuration
|
|
|
|
configurationDescriptor =
|
|
Urb->UrbSelectConfiguration.ConfigurationDescriptor;
|
|
|
|
//
|
|
// if null pased in set configuration to 0
|
|
// 'unconfigured'
|
|
//
|
|
|
|
if (configurationDescriptor == NULL) {
|
|
|
|
// device needs to be in the unconfigured state
|
|
|
|
//
|
|
// NOTE:
|
|
// this may fail if the configuration is being
|
|
// closed as the result of the device being unplugged
|
|
// so we ignore the error
|
|
//
|
|
|
|
USBPORT_INIT_SETUP_PACKET(setupPacket,
|
|
USB_REQUEST_SET_CONFIGURATION, // bRequest
|
|
BMREQUEST_HOST_TO_DEVICE, // Dir
|
|
BMREQUEST_TO_DEVICE, // Recipient
|
|
BMREQUEST_STANDARD, // Type
|
|
0, // wValue
|
|
0, // wIndex
|
|
0); // wLength
|
|
|
|
USBPORT_SendCommand(deviceHandle,
|
|
FdoDeviceObject,
|
|
&setupPacket,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
ntStatus = SET_USBD_ERROR(Urb, USBD_STATUS_SUCCESS);
|
|
|
|
goto USBD_SelectConfiguration_Done;
|
|
|
|
} else {
|
|
// validate the config descriptor by accessing it
|
|
//
|
|
// Note: that we we will still crash here if the config
|
|
// descriptor is invalid. However is will be easiser to
|
|
// debug this way.
|
|
//
|
|
//
|
|
//
|
|
|
|
PUCHAR tmp;
|
|
UCHAR ch;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'vCNF',
|
|
configurationDescriptor,
|
|
0,
|
|
0);
|
|
|
|
// first a quick sanity check, it must be non-zero
|
|
if (configurationDescriptor->wTotalLength == 0) {
|
|
// this is bogus
|
|
ntStatus = SET_USBD_ERROR(Urb,
|
|
USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR);
|
|
|
|
goto USBD_SelectConfiguration_Done;
|
|
|
|
} else {
|
|
// touch first and last byte, this wil fault if invalid.
|
|
|
|
tmp = (PUCHAR) configurationDescriptor;
|
|
ch = *tmp;
|
|
tmp += configurationDescriptor->wTotalLength-1;
|
|
ch = *tmp;
|
|
|
|
}
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'CFok',
|
|
configurationDescriptor,
|
|
0,
|
|
0);
|
|
}
|
|
|
|
//
|
|
// count the number of interfaces to process in this
|
|
// request
|
|
//
|
|
|
|
pch = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
|
|
numInterfaces = 0;
|
|
end = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length;
|
|
|
|
do {
|
|
numInterfaces++;
|
|
|
|
interfaceInformation = (PUSBD_INTERFACE_INFORMATION) pch;
|
|
pch+=interfaceInformation->Length;
|
|
|
|
} while (pch < end);
|
|
|
|
USBPORT_KdPrint((2, "'USBD_SelectConfiguration -- %d interfaces\n",
|
|
numInterfaces));
|
|
|
|
// sanity check the config descriptor with the URB request
|
|
if (numInterfaces != configurationDescriptor->bNumInterfaces ||
|
|
numInterfaces == 0) {
|
|
//
|
|
// driver is broken, config request does not match
|
|
// config descriptor passed in!!!
|
|
//
|
|
USBPORT_DebugClient((
|
|
"config request does not match config descriptor\n"));
|
|
ntStatus = SET_USBD_ERROR(Urb,
|
|
USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR);
|
|
|
|
TC_TRAP();
|
|
|
|
goto USBD_SelectConfiguration_Done;
|
|
}
|
|
|
|
//
|
|
// Allocate a configuration handle and
|
|
// verify there is enough room to store
|
|
// all the information in the client buffer.
|
|
//
|
|
|
|
configHandle = USBPORT_InitializeConfigurationHandle(deviceHandle,
|
|
FdoDeviceObject,
|
|
configurationDescriptor);
|
|
if (configHandle == NULL) {
|
|
USBPORT_DebugClient((
|
|
"failed to allocate config handle\n"));
|
|
ntStatus = SET_USBD_ERROR(Urb,
|
|
USBD_STATUS_INSUFFICIENT_RESOURCES);
|
|
|
|
goto USBD_SelectConfiguration_Done;
|
|
}
|
|
|
|
//
|
|
// Send the 'set configuration' command
|
|
//
|
|
|
|
USBPORT_INIT_SETUP_PACKET(setupPacket,
|
|
USB_REQUEST_SET_CONFIGURATION, // bRequest
|
|
BMREQUEST_HOST_TO_DEVICE, // Dir
|
|
BMREQUEST_TO_DEVICE, // Recipient
|
|
BMREQUEST_STANDARD, // Type
|
|
configurationDescriptor->bConfigurationValue, // wValue
|
|
0, // wIndex
|
|
0); // wLength
|
|
|
|
|
|
USBPORT_SendCommand(deviceHandle,
|
|
FdoDeviceObject,
|
|
&setupPacket,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&usbdStatus);
|
|
|
|
USBPORT_KdPrint((2,"' SendCommand, SetConfiguration returned 0x%x\n", usbdStatus));
|
|
|
|
if (USBD_ERROR(usbdStatus)) {
|
|
USBPORT_DebugClient((
|
|
"failed to 'set' the configuration\n"));
|
|
ntStatus = SET_USBD_ERROR(Urb,
|
|
USBD_STATUS_SET_CONFIG_FAILED);
|
|
TC_TRAP();
|
|
goto USBD_SelectConfiguration_Done;
|
|
}
|
|
|
|
USBPORT_ASSERT(ntStatus == STATUS_BOGUS);
|
|
|
|
// we have "configured" the device in the USB sense.
|
|
|
|
//
|
|
// User buffer checks out and we have 'configured'
|
|
// the device.
|
|
// Now parse thru the configuration descriptor
|
|
// and open the interfaces.
|
|
//
|
|
// The URB contains a set of INTERFACE_INFORMATION
|
|
// structures these give us the information we need
|
|
// to open the pipes
|
|
/*
|
|
|
|
_USBD_INTERFACE_INFORMATION
|
|
client should have filled in:
|
|
|
|
USHORT Length;
|
|
UCHAR InterfaceNumber;
|
|
UCHAR AlternateSetting;
|
|
|
|
we fill in :
|
|
UCHAR Class;
|
|
UCHAR SubClass;
|
|
UCHAR Protocol;
|
|
UCHAR Reserved;
|
|
|
|
USBD_INTERFACE_HANDLE InterfaceHandle;
|
|
ULONG NumberOfPipes;
|
|
|
|
*/
|
|
|
|
pch = (PUCHAR) &Urb->UrbSelectConfiguration.Interface;
|
|
|
|
for (i=0; i<numInterfaces; i++) {
|
|
PUSBD_INTERFACE_HANDLE_I interfaceHandle;
|
|
// open the interface
|
|
|
|
interfaceInformation = (PUSBD_INTERFACE_INFORMATION) pch;
|
|
|
|
usbdStatus = USBPORT_InitializeInterfaceInformation(
|
|
FdoDeviceObject,
|
|
interfaceInformation,
|
|
configHandle);
|
|
|
|
interfaceHandle = NULL;
|
|
if (usbdStatus == USBD_STATUS_SUCCESS) {
|
|
|
|
// this function allocates the actual 'handle'
|
|
usbdStatus = USBPORT_InternalOpenInterface(Urb,
|
|
deviceHandle,
|
|
FdoDeviceObject,
|
|
configHandle,
|
|
interfaceInformation,
|
|
&interfaceHandle,
|
|
TRUE);
|
|
USBPORT_KdPrint((2, "' InternalOpenInterface returned(USBD) 0x%x\n",
|
|
usbdStatus));
|
|
}
|
|
|
|
pch+=interfaceInformation->Length;
|
|
|
|
// if we got back a handle add it to the list
|
|
if (interfaceHandle != NULL) {
|
|
InsertTailList(&configHandle->InterfaceHandleList,
|
|
&interfaceHandle->InterfaceLink);
|
|
}
|
|
|
|
if (!USBD_SUCCESS(usbdStatus)) {
|
|
|
|
ntStatus = SET_USBD_ERROR(Urb, usbdStatus);
|
|
|
|
// we have an error opening the interface
|
|
DEBUG_BREAK();
|
|
TC_TRAP();
|
|
goto USBD_SelectConfiguration_Done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// interfaces were successfully set up then return success.
|
|
//
|
|
|
|
ntStatus = SET_USBD_ERROR(Urb, USBD_STATUS_SUCCESS);
|
|
|
|
USBD_SelectConfiguration_Done:
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
USBPORT_ASSERT(Urb->UrbSelectConfiguration.Hdr.Status ==
|
|
USBD_STATUS_SUCCESS);
|
|
|
|
Urb->UrbSelectConfiguration.ConfigurationHandle =
|
|
configHandle;
|
|
|
|
// remember the current configuration
|
|
deviceHandle->ConfigurationHandle = configHandle;
|
|
|
|
} else {
|
|
|
|
//
|
|
// something failed, clean up before we return an error.
|
|
//
|
|
|
|
if (configHandle) {
|
|
|
|
TC_TRAP();
|
|
ASSERT_DEVICE_HANDLE(deviceHandle);
|
|
|
|
//
|
|
// if we have a configHandle then we need to free it
|
|
deviceHandle->ConfigurationHandle =
|
|
configHandle;
|
|
|
|
//
|
|
// attempt to close it
|
|
//
|
|
|
|
USBPORT_InternalCloseConfiguration(deviceHandle,
|
|
FdoDeviceObject,
|
|
0);
|
|
|
|
deviceHandle->ConfigurationHandle = NULL;
|
|
}
|
|
|
|
// make sure we return an error in the URB.
|
|
USBPORT_ASSERT(Urb->UrbSelectConfiguration.Hdr.Status !=
|
|
USBD_STATUS_SUCCESS);
|
|
USBPORT_KdPrint((2, "'Failing SelectConfig\n"));
|
|
}
|
|
|
|
UNLOCK_DEVICE(deviceHandle, FdoDeviceObject);
|
|
|
|
USBPORT_KdPrint((2, "'exit SelectConfiguration 0x%x\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
PUSBD_CONFIG_HANDLE
|
|
USBPORT_InitializeConfigurationHandle(
|
|
PUSBD_DEVICE_HANDLE DeviceHandle,
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the configuration handle structure.
|
|
|
|
Given a (hopefully) valid configuration descriptor
|
|
and a count of the interfaces create the configuration
|
|
handle for the device
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PUSBD_CONFIG_HANDLE configHandle = NULL;
|
|
ULONG i;
|
|
PUCHAR pch;
|
|
|
|
PAGED_CODE();
|
|
USBPORT_ASSERT(ConfigurationDescriptor->bNumInterfaces > 0);
|
|
|
|
USBPORT_KdPrint((2, "' enter InitializeConfigurationHandle\n"));
|
|
|
|
// get enough space for each interface
|
|
ALLOC_POOL_Z(configHandle,
|
|
NonPagedPool,
|
|
sizeof(USBD_CONFIG_HANDLE) +
|
|
ConfigurationDescriptor->wTotalLength);
|
|
|
|
pch = (PUCHAR)configHandle;
|
|
|
|
if (configHandle) {
|
|
|
|
//
|
|
// Initilaize the interface handle list
|
|
//
|
|
|
|
InitializeListHead(&configHandle->InterfaceHandleList);
|
|
|
|
configHandle->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)
|
|
(pch + sizeof(USBD_CONFIG_HANDLE));
|
|
|
|
// copy the config descriptor to our handle
|
|
|
|
RtlCopyMemory(configHandle->ConfigurationDescriptor,
|
|
ConfigurationDescriptor,
|
|
ConfigurationDescriptor->wTotalLength);
|
|
|
|
configHandle->Sig = SIG_CONFIG_HANDLE;
|
|
|
|
}
|
|
|
|
USBPORT_KdPrint((2, "' exit InitializeConfigurationHandle 0x%x\n",
|
|
configHandle));
|
|
|
|
return configHandle;
|
|
}
|
|
|
|
|
|
USBD_STATUS
|
|
USBPORT_InternalOpenInterface(
|
|
PURB Urb,
|
|
PUSBD_DEVICE_HANDLE DeviceHandle,
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSBD_CONFIG_HANDLE ConfigHandle,
|
|
PUSBD_INTERFACE_INFORMATION InterfaceInformation,
|
|
PUSBD_INTERFACE_HANDLE_I *InterfaceHandle,
|
|
BOOLEAN SendSetInterfaceCommand
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
DeviceHandle - USBD device handle for this device.
|
|
|
|
ConfigHandle - USBD configuration handle.
|
|
|
|
InterfaceInformation - pointer to USBD interface information structure
|
|
passed in by the client.
|
|
|
|
We use the InterfaceNumber and AlternateSetting specified
|
|
in this structure to select the interface.
|
|
|
|
On success the .Length field is filled in with the actual length
|
|
of the interface_information structure and the Pipe[] fields are filled
|
|
in with the handles for the opened pipes.
|
|
|
|
InterfaceHandle - pointer to an interface handle pointer, filled in
|
|
with the allocated interface handle structure if NULL, otherwise the
|
|
structure passed in is used.
|
|
|
|
SendSetInterfaceCommand - indicates if the set_interface command should be
|
|
sent.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
|
|
BOOLEAN hasAlternateSettings;
|
|
PUSBD_INTERFACE_HANDLE_I interfaceHandle = NULL;
|
|
PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
|
|
PUCHAR pch;
|
|
ULONG i;
|
|
BOOLEAN allocated = FALSE;
|
|
PUSB_COMMON_DESCRIPTOR descriptor;
|
|
USHORT need;
|
|
ULONG numEndpoints;
|
|
USB_DEFAULT_PIPE_SETUP_PACKET setupPacket;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT_CONFIG_HANDLE(ConfigHandle);
|
|
|
|
if (*InterfaceHandle != NULL) {
|
|
// using a previously allocated interface handle
|
|
ASSERT_INTERFACE_HANDLE(*InterfaceHandle);
|
|
TEST_TRAP();
|
|
}
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'opIF',
|
|
InterfaceInformation->InterfaceNumber,
|
|
InterfaceInformation->AlternateSetting,
|
|
*InterfaceHandle);
|
|
|
|
USBPORT_KdPrint((2, "' enter InternalOpenInterface\n"));
|
|
USBPORT_KdPrint((2, "' Interface %d Altsetting %d\n",
|
|
InterfaceInformation->InterfaceNumber,
|
|
InterfaceInformation->AlternateSetting));
|
|
|
|
//
|
|
// Find the interface descriptor we are interested in inside
|
|
// the configuration descriptor.
|
|
//
|
|
|
|
interfaceDescriptor =
|
|
USBPORT_InternalParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor,
|
|
InterfaceInformation->InterfaceNumber,
|
|
InterfaceInformation->AlternateSetting,
|
|
&hasAlternateSettings);
|
|
|
|
// we already validated this, if it is NULL
|
|
// the function has a bug.
|
|
USBPORT_ASSERT(interfaceDescriptor != NULL);
|
|
if (interfaceDescriptor == NULL) {
|
|
BUGCHECK(USBBUGCODE_INTERNAL_ERROR, (ULONG_PTR) DeviceHandle, 0, 0);
|
|
// keep prefix scanner happy
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// We got the interface descriptor, now try
|
|
// to open all the pipes.
|
|
//
|
|
|
|
// found the requested interface in the configuration descriptor.
|
|
|
|
|
|
numEndpoints = interfaceDescriptor->bNumEndpoints;
|
|
need = (USHORT) (((numEndpoints-1) * sizeof(USBD_PIPE_INFORMATION) +
|
|
sizeof(USBD_INTERFACE_INFORMATION)));
|
|
|
|
// we should have already validated this
|
|
USBPORT_ASSERT(InterfaceInformation->Length == need);
|
|
|
|
if (hasAlternateSettings &&
|
|
SendSetInterfaceCommand) {
|
|
|
|
NTSTATUS ntStatus;
|
|
//
|
|
// If we have alternate settings we need
|
|
// to send the set interface command.
|
|
//
|
|
|
|
USBPORT_INIT_SETUP_PACKET(setupPacket,
|
|
USB_REQUEST_SET_INTERFACE, // bRequest
|
|
BMREQUEST_HOST_TO_DEVICE, // Dir
|
|
BMREQUEST_TO_INTERFACE, // Recipient
|
|
BMREQUEST_STANDARD, // Type
|
|
InterfaceInformation->AlternateSetting, // wValue
|
|
InterfaceInformation->InterfaceNumber, // wIndex
|
|
0); // wLength
|
|
|
|
|
|
ntStatus = USBPORT_SendCommand(DeviceHandle,
|
|
FdoDeviceObject,
|
|
&setupPacket,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&usbdStatus);
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'seIF',
|
|
ntStatus,
|
|
InterfaceInformation->AlternateSetting,
|
|
InterfaceInformation->InterfaceNumber);
|
|
|
|
if (USBD_ERROR(usbdStatus)) {
|
|
DEBUG_BREAK();
|
|
goto USBPORT_InternalOpenInterface_Done;
|
|
}
|
|
|
|
USBPORT_ASSERT(ntStatus == STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
//
|
|
// we successfully selected the alternate interface
|
|
// initialize the interface handle and open the pipes
|
|
//
|
|
|
|
if (*InterfaceHandle == NULL) {
|
|
|
|
ULONG privateLength = sizeof(USBD_INTERFACE_HANDLE_I) +
|
|
sizeof(USBD_PIPE_HANDLE_I) * numEndpoints;
|
|
|
|
// allow space for a copy of the USBD_INTERFACE_INFORMATION
|
|
// that is returned to the client
|
|
ALLOC_POOL_Z(interfaceHandle,
|
|
NonPagedPool,
|
|
privateLength);
|
|
|
|
if (interfaceHandle != NULL) {
|
|
// initialize the pipe handles to a known state
|
|
for (i=0; i<numEndpoints; i++) {
|
|
interfaceHandle->PipeHandle[i].Endpoint = NULL;
|
|
interfaceHandle->PipeHandle[i].Sig = SIG_PIPE_HANDLE;
|
|
interfaceHandle->PipeHandle[i].PipeStateFlags =
|
|
USBPORT_PIPE_STATE_CLOSED;
|
|
//interfaceHandle->PipeHandle[i].ListEntry.Flink = NULL;
|
|
//interfaceHandle->PipeHandle[i].ListEntry.Blink = NULL;
|
|
}
|
|
allocated = TRUE;
|
|
} else {
|
|
|
|
usbdStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto USBPORT_InternalOpenInterface_Done;
|
|
}
|
|
|
|
} else {
|
|
// using old handle
|
|
interfaceHandle = *InterfaceHandle;
|
|
}
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'ihIF',
|
|
interfaceHandle,
|
|
0,
|
|
0);
|
|
|
|
USBPORT_ASSERT(interfaceHandle != NULL);
|
|
|
|
interfaceHandle->Sig = SIG_INTERFACE_HANDLE;
|
|
interfaceHandle->HasAlternateSettings = hasAlternateSettings;
|
|
|
|
InterfaceInformation->NumberOfPipes =
|
|
interfaceDescriptor->bNumEndpoints;
|
|
InterfaceInformation->Class =
|
|
interfaceDescriptor->bInterfaceClass;
|
|
InterfaceInformation->SubClass =
|
|
interfaceDescriptor->bInterfaceSubClass;
|
|
InterfaceInformation->Protocol =
|
|
interfaceDescriptor->bInterfaceProtocol;
|
|
InterfaceInformation->Reserved = 0;
|
|
|
|
// start with first endpoint
|
|
// skip over any non-endpoint descriptors
|
|
pch = (PUCHAR) (interfaceDescriptor) +
|
|
interfaceDescriptor->bLength;
|
|
|
|
// initialize the pipe fields for this interfacae
|
|
|
|
// assume success
|
|
usbdStatus = USBD_STATUS_SUCCESS;
|
|
|
|
interfaceHandle->InterfaceDescriptor = *interfaceDescriptor;
|
|
for (i=0; i<numEndpoints; i++) {
|
|
USB_HIGH_SPEED_MAXPACKET muxPacket;
|
|
|
|
descriptor = (PUSB_COMMON_DESCRIPTOR) pch;
|
|
while (descriptor->bDescriptorType !=
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE) {
|
|
if (descriptor->bLength == 0) {
|
|
break; // Don't loop forever
|
|
}
|
|
pch += descriptor->bLength;
|
|
descriptor = (PUSB_COMMON_DESCRIPTOR) pch;
|
|
}
|
|
|
|
endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) pch;
|
|
USBPORT_ASSERT(endpointDescriptor->bDescriptorType ==
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE);
|
|
|
|
// initial state is CLOSED
|
|
interfaceHandle->PipeHandle[i].PipeStateFlags =
|
|
USBPORT_PIPE_STATE_CLOSED;
|
|
interfaceHandle->PipeHandle[i].Endpoint = NULL;
|
|
|
|
// init pipe flags
|
|
interfaceHandle->PipeHandle[i].UsbdPipeFlags =
|
|
InterfaceInformation->Pipes[i].PipeFlags;
|
|
|
|
if (InterfaceInformation->Pipes[i].PipeFlags &
|
|
USBD_PF_CHANGE_MAX_PACKET) {
|
|
// client wants to override original max_packet
|
|
// size in endpoint descriptor
|
|
endpointDescriptor->wMaxPacketSize =
|
|
InterfaceInformation->Pipes[i].MaximumPacketSize;
|
|
|
|
USBPORT_KdPrint((2,
|
|
"'new bMaxPacket 0x%x\n", endpointDescriptor->wMaxPacketSize));
|
|
}
|
|
|
|
//
|
|
// copy the endpoint descriptor into the
|
|
// pipe handle structure.
|
|
//
|
|
|
|
RtlCopyMemory(&interfaceHandle->PipeHandle[i].EndpointDescriptor,
|
|
pch,
|
|
sizeof(interfaceHandle->PipeHandle[i].EndpointDescriptor) );
|
|
|
|
// advance to next endpoint
|
|
// first field in endpoint descriptor is length
|
|
pch += endpointDescriptor->bLength;
|
|
|
|
//
|
|
// return information about the pipe
|
|
//
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'ipIF',
|
|
interfaceHandle,
|
|
i,
|
|
&interfaceHandle->PipeHandle[i]);
|
|
|
|
InterfaceInformation->Pipes[i].EndpointAddress =
|
|
endpointDescriptor->bEndpointAddress;
|
|
InterfaceInformation->Pipes[i].PipeType =
|
|
PipeTypes[endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK];
|
|
muxPacket.us = endpointDescriptor->wMaxPacketSize;
|
|
InterfaceInformation->Pipes[i].MaximumPacketSize =
|
|
muxPacket.MaxPacket * (muxPacket.HSmux+1);
|
|
InterfaceInformation->Pipes[i].Interval =
|
|
endpointDescriptor->bInterval;
|
|
|
|
InterfaceInformation->Pipes[i].PipeHandle =
|
|
USBPORT_BAD_HANDLE;
|
|
|
|
} /* end for numEndpoints */
|
|
|
|
if (usbdStatus != USBD_STATUS_SUCCESS) {
|
|
// if we got an error bail now
|
|
// we will return with the structure
|
|
// initailized but no open pipes
|
|
goto USBPORT_InternalOpenInterface_Done;
|
|
}
|
|
|
|
// all pipe handle fields initialized and
|
|
// urb structure has been filled in
|
|
|
|
// now loop thru and open the pipes
|
|
for (i=0; i<interfaceDescriptor->bNumEndpoints; i++) {
|
|
NTSTATUS ntStatus;
|
|
|
|
ntStatus = USBPORT_OpenEndpoint(DeviceHandle,
|
|
FdoDeviceObject,
|
|
&interfaceHandle->PipeHandle[i],
|
|
&usbdStatus,
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
// if success set the pipe handle for client
|
|
InterfaceInformation->Pipes[i].PipeHandle =
|
|
&interfaceHandle->PipeHandle[i];
|
|
USBPORT_KdPrint((2, "'pipe handle = 0x%x\n",
|
|
InterfaceInformation->Pipes[i].PipeHandle ));
|
|
|
|
} else {
|
|
|
|
USBPORT_KdPrint((1,
|
|
"'error opening one of the pipes in interface (%x)\n", usbdStatus));
|
|
ntStatus = SET_USBD_ERROR(Urb, usbdStatus);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
USBPORT_InternalOpenInterface_Done:
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'oIFd',
|
|
InterfaceInformation->InterfaceNumber,
|
|
InterfaceInformation->AlternateSetting,
|
|
usbdStatus);
|
|
|
|
if (USBD_SUCCESS(usbdStatus)) {
|
|
|
|
//
|
|
// successfully opened the interface, return the handle
|
|
// to it
|
|
//
|
|
|
|
*InterfaceHandle =
|
|
InterfaceInformation->InterfaceHandle = interfaceHandle;
|
|
|
|
//
|
|
// set the length properly, the value we already
|
|
// calculated
|
|
//
|
|
|
|
InterfaceInformation->Length = (USHORT) need;
|
|
|
|
} else {
|
|
|
|
//
|
|
// had a problem, go back thru and close anything we opened.
|
|
//
|
|
|
|
if (interfaceHandle) {
|
|
|
|
for (i=0; i<numEndpoints; i++) {
|
|
|
|
USBPORT_KdPrint((2, "'open interface cleanup -- closing endpoint %x\n",
|
|
&interfaceHandle->PipeHandle[i]));
|
|
|
|
// fortunately this cannot fail
|
|
USBPORT_ClosePipe(DeviceHandle,
|
|
FdoDeviceObject,
|
|
&interfaceHandle->PipeHandle[i]);
|
|
|
|
}
|
|
|
|
if (allocated) {
|
|
FREE_POOL(FdoDeviceObject, interfaceHandle);
|
|
interfaceHandle = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
USBPORT_KdPrint((3, "' exit InternalOpenInterface 0x%x\n", usbdStatus));
|
|
|
|
return usbdStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
USBPORT_InternalCloseConfiguration(
|
|
PUSBD_DEVICE_HANDLE DeviceHandle,
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
ULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes the current configuration for a device.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
this function cannot fail
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG i, j;
|
|
PUSBD_CONFIG_HANDLE configHandle = NULL;
|
|
BOOLEAN retry = TRUE;
|
|
ULONG interfaceCount;
|
|
|
|
PAGED_CODE();
|
|
|
|
// device handle MUST be valid
|
|
ASSERT_DEVICE_HANDLE(DeviceHandle);
|
|
configHandle = DeviceHandle->ConfigurationHandle;
|
|
|
|
if (configHandle == NULL) {
|
|
// device is not configured
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'nCFG', 0, 0, DeviceHandle);
|
|
goto USBPORT_InternalCloseConfiguration_Done;
|
|
}
|
|
|
|
ASSERT_CONFIG_HANDLE(configHandle);
|
|
interfaceCount = configHandle->ConfigurationDescriptor->bNumInterfaces;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject,
|
|
LOG_PNP, 'cCFG', interfaceCount, 0, configHandle);
|
|
|
|
// we ensure that all transfers are aborted for the device handle
|
|
// before calling this function so the close configuration will
|
|
// not fail
|
|
|
|
|
|
// do the cleanup
|
|
|
|
while (!IsListEmpty(&configHandle->InterfaceHandleList)) {
|
|
|
|
//
|
|
// found an open interface, close it
|
|
//
|
|
|
|
PUSBD_INTERFACE_HANDLE_I iHandle;
|
|
ULONG endpointCount;
|
|
PLIST_ENTRY listEntry;
|
|
|
|
listEntry = RemoveHeadList(&configHandle->InterfaceHandleList);
|
|
iHandle = (PUSBD_INTERFACE_HANDLE_I) CONTAINING_RECORD(
|
|
listEntry,
|
|
struct _USBD_INTERFACE_HANDLE_I,
|
|
InterfaceLink);
|
|
|
|
ASSERT_INTERFACE(iHandle);
|
|
|
|
endpointCount = iHandle->InterfaceDescriptor.bNumEndpoints;
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject,
|
|
LOG_PNP, 'cIFX', iHandle, 0, configHandle);
|
|
|
|
USBPORT_KdPrint((2, "'%d endpoints to close\n", endpointCount));
|
|
|
|
for (j=0; j<endpointCount; j++) {
|
|
|
|
PUSBD_PIPE_HANDLE_I pipeHandle;
|
|
|
|
// if the pipe is open, close it
|
|
|
|
pipeHandle = &iHandle->PipeHandle[j];
|
|
|
|
USBPORT_KdPrint((2, "'close config -- closing pipe %x\n",
|
|
&iHandle->PipeHandle[j]));
|
|
|
|
USBPORT_ClosePipe(DeviceHandle,
|
|
FdoDeviceObject,
|
|
pipeHandle);
|
|
|
|
USBPORT_ASSERT(pipeHandle->ListEntry.Flink == NULL &&
|
|
pipeHandle->ListEntry.Blink == NULL);
|
|
}
|
|
|
|
// all pipes are now closed
|
|
FREE_POOL(FdoDeviceObject, iHandle);
|
|
}
|
|
|
|
// NOTE: this also frees
|
|
// configHandle->ConfigurationDescriptor since it
|
|
// is in the same block allocated for the confighandle
|
|
FREE_POOL(FdoDeviceObject, configHandle);
|
|
// device is not 'unconfigured'
|
|
DeviceHandle->ConfigurationHandle = NULL;
|
|
|
|
USBPORT_InternalCloseConfiguration_Done:
|
|
|
|
USBPORT_KdPrint((2, "'current configuration closed\n"));
|
|
|
|
}
|
|
|
|
|
|
PUSB_INTERFACE_DESCRIPTOR
|
|
USBPORT_InternalParseConfigurationDescriptor(
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
|
|
UCHAR InterfaceNumber,
|
|
UCHAR AlternateSetting,
|
|
PBOOLEAN HasAlternateSettings
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the configuration descriptor for a given device.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject -
|
|
|
|
DeviceData -
|
|
|
|
Urb -
|
|
|
|
ConfigurationDescriptor -
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptorSetting = NULL;
|
|
PUCHAR pch = (PUCHAR) ConfigurationDescriptor, end;
|
|
ULONG i;
|
|
PUSB_COMMON_DESCRIPTOR commonDescriptor;
|
|
|
|
PAGED_CODE();
|
|
if (HasAlternateSettings) {
|
|
*HasAlternateSettings = FALSE;
|
|
}
|
|
|
|
commonDescriptor =
|
|
(PUSB_COMMON_DESCRIPTOR) (pch + ConfigurationDescriptor->bLength);
|
|
|
|
while (commonDescriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE) {
|
|
if (commonDescriptor->bLength == 0) {
|
|
break; // Don't loop forever
|
|
}
|
|
((PUCHAR)(commonDescriptor))+= commonDescriptor->bLength;
|
|
}
|
|
|
|
interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) commonDescriptor;
|
|
USBPORT_ASSERT(interfaceDescriptor->bDescriptorType ==
|
|
USB_INTERFACE_DESCRIPTOR_TYPE);
|
|
|
|
end = pch + ConfigurationDescriptor->wTotalLength;
|
|
|
|
//
|
|
// First find the matching InterfaceNumber
|
|
//
|
|
while (pch < end && interfaceDescriptor->bInterfaceNumber != InterfaceNumber) {
|
|
pch = (PUCHAR) interfaceDescriptor;
|
|
pch += USBPORT_InternalGetInterfaceLength(interfaceDescriptor, end);
|
|
|
|
// point to the next interface
|
|
interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) pch;
|
|
#if DBG
|
|
if (pch < end) {
|
|
USBPORT_ASSERT(interfaceDescriptor->bDescriptorType ==
|
|
USB_INTERFACE_DESCRIPTOR_TYPE);
|
|
}
|
|
#endif //MAX_DEBUG
|
|
}
|
|
|
|
//#ifdef MAX_DEBUG
|
|
// if (pch >= end) {
|
|
// USBD_KdPrint(3, ("'Interface %x alt %x not found!\n", InterfaceNumber,
|
|
// AlternateSetting));
|
|
// TEST_TRAP();
|
|
// }
|
|
//#endif //MAX_DEBUG
|
|
|
|
i = 0;
|
|
// Now find the proper alternate setting
|
|
while (pch < end && interfaceDescriptor->bInterfaceNumber == InterfaceNumber) {
|
|
|
|
if (interfaceDescriptor->bAlternateSetting == AlternateSetting) {
|
|
interfaceDescriptorSetting = interfaceDescriptor;
|
|
}
|
|
|
|
pch = (PUCHAR) interfaceDescriptor;
|
|
pch += USBPORT_InternalGetInterfaceLength(interfaceDescriptor, end);
|
|
|
|
// point to next interface
|
|
interfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) pch;
|
|
#if DBG
|
|
if (pch < end) {
|
|
USBPORT_ASSERT(interfaceDescriptor->bDescriptorType ==
|
|
USB_INTERFACE_DESCRIPTOR_TYPE);
|
|
}
|
|
#endif
|
|
i++;
|
|
}
|
|
|
|
if (i>1 && HasAlternateSettings) {
|
|
*HasAlternateSettings = TRUE;
|
|
USBPORT_KdPrint((2, "'device has alternate settings!\n"));
|
|
}
|
|
|
|
return interfaceDescriptorSetting;
|
|
}
|
|
|
|
|
|
ULONG
|
|
USBPORT_InternalGetInterfaceLength(
|
|
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
|
|
PUCHAR End
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the configuration handle structure.
|
|
|
|
Arguments:
|
|
|
|
InterfaceDescriptor - pointer to usb interface descriptor
|
|
followed by endpoint descriptors
|
|
|
|
Return Value:
|
|
|
|
Length of the interface plus endpoint descriptors and class specific
|
|
descriptors in bytes.
|
|
|
|
--*/
|
|
{
|
|
PUCHAR pch = (PUCHAR) InterfaceDescriptor;
|
|
ULONG i, numEndpoints;
|
|
PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
|
|
PUSB_COMMON_DESCRIPTOR usbDescriptor;
|
|
|
|
PAGED_CODE();
|
|
USBPORT_ASSERT(InterfaceDescriptor->bDescriptorType ==
|
|
USB_INTERFACE_DESCRIPTOR_TYPE);
|
|
i = InterfaceDescriptor->bLength;
|
|
numEndpoints = InterfaceDescriptor->bNumEndpoints;
|
|
|
|
// advance to the first endpoint
|
|
pch += i;
|
|
|
|
while (numEndpoints) {
|
|
|
|
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
|
|
while (usbDescriptor->bDescriptorType !=
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE) {
|
|
if (usbDescriptor->bLength == 0) {
|
|
break; // Don't loop forever
|
|
}
|
|
i += usbDescriptor->bLength;
|
|
pch += usbDescriptor->bLength;
|
|
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
|
|
}
|
|
|
|
endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) pch;
|
|
USBPORT_ASSERT(endpointDescriptor->bDescriptorType ==
|
|
USB_ENDPOINT_DESCRIPTOR_TYPE);
|
|
i += endpointDescriptor->bLength;
|
|
pch += endpointDescriptor->bLength;
|
|
numEndpoints--;
|
|
}
|
|
|
|
while (pch < End) {
|
|
// see if we are pointing at an interface
|
|
// if not skip over the other junk
|
|
usbDescriptor = (PUSB_COMMON_DESCRIPTOR) pch;
|
|
if (usbDescriptor->bDescriptorType ==
|
|
USB_INTERFACE_DESCRIPTOR_TYPE) {
|
|
break;
|
|
}
|
|
|
|
USBPORT_ASSERT(usbDescriptor->bLength != 0);
|
|
if (usbDescriptor->bLength == 0) {
|
|
break; // Don't loop forever
|
|
}
|
|
i += usbDescriptor->bLength;
|
|
pch += usbDescriptor->bLength;
|
|
}
|
|
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
USBPORT_ValidateConfigurtionDescriptor(
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
|
|
USBD_STATUS *UsbdStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validate a configuration descriptor
|
|
|
|
Arguments:
|
|
|
|
ConfigurationDescriptor -
|
|
|
|
Urb -
|
|
|
|
Return Value:
|
|
|
|
TRUE if it looks valid
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN valid = TRUE;
|
|
|
|
if (ConfigurationDescriptor->bDescriptorType !=
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE) {
|
|
|
|
valid = FALSE;
|
|
|
|
*UsbdStatus = USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR;
|
|
}
|
|
|
|
if (ConfigurationDescriptor->bLength !=
|
|
sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
|
|
|
|
valid = FALSE;
|
|
|
|
*UsbdStatus = USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR;
|
|
}
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
PUSBD_INTERFACE_HANDLE_I
|
|
USBPORT_GetInterfaceHandle(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSBD_CONFIG_HANDLE ConfigurationHandle,
|
|
UCHAR InterfaceNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walks the list of interfaces attached to the configuration
|
|
handle and returns the one with the matching InterfaceNumber
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
interface handle
|
|
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY listEntry;
|
|
PUSBD_INTERFACE_HANDLE_I iHandle;
|
|
|
|
// walk the list
|
|
GET_HEAD_LIST(ConfigurationHandle->InterfaceHandleList, listEntry);
|
|
|
|
while (listEntry &&
|
|
listEntry != &ConfigurationHandle->InterfaceHandleList) {
|
|
|
|
// extract the handle from this entry
|
|
iHandle = (PUSBD_INTERFACE_HANDLE_I) CONTAINING_RECORD(
|
|
listEntry,
|
|
struct _USBD_INTERFACE_HANDLE_I,
|
|
InterfaceLink);
|
|
|
|
ASSERT_INTERFACE(iHandle);
|
|
|
|
// is this the one we want?
|
|
if (iHandle->InterfaceDescriptor.bInterfaceNumber ==
|
|
InterfaceNumber) {
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'gfh1', iHandle, 0, 0);
|
|
return iHandle;
|
|
}
|
|
|
|
listEntry = iHandle->InterfaceLink.Flink;
|
|
|
|
} /* while */
|
|
|
|
LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'gfh2', 0, 0, 0);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
USBD_STATUS
|
|
USBPORT_InitializeInterfaceInformation(
|
|
PDEVICE_OBJECT FdoDeviceObject,
|
|
PUSBD_INTERFACE_INFORMATION InterfaceInformation,
|
|
PUSBD_CONFIG_HANDLE ConfigHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
validates and initializes the interface information structure
|
|
passed by the client
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ULONG need, i;
|
|
ULONG numEndpoints;
|
|
USBD_STATUS usbdStatus = USBD_STATUS_SUCCESS;
|
|
BOOLEAN hasAlternateSettings;
|
|
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
|
|
|
|
interfaceDescriptor =
|
|
USBPORT_InternalParseConfigurationDescriptor(
|
|
ConfigHandle->ConfigurationDescriptor,
|
|
InterfaceInformation->InterfaceNumber,
|
|
InterfaceInformation->AlternateSetting,
|
|
&hasAlternateSettings);
|
|
|
|
// we know we need at least this much
|
|
need = sizeof(USBD_PIPE_INFORMATION) + sizeof(USBD_INTERFACE_INFORMATION);
|
|
|
|
if (interfaceDescriptor == NULL) {
|
|
usbdStatus = USBD_STATUS_INTERFACE_NOT_FOUND;
|
|
TEST_TRAP();
|
|
goto USBPORT_InitializeInterfaceInformation_Done;
|
|
}
|
|
|
|
// Here is where we verify there is enough room in the client
|
|
// buffer since we know how many pipes we'll need based on the
|
|
// interface descriptor.
|
|
//
|
|
// we need space for pipe_info for each endpoint plus the
|
|
// interface_info
|
|
|
|
|
|
numEndpoints = interfaceDescriptor->bNumEndpoints;
|
|
need = (USHORT) (((numEndpoints-1) * sizeof(USBD_PIPE_INFORMATION) +
|
|
sizeof(USBD_INTERFACE_INFORMATION)));
|
|
|
|
USBPORT_KdPrint((2, "'Interface.Length = %d need = %d\n",
|
|
InterfaceInformation->Length, need));
|
|
|
|
if (InterfaceInformation->Length < need) {
|
|
// the client has indicated that the buffer
|
|
// is smaller than what we need
|
|
|
|
usbdStatus = USBD_STATUS_BUFFER_TOO_SMALL;
|
|
TC_TRAP();
|
|
}
|
|
|
|
if (usbdStatus == USBD_STATUS_SUCCESS) {
|
|
// initialize all fields not set by caller to zero
|
|
|
|
InterfaceInformation->Class = 0;
|
|
InterfaceInformation->SubClass = 0;
|
|
InterfaceInformation->Protocol = 0;
|
|
InterfaceInformation->Reserved = 0;
|
|
InterfaceInformation->InterfaceHandle = NULL;
|
|
InterfaceInformation->NumberOfPipes =
|
|
numEndpoints;
|
|
|
|
for (i=0; i< numEndpoints; i++) {
|
|
InterfaceInformation->Pipes[i].EndpointAddress = 0;
|
|
InterfaceInformation->Pipes[i].Interval = 0;
|
|
InterfaceInformation->Pipes[i].PipeType = 0;
|
|
InterfaceInformation->Pipes[i].PipeHandle = NULL;
|
|
|
|
// attempt to detect bad flags
|
|
// if any unused bits are set we assume that the pipeflags
|
|
// field is uninitialized.
|
|
if (InterfaceInformation->Pipes[i].PipeFlags & ~USBD_PF_VALID_MASK) {
|
|
// client driver is passing bad flags
|
|
USBPORT_DebugClient(("client driver is passing bad pipe flags\n"));
|
|
|
|
usbdStatus = USBD_STATUS_INAVLID_PIPE_FLAGS;
|
|
TC_TRAP();
|
|
}
|
|
|
|
// note: if USBD_PF_CHANGE_MAX_PACKET is set then
|
|
// maxpacket size is passed in as a parameter so
|
|
// we don't initialize it
|
|
|
|
if (!TEST_FLAG(InterfaceInformation->Pipes[i].PipeFlags,
|
|
USBD_PF_CHANGE_MAX_PACKET)) {
|
|
InterfaceInformation->Pipes[i].MaximumPacketSize = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
USBPORT_InitializeInterfaceInformation_Done:
|
|
|
|
// set length to the correct value regardless
|
|
// of error
|
|
InterfaceInformation->Length = need;
|
|
|
|
return usbdStatus;
|
|
}
|