Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1746 lines
57 KiB

/*++
Copyright (c) 1996-2001 Microsoft Corporation
Module Name:
USB.C
Abstract:
This source file contains the functions for communicating with
the usb bus.
Environment:
kernel mode
Revision History:
Sep 2001 : Copied from USBMASS
--*/
//*****************************************************************************
// I N C L U D E S
//*****************************************************************************
#include "genusb.h"
//*****************************************************************************
// L O C A L F U N C T I O N P R O T O T Y P E S
//*****************************************************************************
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, GenUSB_GetDescriptor)
#pragma alloc_text(PAGE, GenUSB_GetDescriptors)
#pragma alloc_text(PAGE, GenUSB_GetStringDescriptors)
#pragma alloc_text(PAGE, GenUSB_VendorControlRequest)
#pragma alloc_text(PAGE, GenUSB_ResetPipe)
#endif
//******************************************************************************
//
// GenUSB_GetDescriptors()
//
// This routine is called at START_DEVICE time for the FDO to retrieve the
// Device and Configurations descriptors from the device and store them in
// the device extension.
//
//******************************************************************************
NTSTATUS
GenUSB_GetDescriptors (
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION deviceExtension;
PUCHAR descriptor;
ULONG descriptorLength;
NTSTATUS status;
PAGED_CODE();
DBGPRINT(2, ("enter: GenUSB_GetDescriptors\n"));
deviceExtension = DeviceObject->DeviceExtension;
descriptor = NULL;
LOGENTRY(deviceExtension, 'GDSC', DeviceObject, 0, 0);
//
// Get Device Descriptor
//
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_DEVICE_DESCRIPTOR_TYPE,
0, // Index
0, // LanguageId
2, // RetryCount
sizeof(USB_DEVICE_DESCRIPTOR),
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Device Descriptor failed\n"));
goto GenUSB_GetDescriptorsDone;
}
ASSERT(NULL == deviceExtension->DeviceDescriptor);
deviceExtension->DeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)descriptor;
descriptor = NULL;
//
// Get Configuration Descriptor (just the Configuration Descriptor)
//
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0, // Index
0, // LanguageId
2, // RetryCount
sizeof(USB_CONFIGURATION_DESCRIPTOR),
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Configuration Descriptor failed (1)\n"));
goto GenUSB_GetDescriptorsDone;
}
descriptorLength = ((PUSB_CONFIGURATION_DESCRIPTOR)descriptor)->wTotalLength;
ExFreePool(descriptor);
descriptor = NULL;
if (descriptorLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))
{
status = STATUS_DEVICE_DATA_ERROR;
DBGPRINT(1, ("Get Configuration Descriptor failed (2)\n"));
goto GenUSB_GetDescriptorsDone;
}
//
// Get Configuration Descriptor (and Interface and Endpoint Descriptors)
//
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0, // Index
0, // LanguageId
2, // RetryCount
descriptorLength,
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Configuration Descriptor failed (3)\n"));
goto GenUSB_GetDescriptorsDone;
}
ASSERT(NULL == deviceExtension->ConfigurationDescriptor);
deviceExtension->ConfigurationDescriptor =
(PUSB_CONFIGURATION_DESCRIPTOR)descriptor;
//
// Get the Serial Number String Descriptor, if there is one
//
if (deviceExtension->DeviceDescriptor->iSerialNumber)
{
GenUSB_GetStringDescriptors(DeviceObject);
}
#if DBG
DumpDeviceDesc(deviceExtension->DeviceDescriptor);
DumpConfigDesc(deviceExtension->ConfigurationDescriptor);
#endif
GenUSB_GetDescriptorsDone:
DBGPRINT(2, ("exit: GenUSB_GetDescriptors %08X\n", status));
LOGENTRY(deviceExtension,
'gdsc',
status,
deviceExtension->DeviceDescriptor,
deviceExtension->ConfigurationDescriptor);
return status;
}
//******************************************************************************
//
// GenUSB_GetDescriptor()
//
// Must be called at IRQL PASSIVE_LEVEL
//
//******************************************************************************
NTSTATUS
GenUSB_GetDescriptor (
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR Function,
IN UCHAR DescriptorType,
IN UCHAR Index,
IN USHORT LanguageId,
IN ULONG RetryCount,
IN ULONG DescriptorLength,
OUT PUCHAR *Descriptor
)
{
PURB urb;
NTSTATUS status;
BOOLEAN descriptorAllocated = FALSE;
PAGED_CODE();
DBGPRINT(2, ("enter: GenUSB_GetDescriptor\n"));
if (NULL == *Descriptor)
{
// Allocate a descriptor buffer
*Descriptor = ExAllocatePool(NonPagedPool, DescriptorLength);
descriptorAllocated = TRUE;
}
if (NULL != *Descriptor)
{
// Allocate a URB for the Get Descriptor request
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
if (NULL != urb)
{
do
{
// Initialize the URB
urb->UrbHeader.Function = Function;
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
urb->UrbControlDescriptorRequest.TransferBufferLength = DescriptorLength;
urb->UrbControlDescriptorRequest.TransferBuffer = *Descriptor;
urb->UrbControlDescriptorRequest.TransferBufferMDL = NULL;
urb->UrbControlDescriptorRequest.UrbLink = NULL;
urb->UrbControlDescriptorRequest.DescriptorType = DescriptorType;
urb->UrbControlDescriptorRequest.Index = Index;
urb->UrbControlDescriptorRequest.LanguageId = LanguageId;
// Send the URB down the stack
status = GenUSB_SyncSendUsbRequest(DeviceObject, urb);
if (NT_SUCCESS(status))
{
// No error, make sure the length and type are correct
if ((DescriptorLength ==
urb->UrbControlDescriptorRequest.TransferBufferLength) &&
(DescriptorType ==
((PUSB_COMMON_DESCRIPTOR)*Descriptor)->bDescriptorType))
{
// The length and type are correct, all done
break;
}
else
{
// No error, but the length or type is incorrect
status = STATUS_DEVICE_DATA_ERROR;
}
}
} while (RetryCount-- > 0);
ExFreePool(urb);
}
else
{
// Failed to allocate the URB
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
// Failed to allocate the descriptor buffer
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(status))
{
if ((*Descriptor != NULL) && descriptorAllocated)
{
ExFreePool(*Descriptor);
*Descriptor = NULL;
}
}
DBGPRINT(2, ("exit: GenUSB_GetDescriptor %08X\n", status));
return status;
}
//******************************************************************************
//
// GenUSB_GetStringDescriptors()
//
// This routine is called at START_DEVICE time for the FDO to retrieve the
// Serial Number string descriptor from the device and store it in
// the device extension.
//
//******************************************************************************
GenUSB_GetStringDescriptors (
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION deviceExtension;
PUCHAR descriptor;
ULONG descriptorLength;
ULONG i, numIds;
NTSTATUS status;
PAGED_CODE();
DBGPRINT(2, ("enter: GenUSB_GetStringDescriptors\n"));
deviceExtension = DeviceObject->DeviceExtension;
descriptor = NULL;
LOGENTRY(deviceExtension, 'GSDC', DeviceObject, 0, 0);
// Get the list of Language IDs (descriptor header only)
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_STRING_DESCRIPTOR_TYPE,
0, // Index
0, // LanguageId
2, // RetryCount
sizeof(USB_COMMON_DESCRIPTOR),
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Language IDs failed (1) %08X\n", status));
goto GenUSB_GetStringDescriptorsDone;
}
descriptorLength = ((PUSB_COMMON_DESCRIPTOR)descriptor)->bLength;
ExFreePool(descriptor);
descriptor = NULL;
if ((descriptorLength < sizeof(USB_COMMON_DESCRIPTOR) + sizeof(USHORT)) ||
(descriptorLength & 1))
{
status = STATUS_DEVICE_DATA_ERROR;
DBGPRINT(1, ("Get Language IDs failed (2) %d\n", descriptorLength));
goto GenUSB_GetStringDescriptorsDone;
}
// Get the list of Language IDs (complete descriptor)
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_STRING_DESCRIPTOR_TYPE,
0, // Index
0, // LanguageId
2, // RetryCount
descriptorLength,
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Language IDs failed (3) %08X\n", status));
goto GenUSB_GetStringDescriptorsDone;
}
// Search the list of LanguageIDs for US-English (0x0409). If we find
// it in the list, that's the LanguageID we'll use. Else just default
// to the first LanguageID in the list.
numIds = (descriptorLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(USHORT);
deviceExtension->LanguageId = ((PUSHORT)descriptor)[1];
for (i = 2; i <= numIds; i++)
{
if (((PUSHORT)descriptor)[i] == 0x0409)
{
deviceExtension->LanguageId = 0x0409;
break;
}
}
ExFreePool(descriptor);
descriptor = NULL;
//
// Get the Serial Number (descriptor header only)
//
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_STRING_DESCRIPTOR_TYPE,
deviceExtension->DeviceDescriptor->iSerialNumber,
deviceExtension->LanguageId,
2, // RetryCount
sizeof(USB_COMMON_DESCRIPTOR),
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Serial Number failed (1) %08X\n", status));
goto GenUSB_GetStringDescriptorsDone;
}
descriptorLength = ((PUSB_COMMON_DESCRIPTOR)descriptor)->bLength;
ExFreePool(descriptor);
descriptor = NULL;
if ((descriptorLength < sizeof(USB_COMMON_DESCRIPTOR) + sizeof(USHORT)) ||
(descriptorLength & 1))
{
status = STATUS_DEVICE_DATA_ERROR;
DBGPRINT(1, ("Get Serial Number failed (2) %d\n", descriptorLength));
goto GenUSB_GetStringDescriptorsDone;
}
//
// Get the Serial Number (complete descriptor)
//
status = GenUSB_GetDescriptor(DeviceObject,
USB_RECIPIENT_DEVICE,
USB_STRING_DESCRIPTOR_TYPE,
deviceExtension->DeviceDescriptor->iSerialNumber,
deviceExtension->LanguageId,
2, // RetryCount
descriptorLength,
&descriptor);
if (!NT_SUCCESS(status))
{
DBGPRINT(1, ("Get Serial Number failed (3) %08X\n", status));
goto GenUSB_GetStringDescriptorsDone;
}
ASSERT(NULL == deviceExtension->SerialNumber);
deviceExtension->SerialNumber = (PUSB_STRING_DESCRIPTOR)descriptor;
GenUSB_GetStringDescriptorsDone:
DBGPRINT(2, ("exit: GenUSB_GetStringDescriptors %08X %08X\n",
status, deviceExtension->SerialNumber));
LOGENTRY(deviceExtension,
'gdsc',
status,
deviceExtension->LanguageId,
deviceExtension->SerialNumber);
return status;
}
NTSTATUS
GenUSB_VendorControlRequest (
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR RequestType,
IN UCHAR Request,
IN USHORT Value,
IN USHORT Index,
IN USHORT Length,
IN ULONG RetryCount,
OUT PULONG UrbStatus,
OUT PUSHORT ResultLength,
OUT PUCHAR *Descriptor
)
{
PURB urb;
NTSTATUS status;
BOOLEAN descriptorAllocated = FALSE;
PAGED_CODE();
DBGPRINT(2, ("enter: GenUSB_GetDescriptor\n"));
if (NULL == *Descriptor)
{
// Allocate a descriptor buffer
*Descriptor = ExAllocatePool(NonPagedPool, Length);
descriptorAllocated = TRUE;
}
if (NULL != *Descriptor)
{
// Allocate a URB for the Get Descriptor request
urb = ExAllocatePool(NonPagedPool, sizeof(struct _URB_CONTROL_TRANSFER));
if (NULL != urb)
{
do
{
// Initialize the URB
urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
urb->UrbControlTransfer.PipeHandle = NULL;
urb->UrbControlTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN
| USBD_DEFAULT_PIPE_TRANSFER
| USBD_SHORT_TRANSFER_OK;
urb->UrbControlTransfer.TransferBufferLength = Length;
urb->UrbControlTransfer.TransferBuffer = *Descriptor;
urb->UrbControlTransfer.TransferBufferMDL = NULL;
urb->UrbControlTransfer.UrbLink = NULL;
urb->UrbControlTransfer.SetupPacket [0] = RequestType;
urb->UrbControlTransfer.SetupPacket [1] = Request;
((WCHAR *) urb->UrbControlTransfer.SetupPacket) [1] = Value;
((WCHAR *) urb->UrbControlTransfer.SetupPacket) [2] = Index;
((WCHAR *) urb->UrbControlTransfer.SetupPacket) [3] = Length;
// Send the URB down the stack
status = GenUSB_SyncSendUsbRequest(DeviceObject, urb);
if (NT_SUCCESS(status))
{
break;
}
} while (RetryCount-- > 0);
*UrbStatus = urb->UrbHeader.Status;
*ResultLength = (USHORT) urb->UrbControlTransfer.TransferBufferLength;
ExFreePool(urb);
}
else
{
// Failed to allocate the URB
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
// Failed to allocate the descriptor buffer
status = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(status))
{
if ((*Descriptor != NULL) && descriptorAllocated)
{
ExFreePool(*Descriptor);
*Descriptor = NULL;
}
}
DBGPRINT(2, ("exit: GenUSB_GetDescriptor %08X\n", status));
return status;
}
void blah()
{
return;
}
VOID
GenUSB_ParseConfigurationDescriptors(
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN ULONG NumberInterfaces,
IN USB_INTERFACE_DESCRIPTOR DesiredArray[],
OUT USB_INTERFACE_DESCRIPTOR FoundArray[],
OUT PUCHAR InterfacesFound,
OUT PUSBD_INTERFACE_LIST_ENTRY DescriptorArray
)
/*++
Routine Description:
Parses a standard USB configuration descriptor (returned from a device)
for an array of specific interfaces, alternate setting class subclass or
protocol codes
Arguments:
Return Value:
NT status code.
--*/
{
ULONG i;
ULONG foo;
PUSB_INTERFACE_DESCRIPTOR inter;
PAGED_CODE();
ASSERT (NULL != InterfacesFound);
ASSERT (NULL != DescriptorArray);
*InterfacesFound = 0; // none found yet.
ASSERT(ConfigurationDescriptor->bDescriptorType
== USB_CONFIGURATION_DESCRIPTOR_TYPE);
//
// we walk the table of desired interfaces descriptors looking for an
// looking for all of them in the configuration descriptor
//
//
// here we use ParseConfigurationDescriptorEx, which walks through the
// entire configuration descriptor looking for matches. While this is
// more or less order n^2 things are not much better if done by hand
// so just use the given routine.
//
for (i = 0; i < NumberInterfaces; i++)
{
inter = USBD_ParseConfigurationDescriptorEx (
ConfigurationDescriptor,
ConfigurationDescriptor,
(CHAR) DesiredArray[i].bInterfaceNumber,
(CHAR) DesiredArray[i].bAlternateSetting,
(CHAR) DesiredArray[i].bInterfaceClass,
(CHAR) DesiredArray[i].bInterfaceSubClass,
(CHAR) DesiredArray[i].bInterfaceProtocol);
if (NULL != inter)
{
DescriptorArray[*InterfacesFound].InterfaceDescriptor = inter;
(*InterfacesFound)++;
FoundArray[i] = *inter;
}
}
}
//******************************************************************************
//
// GenUSB_SelectConfiguration()
//
// Must be called at IRQL PASSIVE_LEVEL
//
//******************************************************************************
NTSTATUS
GenUSB_SelectConfiguration (
IN PDEVICE_EXTENSION DeviceExtension,
IN ULONG NumberInterfaces,
IN PUSB_INTERFACE_DESCRIPTOR DesiredArray,
OUT PUSB_INTERFACE_DESCRIPTOR FoundArray
)
{
PGENUSB_INTERFACE inter;
// Apparently the compiler will not allow a local variable of the name
// interface for some probably valid but frustrating reason.
PURB urb;
NTSTATUS status;
PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
PUSBD_INTERFACE_INFORMATION interfaceInfo;
PUSBD_INTERFACE_LIST_ENTRY interfaceList;
ULONG i,j;
ULONG size;
UCHAR interfacesFound;
BOOLEAN directionIn;
KIRQL irql;
ExAcquireFastMutex (&DeviceExtension->ConfigMutex);
DBGPRINT(2, ("enter: GenUSB_SelectConfiguration\n"));
LOGENTRY(DeviceExtension, 'SCON', DeviceExtension->Self, 0, 0);
urb = 0;
interfaceList = 0;
//
// We shouldn't have a currently selected interface.
// You must unconfigure the device before configuring it again.
//
if (NULL != DeviceExtension->ConfigurationHandle)
{
status = STATUS_INVALID_PARAMETER;
goto GenUSB_SelectConfigurationReject;
}
ASSERT (NULL == DeviceExtension->Interface);
ASSERT (0 == DeviceExtension->InterfacesFound);
configurationDescriptor = DeviceExtension->ConfigurationDescriptor;
// Allocate storage for an Inteface List to use as an input/output
// parameter to USBD_CreateConfigurationRequestEx().
//
interfaceList =
ExAllocatePool(PagedPool,
sizeof(USBD_INTERFACE_LIST_ENTRY) * (NumberInterfaces + 1));
if (NULL == interfaceList)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto GenUSB_SelectConfigurationReject;
}
// NB we are holding a Fast Mutex whist calling this function
GenUSB_ParseConfigurationDescriptors(configurationDescriptor,
NumberInterfaces,
DesiredArray,
FoundArray,
&interfacesFound,
interfaceList);
if (interfacesFound < NumberInterfaces)
{
// We couldn't select all of the interfaces.
// For now, allow that.
// status = STATUS_INVALID_PARAMETER;
// goto GenUSB_SelectConfigurationReject;
;
}
ASSERT (interfacesFound <= NumberInterfaces);
// Terminate the list.
interfaceList[interfacesFound].InterfaceDescriptor = NULL;
// Create a SELECT_CONFIGURATION URB, turning the Interface
// Descriptors in the interfaceList into USBD_INTERFACE_INFORMATION
// structures in the URB.
//
// NB we are holding a Fast Mutex whist calling this function
urb = USBD_CreateConfigurationRequestEx(
configurationDescriptor,
interfaceList);
if (NULL == urb)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto GenUSB_SelectConfigurationReject;
}
// Now issue the USB request to set the Configuration
// NB we are holding a Fast Mutex whist calling this function
status = GenUSB_SyncSendUsbRequest(DeviceExtension->Self, urb);
if (!NT_SUCCESS(status))
{
goto GenUSB_SelectConfigurationReject;
}
KeAcquireSpinLock (&DeviceExtension->SpinLock, &irql);
{
DeviceExtension->InterfacesFound = interfacesFound;
DeviceExtension->TotalNumberOfPipes = 0;
// Save the configuration handle for this device in
// the Device Extension.
DeviceExtension->ConfigurationHandle =
urb->UrbSelectConfiguration.ConfigurationHandle;
//
// Now for each interface in the list...
// Save a copy of the interface information returned
// by the SELECT_CONFIGURATION request in the Device
// Extension. This gives us a list of PIPE_INFORMATION
// structures for each pipe opened in this configuration.
//
size = interfacesFound * sizeof (PVOID);
DeviceExtension->Interface = ExAllocatePool (NonPagedPool, size);
if (NULL == DeviceExtension->Interface)
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
RtlZeroMemory (DeviceExtension->Interface, size);
interfaceInfo = &urb->UrbSelectConfiguration.Interface;
for (i=0; i < interfacesFound; i++)
{
size = sizeof (GENUSB_INTERFACE)
+ (interfaceInfo->NumberOfPipes * sizeof(GENUSB_PIPE_INFO));
inter =
DeviceExtension->Interface[i] =
ExAllocatePool (NonPagedPool, size);
if (inter)
{
RtlZeroMemory (inter, size);
inter->InterfaceNumber = interfaceInfo->InterfaceNumber;
inter->CurrentAlternate = interfaceInfo->AlternateSetting;
inter->Handle = interfaceInfo->InterfaceHandle;
inter->NumberOfPipes = (UCHAR)interfaceInfo->NumberOfPipes;
DeviceExtension->TotalNumberOfPipes += inter->NumberOfPipes;
for (j=0; j < inter->NumberOfPipes; j++)
{
inter->Pipes[j].Info = interfaceInfo->Pipes[j];
// Set the default timeout for this device to be zero.
// (structure already initialized to zero.)
//
// inter->Pipes[j].Properties.DefaultTimeout = 0;
// inter->Pipes[j].CurrentTimeout = 0;
// set the outstanding number of transactions for this
// pipe to be 0.
//
// inter->Pipes[j].OutandingIO = 0;
directionIn =
USBD_PIPE_DIRECTION_IN (&inter->Pipes[j].Info);
if (directionIn)
{
//
// by default we always truncate reads requests from
// the device.
//
inter->Pipes[j].Properties.DirectionIn = TRUE;
inter->Pipes[j].Properties.NoTruncateToMaxPacket = FALSE;
}
}
}
else
{
// Could not allocate a copy of interface information
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// find the next interfaceInfo
//
interfaceInfo = (PUSBD_INTERFACE_INFORMATION)
((PUCHAR) interfaceInfo + interfaceInfo->Length);
}
}
//
// Regardless of whether or not we've been successful...
// We've just invalidated the pipe table so blow away the
// read and write values.
//
DeviceExtension->ReadInterface = -1;
DeviceExtension->ReadPipe = -1;
DeviceExtension->WriteInterface = -1;
DeviceExtension->WritePipe = -1;
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, irql);
if (!NT_SUCCESS (status))
{
goto GenUSB_SelectConfigurationReject;
}
IoInitializeRemoveLock (&DeviceExtension->ConfigurationRemoveLock,
POOL_TAG,
0,
0);
IoStartTimer (DeviceExtension->Self);
ExFreePool(urb);
ExFreePool(interfaceList);
DBGPRINT(2, ("exit: GenUSB_SelectConfiguration %08X\n", status));
LOGENTRY(DeviceExtension, 'scon', 0, 0, status);
ExReleaseFastMutex (&DeviceExtension->ConfigMutex);
return status;
GenUSB_SelectConfigurationReject:
if (interfaceList)
{
ExFreePool (interfaceList);
}
if (urb)
{
ExFreePool (urb);
}
GenUSB_FreeInterfaceTable (DeviceExtension);
LOGENTRY(DeviceExtension, 'scon', 0, 0, status);
ExReleaseFastMutex (&DeviceExtension->ConfigMutex);
return status;
}
VOID
GenUSB_FreeInterfaceTable (
PDEVICE_EXTENSION DeviceExtension
)
{
KIRQL irql;
ULONG i;
KeAcquireSpinLock (&DeviceExtension->SpinLock, &irql);
{
if (DeviceExtension->Interface)
{
for (i = 0; i < DeviceExtension->InterfacesFound; i++)
{
if (DeviceExtension->Interface[i])
{
ExFreePool (DeviceExtension->Interface[i]);
}
}
ExFreePool (DeviceExtension->Interface);
DeviceExtension->Interface = 0;
}
DeviceExtension->InterfacesFound = 0;
DeviceExtension->ConfigurationHandle = NULL; // Freed automatically by USB
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, irql);
}
//******************************************************************************
//
// GenUSB_UnConfigure()
//
// Must be called at IRQL PASSIVE_LEVEL
//
//******************************************************************************
NTSTATUS
GenUSB_DeselectConfiguration (
PDEVICE_EXTENSION DeviceExtension,
BOOLEAN SendUrb
)
{
NTSTATUS status;
PURB urb;
ULONG ulSize;
ExAcquireFastMutex (&DeviceExtension->ConfigMutex);
DBGPRINT(2, ("enter: GenUSB_UnConfigure\n"));
LOGENTRY(DeviceExtension, 'UCON', DeviceExtension->Self, 0, 0);
if (NULL == DeviceExtension->ConfigurationHandle)
{
status = STATUS_UNSUCCESSFUL;
LOGENTRY(DeviceExtension, 'ucon', 1, 0, status);
ExReleaseFastMutex (&DeviceExtension->ConfigMutex);
return status;
}
status = STATUS_SUCCESS;
IoStopTimer (DeviceExtension->Self);
// Allocate a URB for the SELECT_CONFIGURATION request. As we are
// unconfiguring the device, the request needs no pipe and interface
// information structures.
if (SendUrb)
{
ulSize = sizeof(struct _URB_SELECT_CONFIGURATION);
urb = ExAllocatePool (NonPagedPool, ulSize);
if (urb)
{
// Initialize the URB. A NULL Configuration Descriptor indicates
// that the device should be unconfigured.
//
UsbBuildSelectConfigurationRequest(urb, (USHORT)ulSize, NULL);
// Now issue the USB request to set the Configuration
//
status = GenUSB_SyncSendUsbRequest(DeviceExtension->Self, urb);
ASSERT ((STATUS_SUCCESS == status) ||
(STATUS_DEVICE_NOT_CONNECTED == status) ||
(STATUS_DEVICE_POWERED_OFF == status));
ExFreePool (urb);
}
else
{
// Could not allocate the URB.
//
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// We need to wait for all outstanding IO to finish before
// freeing the pipe table
//
// In order to use ReleaseAndWait, we need to first take the lock another
// time.
//
status = IoAcquireRemoveLock (&DeviceExtension->ConfigurationRemoveLock,
DeviceExtension);
ASSERT (STATUS_SUCCESS == status);
IoReleaseRemoveLockAndWait (&DeviceExtension->ConfigurationRemoveLock,
DeviceExtension);
GenUSB_FreeInterfaceTable (DeviceExtension);
//
// We've just invalidated the pipe table so blow away the
// read and write values.
//
DeviceExtension->ReadInterface = -1;
DeviceExtension->ReadPipe = -1;
DeviceExtension->WriteInterface = -1;
DeviceExtension->WritePipe = -1;
DBGPRINT(2, ("exit: GenUSB_UnConfigure %08X\n", status));
LOGENTRY(DeviceExtension, 'ucon', 0, 0, status);
ExReleaseFastMutex (&DeviceExtension->ConfigMutex);
return status;
}
NTSTATUS
GenUSB_GetSetPipe (
IN PDEVICE_EXTENSION DeviceExtension,
IN PUCHAR InterfaceIndex, // Optional
IN PUCHAR InterfaceNumber, // Optional
IN PUCHAR PipeIndex, // Optional
IN PUCHAR EndpointAddress, // Optional
IN PGENUSB_PIPE_PROPERTIES SetPipeProperties, // Optional
OUT PGENUSB_PIPE_INFORMATION PipeInfo, // Optional
OUT PGENUSB_PIPE_PROPERTIES GetPipeProperties, // Optional
OUT USBD_PIPE_HANDLE * UsbdPipeHandle // Optional
)
{
KIRQL irql;
UCHAR i;
NTSTATUS status;
BOOLEAN directionIn;
UCHAR trueInterIndex;
PGENUSB_INTERFACE genusbInterface;
PGENUSB_PIPE_INFO pipe;
status = IoAcquireRemoveLock (&DeviceExtension->ConfigurationRemoveLock,
PipeInfo);
if (!NT_SUCCESS(status)) {
return status;
}
status = STATUS_INVALID_PARAMETER;
KeAcquireSpinLock (&DeviceExtension->SpinLock, &irql);
{
if (NULL != InterfaceNumber)
{
// We need to walk the list of interfaces looking for this
// interface number.
//
// set trueInterIndex to an invalid value to start so that if it's
// not found, we will fall through the error path.
//
trueInterIndex = DeviceExtension->InterfacesFound;
for (i=0; i<DeviceExtension->InterfacesFound; i++)
{
genusbInterface = DeviceExtension->Interface[i];
if (genusbInterface->InterfaceNumber == *InterfaceNumber)
{
trueInterIndex = i;
break;
}
}
}
else
{
ASSERT (NULL != InterfaceIndex);
trueInterIndex = *InterfaceIndex;
}
if (trueInterIndex < DeviceExtension->InterfacesFound)
{
genusbInterface = DeviceExtension->Interface[trueInterIndex];
//
// Find the Pipe in question using either the PipeIndex
// or the Endpoint Address.
//
pipe = NULL;
if (NULL != PipeIndex)
{
ASSERT (0 == EndpointAddress);
if (*PipeIndex < genusbInterface->NumberOfPipes)
{
pipe = &genusbInterface->Pipes[*PipeIndex];
}
}
else
{
for (i=0; i < genusbInterface->NumberOfPipes; i++)
{
if (genusbInterface->Pipes[i].Info.EndpointAddress ==
*EndpointAddress)
{
// *PipeInfo = genusbInterface->Pipes[i].Info;
pipe = &genusbInterface->Pipes[i];
break;
}
}
}
if (NULL != pipe)
{
//
// Now that we have the Pipe, retrieve and set optional info
//
if (PipeInfo)
{
// *PipeInfo = pipe->Info;
PipeInfo->MaximumPacketSize = pipe->Info.MaximumPacketSize;
PipeInfo->EndpointAddress = pipe->Info.EndpointAddress;
PipeInfo->Interval = pipe->Info.Interval;
PipeInfo->PipeType = pipe->Info.PipeType;
PipeInfo->MaximumTransferSize = pipe->Info.MaximumTransferSize;
PipeInfo->PipeFlags = pipe->Info.PipeFlags;
((PGENUSB_PIPE_HANDLE)&PipeInfo->PipeHandle)->InterfaceIndex
= trueInterIndex;
((PGENUSB_PIPE_HANDLE)&PipeInfo->PipeHandle)->PipeIndex = i;
((PGENUSB_PIPE_HANDLE)&PipeInfo->PipeHandle)->Signature
= CONFIGURATION_CHECK_BITS (DeviceExtension);
status = STATUS_SUCCESS;
}
if (SetPipeProperties)
{
C_ASSERT (RTL_FIELD_SIZE (GENUSB_PIPE_PROPERTIES, ReservedFields) +
FIELD_OFFSET (GENUSB_PIPE_PROPERTIES, ReservedFields) ==
sizeof (GENUSB_PIPE_PROPERTIES));
// ensure that this is a valid set request.
// the check bits must be present that were set when the
// caller did a get, and the unused fields must be zero.
if (!VERIFY_PIPE_PROPERTIES_HANDLE (SetPipeProperties, pipe))
{
; // status is already set.
}
else if (RtlEqualMemory (pipe->Properties.ReservedFields,
SetPipeProperties->ReservedFields,
RTL_FIELD_SIZE (GENUSB_PIPE_PROPERTIES,
ReservedFields)))
{
// This field is not settable
directionIn = pipe->Properties.DirectionIn;
pipe->Properties = *SetPipeProperties;
// the timeout must be greater than one so fix that here.
if (1 == pipe->Properties.Timeout)
{
pipe->Properties.Timeout++;
}
pipe->Properties.DirectionIn = directionIn;
status = STATUS_SUCCESS;
}
}
if (GetPipeProperties)
{
*GetPipeProperties = pipe->Properties;
// set the checkbits before returning to the user
GetPipeProperties->PipePropertyHandle =
PIPE_PROPERTIES_CHECK_BITS (pipe);
status = STATUS_SUCCESS;
}
if (UsbdPipeHandle)
{
*UsbdPipeHandle = pipe->Info.PipeHandle;
status = STATUS_SUCCESS;
}
}
}
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, irql);
IoReleaseRemoveLock (&DeviceExtension->ConfigurationRemoveLock, PipeInfo);
return status;
}
NTSTATUS
GenUSB_SetReadWritePipes (
IN PDEVICE_EXTENSION DeviceExtension,
IN PGENUSB_PIPE_HANDLE ReadPipe,
IN PGENUSB_PIPE_HANDLE WritePipe
)
{
NTSTATUS status;
KIRQL irql;
PGENUSB_INTERFACE inter;
BOOLEAN isReadPipe;
BOOLEAN isWritePipe;
PUSBD_PIPE_INFORMATION pipeInfo;
isReadPipe = isWritePipe = TRUE;
status = IoAcquireRemoveLock (&DeviceExtension->ConfigurationRemoveLock,
GenUSB_SetReadWritePipes);
if (!NT_SUCCESS(status)) {
return status;
}
if ((0 == ReadPipe->Signature) &&
(0 == ReadPipe->InterfaceIndex) &&
(0 == ReadPipe->PipeIndex))
{
isReadPipe = FALSE;
}
else if (! VERIFY_PIPE_HANDLE_SIG (ReadPipe, DeviceExtension))
{
status = STATUS_INVALID_PARAMETER;
}
if ((0 == WritePipe->Signature) &&
(0 == WritePipe->InterfaceIndex) &&
(0 == WritePipe->PipeIndex))
{
isWritePipe = FALSE;
}
else if (! VERIFY_PIPE_HANDLE_SIG (WritePipe, DeviceExtension))
{
status = STATUS_INVALID_PARAMETER;
}
if (NT_SUCCESS (status))
{
KeAcquireSpinLock (&DeviceExtension->SpinLock, &irql);
//
// Verify that the given values for read and write pipes are
// within range and then set them.
//
if (isReadPipe)
{
if (ReadPipe->InterfaceIndex < DeviceExtension->InterfacesFound)
{
inter = DeviceExtension->Interface[ReadPipe->InterfaceIndex];
if (ReadPipe->PipeIndex < inter->NumberOfPipes)
{
// ok the ranges are now valid, test to make sure that
// we are configuring for pipes in the correct direction
// and for the correct endpoint type
//
// Right now we only support Bulk and Interrupt.
pipeInfo = &inter->Pipes[ReadPipe->PipeIndex].Info;
if ( (USBD_PIPE_DIRECTION_IN (pipeInfo))
&& ( (UsbdPipeTypeBulk == pipeInfo->PipeType)
|| (UsbdPipeTypeInterrupt == pipeInfo->PipeType)))
{
DeviceExtension->ReadInterface = ReadPipe->InterfaceIndex;
DeviceExtension->ReadPipe = ReadPipe->PipeIndex;
status = STATUS_SUCCESS;
}
}
}
}
if (isWritePipe)
{
if (WritePipe->InterfaceIndex < DeviceExtension->InterfacesFound)
{
inter = DeviceExtension->Interface[WritePipe->InterfaceIndex];
if (WritePipe->PipeIndex < inter->NumberOfPipes)
{
// ok the ranges are now valid, test to make sure that
// we are configuring for pipes in the correct direction
// and for the correct endpoint type
//
// Right now we only support Bulk and Interrupt.
pipeInfo = &inter->Pipes[WritePipe->PipeIndex].Info;
if ( (!USBD_PIPE_DIRECTION_IN (pipeInfo))
&& ( (UsbdPipeTypeBulk == pipeInfo->PipeType)
|| (UsbdPipeTypeInterrupt == pipeInfo->PipeType)))
{
DeviceExtension->WriteInterface = WritePipe->InterfaceIndex;
DeviceExtension->WritePipe = WritePipe->PipeIndex;
status = STATUS_SUCCESS;
}
}
}
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, irql);
}
IoReleaseRemoveLock (&DeviceExtension->ConfigurationRemoveLock,
GenUSB_SetReadWritePipes);
return status;
}
NTSTATUS
GenUSB_TransmitReceiveComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PGENUSB_TRANS_RECV Trc
)
{
PVOID context;
USBD_STATUS urbStatus;
ULONG length;
PDEVICE_EXTENSION deviceExtension;
PGENUSB_PIPE_INFO pipe;
PGENUSB_COMPLETION_ROUTINE complete;
ASSERT (NULL != Trc);
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
complete = Trc->CompletionRoutine;
context = Trc->Context;
urbStatus = Trc->TransUrb.Hdr.Status;
length = Trc->TransUrb.TransferBufferLength;
pipe = Trc->Pipe;
LOGENTRY(deviceExtension, 'TR_C', Irp, urbStatus, Irp->IoStatus.Status);
//
// JD has convinced me that auto reset is not something we should
// do for the vendors, since there are so many different cases that
// require special handling of the data. They will need to do a reset
// themselves explicitely.
//
// if (pipe->Properties.AutoReset &&
// (!USBD_SUCCESS(urbStatus)) &&
// urbStatus != USBD_STATUS_CANCELED)
// {
// GenUSB_ResetPipe (deviceExtension, Irp, Trc);
// return STATUS_MORE_PROCESSING_REQUIRED;
// }
InterlockedDecrement (&pipe->OutstandingIO);
ExFreePool (Trc);
IoReleaseRemoveLock (&deviceExtension->ConfigurationRemoveLock, Irp);
IoReleaseRemoveLock (&deviceExtension->RemoveLock, Irp);
return ((*complete) (DeviceObject, Irp, context, urbStatus, length));
}
//******************************************************************************
//
// GenUSB_TransmitReceive()
//
// This routine may run at DPC level.
//
// Basic idea:
//
// Initializes the Bulk or Interrupt transfer Urb and sends it down the stack
//
// scratch: Transfer Flags: USBD_SHORT_TRANSFER_OK
// USBD_DEFAULT_PIPE_TRANSFER
// USBD_TRANSFER_DIRECTION_OUT
// USBD_TRANSFER_DIRECTION_IN
//
//
//******************************************************************************
NTSTATUS
GenUSB_TransmitReceive (
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp,
IN UCHAR InterfaceNo,
IN UCHAR PipeNo,
IN ULONG TransferFlags,
IN PCHAR Buffer,
IN PMDL BufferMDL,
IN ULONG BufferLength,
IN PVOID Context,
IN PGENUSB_COMPLETION_ROUTINE CompletionRoutine
)
{
PIO_STACK_LOCATION stack;
KIRQL irql;
NTSTATUS status;
GENUSB_TRANS_RECV * trc;
PGENUSB_PIPE_INFO pipe;
DBGPRINT(3, ("enter: GenUSB_TransmitReceive\n"));
LOGENTRY(DeviceExtension,
'TR__',
DeviceExtension,
((InterfaceNo << 16) | PipeNo),
((NULL == Buffer) ? (PCHAR) BufferMDL : Buffer));
trc = NULL;
pipe = NULL;
//
// Add another ref count to the remove lock for this completion routine.
// since the caller will in all cases free the reference that it took.
//
status = IoAcquireRemoveLock (&DeviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
status = IoAcquireRemoveLock (&DeviceExtension->ConfigurationRemoveLock, Irp);
if (!NT_SUCCESS(status)) {
IoReleaseRemoveLock (&DeviceExtension->RemoveLock, Irp);
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
//
// find the pipe in question.
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &irql);
{
if (InterfaceNo < DeviceExtension->InterfacesFound)
{
if (PipeNo < DeviceExtension->Interface[InterfaceNo]->NumberOfPipes)
{
pipe = &DeviceExtension->Interface[InterfaceNo]->Pipes[PipeNo];
}
}
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, irql);
if (NULL == pipe)
{
status = STATUS_INVALID_PARAMETER;
goto GenUSB_TransmitReceiveReject;
}
trc = ExAllocatePool (NonPagedPool, sizeof (GENUSB_TRANS_RECV));
if (NULL == trc)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto GenUSB_TransmitReceiveReject;
}
RtlZeroMemory (trc, sizeof (GENUSB_TRANS_RECV));
trc->Context = Context;
trc->Pipe = pipe;
trc->CompletionRoutine = CompletionRoutine;
// truncate a read packet to the max packet size if necessary.
if ((pipe->Properties.DirectionIn) &&
(!pipe->Properties.NoTruncateToMaxPacket) &&
(BufferLength > pipe->Info.MaximumPacketSize))
{
BufferLength -= (BufferLength % pipe->Info.MaximumPacketSize);
}
// Initialize the TransferURB
trc->TransUrb.Hdr.Length = sizeof (trc->TransUrb);
trc->TransUrb.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
trc->TransUrb.PipeHandle = pipe->Info.PipeHandle;
trc->TransUrb.TransferFlags = TransferFlags;
trc->TransUrb.TransferBufferLength = BufferLength;
trc->TransUrb.TransferBuffer = Buffer;
trc->TransUrb.TransferBufferMDL = BufferMDL;
// Set up the Irp
stack = IoGetNextIrpStackLocation (Irp);
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
stack->Parameters.Others.Argument1 = &trc->TransUrb;
InterlockedIncrement (&pipe->OutstandingIO);
// Reset the timer Value.
pipe->CurrentTimeout = pipe->Properties.Timeout;
IoSetCompletionRoutine (Irp,
GenUSB_TransmitReceiveComplete,
trc,
TRUE,
TRUE,
TRUE);
//
// The rule is: if your completion routine is going to cause the
// Irp to be completed asynchronously (by returning
// STATUS_MORE_PROCESSING_REQUIRED) or if it is going to change
// the status of the Irp, then the dispatch function must mark
// the Irp as pending and return STATUS_PENDING. The completion
// routine TransmitReceiveComplete doesn't change the status,
// but ProbeAndSubmitTransferComlete might.
//
// In either case this prevents us from having to perculate the pending
// bit in the completion routine as well.
//
IoMarkIrpPending (Irp);
status = IoCallDriver (DeviceExtension->StackDeviceObject, Irp);
DBGPRINT(3, ("exit: GenUSB_TransRcv %08X\n", status));
LOGENTRY(DeviceExtension, 'TR_x', Irp, trc, status);
status = STATUS_PENDING;
return status;
GenUSB_TransmitReceiveReject:
if (trc)
{
IoReleaseRemoveLock (&DeviceExtension->ConfigurationRemoveLock, Irp);
IoReleaseRemoveLock (&DeviceExtension->RemoveLock, Irp);
ExFreePool (trc);
}
LOGENTRY(DeviceExtension, 'TR_x', Irp, trc, status);
((*CompletionRoutine) (DeviceExtension->Self, Irp, Context, 0, 0));
//
// Complete the Irp only after this routine fires, since we pass the
// Irp into this routine.
//
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
//******************************************************************************
//
// GenUSB_Timer()
//
//
//
// This is a watchdog timer routine. The assumption here is that this is not
// a highly acurate timer (in fact it only has an accuracy of a single second.
// the point is to see if there is any pipe on this device that has
// outstanding transactions that are stuck, and then reset that pipe.
// We therefore do not spend any effort closing the race conditions
// between a just completing transaction and the timer firing.
// It is sufficient to know that it got that close to reset the pipe.
//
// Apon pipe reset, all outstanding IRPs on the pipe should return with
// and error. (which is just fine.)
//
//
//******************************************************************************
typedef struct _GENUSB_ABORT_CONTEXT {
ULONG NumHandles;
PIO_WORKITEM WorkItem;
USBD_PIPE_HANDLE Handles[];
} GENUSB_ABORT_CONTEXT, *PGENUSB_ABORT_CONTEXT;
VOID
GenUSB_AbortPipeWorker (
IN PDEVICE_OBJECT DeviceObject,
IN PGENUSB_ABORT_CONTEXT Context
)
{
ULONG i;
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension;
struct _URB_PIPE_REQUEST urb;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
for (i=0; i < Context->NumHandles; i++)
{
RtlZeroMemory (&urb, sizeof (urb));
urb.Hdr.Length = sizeof (urb);
urb.Hdr.Function = URB_FUNCTION_ABORT_PIPE;
urb.PipeHandle = Context->Handles [i];
LOGENTRY (deviceExtension, 'Abor', urb.PipeHandle, 0, 0);
status = GenUSB_SyncSendUsbRequest (DeviceObject, (PURB) &urb);
if (!NT_SUCCESS (status))
{
LOGENTRY (deviceExtension, 'Abor', urb.PipeHandle, 0, status);
}
}
IoReleaseRemoveLock (&deviceExtension->ConfigurationRemoveLock, GenUSB_Timer);
IoFreeWorkItem (Context->WorkItem);
ExFreePool (Context);
}
VOID
GenUSB_Timer (
PDEVICE_OBJECT DeviceObject,
PVOID Unused
)
{
PGENUSB_PIPE_INFO pipe;
PGENUSB_INTERFACE inter;
ULONG i,j;
PDEVICE_EXTENSION deviceExtension;
KIRQL irql;
PGENUSB_ABORT_CONTEXT context;
ULONG size;
NTSTATUS status;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock (&deviceExtension->ConfigurationRemoveLock,
GenUSB_Timer);
if (!NT_SUCCESS(status)) {
return;
}
//
// BUGBUG preallocate this structure;
// allowing the workitem and this timer to run at the same time.
//
size = sizeof (GENUSB_ABORT_CONTEXT)
+ sizeof (USBD_PIPE_HANDLE) * deviceExtension->TotalNumberOfPipes;
context = ExAllocatePool (NonPagedPool, size);
if (NULL == context)
{
status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
context->WorkItem = IoAllocateWorkItem (DeviceObject);
if (NULL == context->WorkItem)
{
status = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool (context);
return;
}
context->NumHandles = 0;
KeAcquireSpinLock (&deviceExtension->SpinLock, &irql);
{
// Walk through the list of interfaces and then pipes on those interfaces
// to find any pipes that may need a bit of a bump.
for (i=0; i < deviceExtension->InterfacesFound; i++)
{
inter = deviceExtension->Interface [i];
for (j=0; j < inter->NumberOfPipes; j++)
{
pipe = &inter->Pipes[j];
// now test for the timeout (given the assumptions above)
if (pipe->OutstandingIO)
{
if (0 != pipe->Properties.Timeout)
{
ASSERT (0 < pipe->CurrentTimeout);
if (0 == InterlockedDecrement (&pipe->CurrentTimeout))
{
// abort this pipe.
context->Handles[context->NumHandles]
= pipe->Info.PipeHandle;
context->NumHandles++;
}
}
}
}
}
}
KeReleaseSpinLock (&deviceExtension->SpinLock, irql);
LOGENTRY(deviceExtension,
'Time',
deviceExtension->InterfacesFound,
deviceExtension->TotalNumberOfPipes,
context->NumHandles);
if (0 < context->NumHandles)
{
IoQueueWorkItem (context->WorkItem,
GenUSB_AbortPipeWorker,
DelayedWorkQueue,
context);
}
else
{
IoFreeWorkItem (context->WorkItem);
ExFreePool (context);
IoReleaseRemoveLock (&deviceExtension->ConfigurationRemoveLock,
GenUSB_Timer);
}
return;
}
//******************************************************************************
//
// GenUSB_ResetPipe()
//
//******************************************************************************
NTSTATUS
GenUSB_ResetPipe (
IN PDEVICE_EXTENSION DeviceExtension,
IN USBD_PIPE_HANDLE UsbdPipeHandle,
IN BOOLEAN ResetPipe,
IN BOOLEAN ClearStall,
IN BOOLEAN FlushData
)
{
NTSTATUS status;
struct _URB_PIPE_REQUEST urb;
PAGED_CODE ();
DBGPRINT(2, ("enter: GenUSB_ResetPipe\n"));
LOGENTRY(DeviceExtension, 'RESP',
UsbdPipeHandle,
(ResetPipe << 24) | (ClearStall << 16) | (FlushData << 8),
0);
RtlZeroMemory (&urb, sizeof (urb));
urb.Hdr.Length = sizeof (urb);
urb.PipeHandle = UsbdPipeHandle;
if (ResetPipe && ClearStall)
{
urb.Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
}
else if (ResetPipe)
{
urb.Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE;
}
else if (ClearStall)
{
urb.Hdr.Function = URB_FUNCTION_SYNC_CLEAR_STALL;
}
status = GenUSB_SyncSendUsbRequest (DeviceExtension->Self, (PURB) &urb);
LOGENTRY(DeviceExtension, 'resp',
UsbdPipeHandle,
(ResetPipe << 24) | (ClearStall << 16) | (FlushData << 8),
status);
DBGPRINT(2, ("exit: GenUSB_ResetPipe %08X\n", status));
return status;
}