reactos/drivers/usb/usbport/device.c
Thomas Faber ac20ab031c
[USBPORT] Correctly handle alternate settings returned from USBPORT_ParseConfigurationDescriptor.
The last parameter of USBPORT_ParseConfigurationDescriptor is a pointer
to a boolean indicating whether any alternate interface settings were
found for the specified interface.
Interpreting it as an alternate setting value, as we did before,
would always override the alternate setting to '1' (if any alternate
descriptors were present), therefore selecting the wrong interface
setting, and possibly causing a buffer overflow on the InterfaceList's
Pipes array.

Found by Special Pool.
2019-03-11 08:53:55 +01:00

2027 lines
62 KiB
C

/*
* PROJECT: ReactOS USB Port Driver
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: USBPort device functions
* COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
*/
#include "usbport.h"
#define NDEBUG
#include <debug.h>
NTSTATUS
NTAPI
USBPORT_SendSetupPacket(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
IN PDEVICE_OBJECT FdoDevice,
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN PVOID Buffer,
IN ULONG Length,
IN OUT PULONG TransferedLen,
IN OUT PUSBD_STATUS pUSBDStatus)
{
PURB Urb;
PMDL Mdl;
USBD_STATUS USBDStatus;
KEVENT Event;
NTSTATUS Status;
DPRINT("USBPORT_SendSetupPacket: DeviceHandle - %p, FdoDevice - %p, SetupPacket - %p, Buffer - %p, Length - %x, TransferedLen - %x, pUSBDStatus - %x\n",
DeviceHandle,
FdoDevice,
SetupPacket,
Buffer,
Length,
TransferedLen,
pUSBDStatus);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Urb = ExAllocatePoolWithTag(NonPagedPool,
sizeof(struct _URB_CONTROL_TRANSFER),
USB_PORT_TAG);
if (Urb)
{
InterlockedIncrement(&DeviceHandle->DeviceHandleLock);
RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_TRANSFER));
RtlCopyMemory(Urb->UrbControlTransfer.SetupPacket,
SetupPacket,
sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
Urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
Urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
Urb->UrbHeader.UsbdDeviceHandle = DeviceHandle;
Urb->UrbHeader.UsbdFlags = 0;
Urb->UrbControlTransfer.PipeHandle = &DeviceHandle->PipeHandle;
Urb->UrbControlTransfer.TransferBufferLength = Length;
Urb->UrbControlTransfer.TransferBuffer = Buffer;
Urb->UrbControlTransfer.TransferBufferMDL = NULL;
Urb->UrbControlTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK |
USBD_TRANSFER_DIRECTION;
if (SetupPacket->bmRequestType.Dir != BMREQUEST_DEVICE_TO_HOST)
{
Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN;
}
Status = STATUS_SUCCESS;
if (Length)
{
Mdl = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);
Urb->UrbControlTransfer.TransferBufferMDL = Mdl;
if (Mdl)
{
Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_MDL;
MmBuildMdlForNonPagedPool(Mdl);
}
else
{
Status = USBPORT_USBDStatusToNtStatus(NULL,
USBD_STATUS_INSUFFICIENT_RESOURCES);
}
}
if (NT_SUCCESS(Status))
{
USBDStatus = USBPORT_AllocateTransfer(FdoDevice,
Urb,
NULL,
NULL,
&Event);
if (USBD_SUCCESS(USBDStatus))
{
InterlockedIncrement(&DeviceHandle->DeviceHandleLock);
USBPORT_QueueTransferUrb(Urb);
KeWaitForSingleObject(&Event,
Suspended,
KernelMode,
FALSE,
NULL);
USBDStatus = Urb->UrbHeader.Status;
}
Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
if (TransferedLen)
*TransferedLen = Urb->UrbControlTransfer.TransferBufferLength;
if (pUSBDStatus)
*pUSBDStatus = USBDStatus;
}
InterlockedDecrement(&DeviceHandle->DeviceHandleLock);
ExFreePoolWithTag(Urb, USB_PORT_TAG);
}
else
{
if (pUSBDStatus)
*pUSBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
Status = USBPORT_USBDStatusToNtStatus(NULL,
USBD_STATUS_INSUFFICIENT_RESOURCES);
}
DPRINT("USBPORT_SendSetupPacket: Status - %x\n", Status);
return Status;
}
ULONG
NTAPI
USBPORT_GetInterfaceLength(IN PUSB_INTERFACE_DESCRIPTOR iDescriptor,
IN ULONG_PTR EndDescriptors)
{
SIZE_T Length;
PUSB_ENDPOINT_DESCRIPTOR Descriptor;
ULONG ix;
DPRINT("USBPORT_GetInterfaceLength ... \n");
Length = iDescriptor->bLength;
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)iDescriptor + Length);
if (iDescriptor->bNumEndpoints)
{
for (ix = 0; ix < iDescriptor->bNumEndpoints; ix++)
{
while ((Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE) &&
(Descriptor->bLength > 0))
{
Length += Descriptor->bLength;
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
Descriptor->bLength);
}
Length += Descriptor->bLength;
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
Descriptor->bLength);
}
}
while (((ULONG_PTR)Descriptor < EndDescriptors) &&
(Descriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE) &&
(Descriptor->bLength > 0))
{
Length += Descriptor->bLength;
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
Descriptor->bLength);
}
return Length;
}
PUSB_INTERFACE_DESCRIPTOR
NTAPI
USBPORT_ParseConfigurationDescriptor(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor,
IN UCHAR InterfaceNumber,
IN UCHAR Alternate,
OUT PBOOLEAN HasAlternates)
{
PUSB_CONFIGURATION_DESCRIPTOR TmpDescriptor;
PUSB_INTERFACE_DESCRIPTOR iDescriptor;
PUSB_INTERFACE_DESCRIPTOR OutDescriptor = NULL;
ULONG_PTR Descriptor = (ULONG_PTR)ConfigDescriptor;
ULONG_PTR EndDescriptors;
ULONG ix;
DPRINT("USBPORT_ParseConfigurationDescriptor ... \n");
if (HasAlternates)
*HasAlternates = FALSE;
for (TmpDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)ConfigDescriptor + ConfigDescriptor->bLength);
TmpDescriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE && TmpDescriptor->bLength > 0;
TmpDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)TmpDescriptor + TmpDescriptor->bLength))
;
iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)TmpDescriptor;
EndDescriptors = (ULONG_PTR)ConfigDescriptor +
ConfigDescriptor->wTotalLength;
while ((Descriptor < EndDescriptors) &&
(iDescriptor->bInterfaceNumber != InterfaceNumber))
{
Descriptor = (ULONG_PTR)iDescriptor +
USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors);
iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor;
}
ix = 0;
while (Descriptor < EndDescriptors &&
iDescriptor->bInterfaceNumber == InterfaceNumber)
{
if (iDescriptor->bAlternateSetting == Alternate)
OutDescriptor = iDescriptor;
Descriptor = (ULONG_PTR)iDescriptor +
USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors);
iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor;
++ix;
}
if ((ix > 1) && HasAlternates)
*HasAlternates = TRUE;
return OutDescriptor;
}
USBD_STATUS
NTAPI
USBPORT_OpenInterface(IN PURB Urb,
IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_CONFIGURATION_HANDLE ConfigHandle,
IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
IN OUT PUSBPORT_INTERFACE_HANDLE *iHandle,
IN BOOLEAN IsSetInterface)
{
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
PUSBPORT_INTERFACE_HANDLE InterfaceHandle = NULL;
PUSBPORT_PIPE_HANDLE PipeHandle;
PUSB_ENDPOINT_DESCRIPTOR Descriptor;
PUSBD_PIPE_INFORMATION PipeInfo;
BOOLEAN HasAlternates;
ULONG NumEndpoints;
SIZE_T Length;
SIZE_T HandleLength;
BOOLEAN IsAllocated = FALSE;
USHORT MaxPacketSize;
USHORT wMaxPacketSize;
ULONG ix;
USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS;
NTSTATUS Status;
DPRINT("USBPORT_OpenInterface: ...\n");
InterfaceDescriptor = USBPORT_ParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor,
InterfaceInfo->InterfaceNumber,
InterfaceInfo->AlternateSetting,
&HasAlternates);
NumEndpoints = InterfaceDescriptor->bNumEndpoints;
Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) +
NumEndpoints * sizeof(USBD_PIPE_INFORMATION);
if (HasAlternates && IsSetInterface)
{
DPRINT1("USBPORT_OpenInterface: InterfaceInfo->AlternateSetting && IsSetInterface !\n");
}
if (*iHandle)
{
InterfaceHandle = *iHandle;
}
else
{
HandleLength = FIELD_OFFSET(USBPORT_INTERFACE_HANDLE, PipeHandle) +
NumEndpoints * sizeof(USBPORT_PIPE_HANDLE);
InterfaceHandle = ExAllocatePoolWithTag(NonPagedPool,
HandleLength,
USB_PORT_TAG);
if (!InterfaceHandle)
{
USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
RtlZeroMemory(InterfaceHandle, HandleLength);
for (ix = 0; ix < NumEndpoints; ++ix)
{
PipeHandle = &InterfaceHandle->PipeHandle[ix];
PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED;
PipeHandle->Endpoint = NULL;
}
IsAllocated = TRUE;
}
InterfaceHandle->AlternateSetting = InterfaceInfo->AlternateSetting;
RtlCopyMemory(&InterfaceHandle->InterfaceDescriptor,
InterfaceDescriptor,
sizeof(USB_INTERFACE_DESCRIPTOR));
InterfaceInfo->Class = InterfaceDescriptor->bInterfaceClass;
InterfaceInfo->SubClass = InterfaceDescriptor->bInterfaceSubClass;
InterfaceInfo->Protocol = InterfaceDescriptor->bInterfaceProtocol;
InterfaceInfo->Reserved = 0;
InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor +
InterfaceDescriptor->bLength);
for (ix = 0; ix < NumEndpoints; ++ix)
{
PipeHandle = &InterfaceHandle->PipeHandle[ix];
while (Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE)
{
if (Descriptor->bLength == 0)
{
break;
}
else
{
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
Descriptor->bLength);
}
}
if (InterfaceInfo->Pipes[ix].PipeFlags & USBD_PF_CHANGE_MAX_PACKET)
{
Descriptor->wMaxPacketSize = InterfaceInfo->Pipes[ix].MaximumPacketSize;
}
RtlCopyMemory(&PipeHandle->EndpointDescriptor,
Descriptor,
sizeof(USB_ENDPOINT_DESCRIPTOR));
PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED;
PipeHandle->PipeFlags = InterfaceInfo->Pipes[ix].PipeFlags;
PipeHandle->Endpoint = NULL;
wMaxPacketSize = Descriptor->wMaxPacketSize;
/* USB 2.0 Specification, 5.9 High-Speed, High Bandwidth Endpoints */
MaxPacketSize = (wMaxPacketSize & 0x7FF) * (((wMaxPacketSize >> 11) & 3) + 1);
InterfaceInfo->Pipes[ix].EndpointAddress = Descriptor->bEndpointAddress;
InterfaceInfo->Pipes[ix].PipeType = Descriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK;
InterfaceInfo->Pipes[ix].MaximumPacketSize = MaxPacketSize;
InterfaceInfo->Pipes[ix].PipeHandle = (USBD_PIPE_HANDLE)-1;
InterfaceInfo->Pipes[ix].Interval = Descriptor->bInterval;
Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor +
Descriptor->bLength);
}
if (USBD_SUCCESS(USBDStatus))
{
for (ix = 0; ix < NumEndpoints; ++ix)
{
PipeInfo = &InterfaceInfo->Pipes[ix];
PipeHandle = &InterfaceHandle->PipeHandle[ix];
Status = USBPORT_OpenPipe(FdoDevice,
DeviceHandle,
PipeHandle,
&USBDStatus);
if (!NT_SUCCESS(Status))
break;
PipeInfo->PipeHandle = PipeHandle;
}
if (NumEndpoints)
{
USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
}
}
Exit:
if (USBD_SUCCESS(USBDStatus))
{
InterfaceInfo->InterfaceHandle = InterfaceHandle;
*iHandle = InterfaceHandle;
InterfaceInfo->Length = Length;
}
else
{
if (InterfaceHandle)
{
if (NumEndpoints)
{
DPRINT1("USBPORT_OpenInterface: USBDStatus - %lx\n", USBDStatus);
}
if (IsAllocated)
ExFreePoolWithTag(InterfaceHandle, USB_PORT_TAG);
}
}
return USBDStatus;
}
VOID
NTAPI
USBPORT_CloseConfiguration(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
IN PDEVICE_OBJECT FdoDevice)
{
PUSBPORT_CONFIGURATION_HANDLE ConfigHandle;
PLIST_ENTRY iHandleList;
PUSBPORT_INTERFACE_HANDLE iHandle;
ULONG NumEndpoints;
PUSBPORT_PIPE_HANDLE PipeHandle;
DPRINT("USBPORT_CloseConfiguration: ... \n");
ConfigHandle = DeviceHandle->ConfigHandle;
if (ConfigHandle)
{
iHandleList = &ConfigHandle->InterfaceHandleList;
while (!IsListEmpty(iHandleList))
{
iHandle = CONTAINING_RECORD(iHandleList->Flink,
USBPORT_INTERFACE_HANDLE,
InterfaceLink);
DPRINT("USBPORT_CloseConfiguration: iHandle - %p\n", iHandle);
RemoveHeadList(iHandleList);
NumEndpoints = iHandle->InterfaceDescriptor.bNumEndpoints;
PipeHandle = &iHandle->PipeHandle[0];
while (NumEndpoints > 0)
{
USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle);
PipeHandle += 1;
--NumEndpoints;
}
ExFreePoolWithTag(iHandle, USB_PORT_TAG);
}
ExFreePoolWithTag(ConfigHandle, USB_PORT_TAG);
DeviceHandle->ConfigHandle = NULL;
}
}
NTSTATUS
NTAPI
USBPORT_InitInterfaceInfo(IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
IN PUSBPORT_CONFIGURATION_HANDLE ConfigHandle)
{
PUSB_INTERFACE_DESCRIPTOR Descriptor;
PUSBD_PIPE_INFORMATION Pipe;
SIZE_T Length;
ULONG PipeFlags;
ULONG NumberOfPipes;
USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS;
DPRINT("USBPORT_InitInterfaceInfo: InterfaceInfo - %p, ConfigHandle - %p\n",
InterfaceInfo,
ConfigHandle);
Descriptor = USBPORT_ParseConfigurationDescriptor(ConfigHandle->ConfigurationDescriptor,
InterfaceInfo->InterfaceNumber,
InterfaceInfo->AlternateSetting,
NULL);
Length = sizeof(USBD_INTERFACE_INFORMATION) +
sizeof(USBD_PIPE_INFORMATION);
if (Descriptor)
{
NumberOfPipes = Descriptor->bNumEndpoints;
Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) +
NumberOfPipes * sizeof(USBD_PIPE_INFORMATION);
if (InterfaceInfo->Length >= Length)
{
InterfaceInfo->Class = 0;
InterfaceInfo->SubClass = 0;
InterfaceInfo->Protocol = 0;
InterfaceInfo->Reserved = 0;
InterfaceInfo->InterfaceHandle = 0;
InterfaceInfo->NumberOfPipes = NumberOfPipes;
Pipe = InterfaceInfo->Pipes;
while (NumberOfPipes > 0)
{
Pipe->EndpointAddress = 0;
Pipe->Interval = 0;
Pipe->PipeType = 0;
Pipe->PipeHandle = 0;
PipeFlags = Pipe->PipeFlags;
if (PipeFlags & ~USBD_PF_VALID_MASK)
USBDStatus = USBD_STATUS_INVALID_PIPE_FLAGS;
if (!(PipeFlags & USBD_PF_CHANGE_MAX_PACKET))
Pipe->MaximumPacketSize = 0;
Pipe += 1;
--NumberOfPipes;
}
}
else
{
USBDStatus = USBD_STATUS_BUFFER_TOO_SMALL;
}
}
else
{
USBDStatus = USBD_STATUS_INTERFACE_NOT_FOUND;
}
InterfaceInfo->Length = Length;
return USBDStatus;
}
NTSTATUS
NTAPI
USBPORT_HandleSelectConfiguration(IN PDEVICE_OBJECT FdoDevice,
IN PIRP Irp,
IN PURB Urb)
{
PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor;
PUSBPORT_DEVICE_HANDLE DeviceHandle;
PUSBPORT_CONFIGURATION_HANDLE ConfigHandle = NULL;
PUSBD_INTERFACE_INFORMATION InterfaceInfo;
PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
ULONG iNumber;
ULONG ix;
USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
NTSTATUS Status;
USBD_STATUS USBDStatus;
PUSBPORT_DEVICE_EXTENSION FdoExtension;
DPRINT("USBPORT_HandleSelectConfiguration: ConfigDescriptor %p\n",
Urb->UrbSelectConfiguration.ConfigurationDescriptor);
FdoExtension = FdoDevice->DeviceExtension;
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle;
ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor;
if (!ConfigDescriptor)
{
DPRINT("USBPORT_HandleSelectConfiguration: ConfigDescriptor == NULL\n");
RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
SetupPacket.bmRequestType.B = 0;
SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION;
SetupPacket.wValue.W = 0;
SetupPacket.wIndex.W = 0;
SetupPacket.wLength = 0;
USBPORT_SendSetupPacket(DeviceHandle,
FdoDevice,
&SetupPacket,
NULL,
0,
NULL,
NULL);
Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS);
goto Exit;
}
USBPORT_DumpingConfiguration(ConfigDescriptor);
InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
iNumber = 0;
do
{
++iNumber;
InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)
((ULONG_PTR)InterfaceInfo +
InterfaceInfo->Length);
}
while ((ULONG_PTR)InterfaceInfo < (ULONG_PTR)Urb + Urb->UrbHeader.Length);
if ((iNumber <= 0) || (iNumber != ConfigDescriptor->bNumInterfaces))
{
Status = USBPORT_USBDStatusToNtStatus(Urb,
USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR);
goto Exit;
}
ConfigHandle = ExAllocatePoolWithTag(NonPagedPool,
ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE),
USB_PORT_TAG);
if (!ConfigHandle)
{
Status = USBPORT_USBDStatusToNtStatus(Urb,
USBD_STATUS_INSUFFICIENT_RESOURCES);
goto Exit;
}
RtlZeroMemory(ConfigHandle,
ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE));
InitializeListHead(&ConfigHandle->InterfaceHandleList);
ConfigHandle->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)(ConfigHandle + 1);
RtlCopyMemory(ConfigHandle->ConfigurationDescriptor,
ConfigDescriptor,
ConfigDescriptor->wTotalLength);
RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
SetupPacket.bmRequestType.B = 0;
SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION;
SetupPacket.wValue.W = ConfigDescriptor->bConfigurationValue;
SetupPacket.wIndex.W = 0;
SetupPacket.wLength = 0;
USBPORT_SendSetupPacket(DeviceHandle,
FdoDevice,
&SetupPacket,
NULL,
0,
NULL,
&USBDStatus);
if (USBD_ERROR(USBDStatus))
{
Status = USBPORT_USBDStatusToNtStatus(Urb,
USBD_STATUS_SET_CONFIG_FAILED);
goto Exit;
}
if (iNumber <= 0)
{
Status = USBPORT_USBDStatusToNtStatus(Urb,
USBD_STATUS_SUCCESS);
goto Exit;
}
InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
for (ix = 0; ix < iNumber; ++ix)
{
USBDStatus = USBPORT_InitInterfaceInfo(InterfaceInfo,
ConfigHandle);
InterfaceHandle = NULL;
if (USBD_SUCCESS(USBDStatus))
{
USBDStatus = USBPORT_OpenInterface(Urb,
DeviceHandle,
FdoDevice,
ConfigHandle,
InterfaceInfo,
&InterfaceHandle,
TRUE);
}
if (InterfaceHandle)
{
InsertTailList(&ConfigHandle->InterfaceHandleList,
&InterfaceHandle->InterfaceLink);
}
if (USBD_ERROR(USBDStatus))
break;
InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)
((ULONG_PTR)InterfaceInfo +
InterfaceInfo->Length);
}
if (ix >= iNumber)
{
Status = USBPORT_USBDStatusToNtStatus(Urb,
USBD_STATUS_SUCCESS);
}
else
{
Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
}
Exit:
if (NT_SUCCESS(Status))
{
Urb->UrbSelectConfiguration.ConfigurationHandle = ConfigHandle;
DeviceHandle->ConfigHandle = ConfigHandle;
}
else
{
DPRINT1("USBPORT_HandleSelectConfiguration: Status %x\n", Status);
}
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
return Status;
}
VOID
NTAPI
USBPORT_AddDeviceHandle(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
DPRINT("USBPORT_AddDeviceHandle: ... \n");
FdoExtension = FdoDevice->DeviceExtension;
InsertTailList(&FdoExtension->DeviceHandleList,
&DeviceHandle->DeviceHandleLink);
}
VOID
NTAPI
USBPORT_RemoveDeviceHandle(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
KIRQL OldIrql;
DPRINT("USBPORT_RemoveDeviceHandle \n");
FdoExtension = FdoDevice->DeviceExtension;
KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql);
RemoveEntryList(&DeviceHandle->DeviceHandleLink);
KeReleaseSpinLock(&FdoExtension->DeviceHandleSpinLock, OldIrql);
}
BOOLEAN
NTAPI
USBPORT_ValidateDeviceHandle(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
KIRQL OldIrql;
PLIST_ENTRY HandleList;
PUSBPORT_DEVICE_HANDLE CurrentHandle;
BOOLEAN Result = FALSE;
//DPRINT("USBPORT_ValidateDeviceHandle: DeviceHandle - %p\n", DeviceHandle \n");
FdoExtension = FdoDevice->DeviceExtension;
KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql);
if (DeviceHandle)
{
HandleList = FdoExtension->DeviceHandleList.Flink;
while (HandleList != &FdoExtension->DeviceHandleList)
{
CurrentHandle = CONTAINING_RECORD(HandleList,
USBPORT_DEVICE_HANDLE,
DeviceHandleLink);
if (CurrentHandle == DeviceHandle)
{
Result = TRUE;
break;
}
HandleList = HandleList->Flink;
}
}
KeReleaseSpinLock(&FdoExtension->DeviceHandleSpinLock, OldIrql);
return Result;
}
BOOLEAN
NTAPI
USBPORT_DeviceHasTransfers(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
{
PLIST_ENTRY PipeHandleList;
PUSBPORT_PIPE_HANDLE PipeHandle;
DPRINT("USBPORT_DeviceHasTransfers: ... \n");
PipeHandleList = DeviceHandle->PipeHandleList.Flink;
while (PipeHandleList != &DeviceHandle->PipeHandleList)
{
PipeHandle = CONTAINING_RECORD(PipeHandleList,
USBPORT_PIPE_HANDLE,
PipeLink);
PipeHandleList = PipeHandleList->Flink;
if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE) &&
USBPORT_EndpointHasQueuedTransfers(FdoDevice, PipeHandle->Endpoint, NULL))
{
return TRUE;
}
}
return FALSE;
}
VOID
NTAPI
USBPORT_AbortTransfers(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE DeviceHandle)
{
PLIST_ENTRY HandleList;
PUSBPORT_PIPE_HANDLE PipeHandle;
BOOLEAN Result;
DPRINT("USBPORT_AbortAllTransfers: ... \n");
HandleList = DeviceHandle->PipeHandleList.Flink;
while (HandleList != &DeviceHandle->PipeHandleList)
{
PipeHandle = CONTAINING_RECORD(HandleList,
USBPORT_PIPE_HANDLE,
PipeLink);
HandleList = HandleList->Flink;
if (!(PipeHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB))
{
PipeHandle->Endpoint->Flags |= ENDPOINT_FLAG_ABORTING;
USBPORT_AbortEndpoint(FdoDevice, PipeHandle->Endpoint, NULL);
USBPORT_FlushMapTransfers(FdoDevice);
}
}
while (TRUE)
{
Result = USBPORT_DeviceHasTransfers(FdoDevice, DeviceHandle);
if (!Result)
break;
USBPORT_Wait(FdoDevice, 100);
}
}
PUSB2_TT_EXTENSION
NTAPI
USBPORT_GetTt(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
OUT PUSHORT OutPort,
OUT PUSBPORT_DEVICE_HANDLE * OutHubDeviceHandle)
{
PUSBPORT_DEVICE_HANDLE DeviceHandle = HubDeviceHandle;
ULONG TtCount;
PLIST_ENTRY Entry;
PUSB2_TT_EXTENSION TtExtension = NULL;
DPRINT("USBPORT_GetTt: HubDeviceHandle - %p\n", HubDeviceHandle);
*OutHubDeviceHandle = NULL;
while (DeviceHandle->DeviceSpeed != UsbHighSpeed)
{
DPRINT("USBPORT_GetTt: DeviceHandle - %p, DeviceHandle->PortNumber - %X\n",
DeviceHandle,
DeviceHandle->PortNumber);
*OutPort = DeviceHandle->PortNumber;
DeviceHandle = DeviceHandle->HubDeviceHandle;
if (!DeviceHandle)
return NULL;
}
TtCount = DeviceHandle->TtCount;
if (!TtCount)
return NULL;
if (IsListEmpty(&DeviceHandle->TtList))
return NULL;
Entry = DeviceHandle->TtList.Flink;
if (TtCount > 1)
{
while (Entry != &DeviceHandle->TtList)
{
ASSERT(Entry != NULL);
TtExtension = CONTAINING_RECORD(Entry,
USB2_TT_EXTENSION,
Link);
if (TtExtension->TtNumber == *OutPort)
break;
Entry = Entry->Flink;
TtExtension = NULL;
}
}
else
{
TtExtension = CONTAINING_RECORD(Entry,
USB2_TT_EXTENSION,
Link);
}
*OutHubDeviceHandle = DeviceHandle;
return TtExtension;
}
NTSTATUS
NTAPI
USBPORT_CreateDevice(IN OUT PUSB_DEVICE_HANDLE *pUsbdDeviceHandle,
IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
IN USHORT PortStatus,
IN USHORT Port)
{
PUSBPORT_DEVICE_HANDLE TtDeviceHandle = NULL;
PUSB2_TT_EXTENSION TtExtension = NULL;
USHORT port;
PUSBPORT_DEVICE_HANDLE DeviceHandle;
PUSBPORT_PIPE_HANDLE PipeHandle;
BOOL IsOpenedPipe;
PVOID DeviceDescriptor;
USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
ULONG TransferedLen;
ULONG DescriptorMinSize;
UCHAR MaxPacketSize;
PUSBPORT_DEVICE_EXTENSION FdoExtension;
PUSBPORT_REGISTRATION_PACKET Packet;
NTSTATUS Status;
DPRINT("USBPORT_CreateDevice: PortStatus - %p, Port - %x\n",
PortStatus,
Port);
FdoExtension = FdoDevice->DeviceExtension;
Packet = &FdoExtension->MiniPortInterface->Packet;
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
if (!USBPORT_ValidateDeviceHandle(FdoDevice, HubDeviceHandle))
{
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
DPRINT1("USBPORT_CreateDevice: Not valid hub DeviceHandle\n");
return STATUS_DEVICE_NOT_CONNECTED;
}
port = Port;
if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2 &&
!(PortStatus & USB_PORT_STATUS_HIGH_SPEED))
{
DPRINT1("USBPORT_CreateDevice: USB1 device connected to USB2 port\n");
TtExtension = USBPORT_GetTt(FdoDevice,
HubDeviceHandle,
&port,
&TtDeviceHandle);
DPRINT("USBPORT_CreateDevice: TtDeviceHandle - %p, port - %x\n",
TtDeviceHandle,
port);
}
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
DeviceHandle = ExAllocatePoolWithTag(NonPagedPool,
sizeof(USBPORT_DEVICE_HANDLE),
USB_PORT_TAG);
if (!DeviceHandle)
{
DPRINT1("USBPORT_CreateDevice: Not allocated DeviceHandle\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(DeviceHandle, sizeof(USBPORT_DEVICE_HANDLE));
*pUsbdDeviceHandle = NULL;
DeviceHandle->TtExtension = TtExtension;
DeviceHandle->PortNumber = Port;
DeviceHandle->HubDeviceHandle = HubDeviceHandle;
if (PortStatus & USB_PORT_STATUS_LOW_SPEED)
{
DeviceHandle->DeviceSpeed = UsbLowSpeed;
}
else if (PortStatus & USB_PORT_STATUS_HIGH_SPEED)
{
DeviceHandle->DeviceSpeed = UsbHighSpeed;
}
else
{
DeviceHandle->DeviceSpeed = UsbFullSpeed;
}
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
PipeHandle = &DeviceHandle->PipeHandle;
PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED;
PipeHandle->EndpointDescriptor.bLength = sizeof(PipeHandle->EndpointDescriptor);
PipeHandle->EndpointDescriptor.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE;
if (DeviceHandle->DeviceSpeed == UsbLowSpeed)
{
PipeHandle->EndpointDescriptor.wMaxPacketSize = 8;
}
else
{
PipeHandle->EndpointDescriptor.wMaxPacketSize = USB_DEFAULT_MAX_PACKET;
}
InitializeListHead(&DeviceHandle->PipeHandleList);
InitializeListHead(&DeviceHandle->TtList);
Status = USBPORT_OpenPipe(FdoDevice,
DeviceHandle,
PipeHandle,
NULL);
IsOpenedPipe = NT_SUCCESS(Status);
if (NT_ERROR(Status))
{
DPRINT1("USBPORT_CreateDevice: USBPORT_OpenPipe return - %lx\n", Status);
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG);
return Status;
}
DeviceDescriptor = ExAllocatePoolWithTag(NonPagedPool,
USB_DEFAULT_MAX_PACKET,
USB_PORT_TAG);
if (!DeviceDescriptor)
{
DPRINT1("USBPORT_CreateDevice: Not allocated DeviceDescriptor\n");
goto ErrorExit;
}
RtlZeroMemory(DeviceDescriptor, USB_DEFAULT_MAX_PACKET);
RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
SetupPacket.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
SetupPacket.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
SetupPacket.wLength = USB_DEFAULT_MAX_PACKET;
TransferedLen = 0;
Status = USBPORT_SendSetupPacket(DeviceHandle,
FdoDevice,
&SetupPacket,
DeviceDescriptor,
USB_DEFAULT_MAX_PACKET,
&TransferedLen,
NULL);
RtlCopyMemory(&DeviceHandle->DeviceDescriptor,
DeviceDescriptor,
sizeof(USB_DEVICE_DESCRIPTOR));
ExFreePoolWithTag(DeviceDescriptor, USB_PORT_TAG);
DescriptorMinSize = RTL_SIZEOF_THROUGH_FIELD(USB_DEVICE_DESCRIPTOR,
bMaxPacketSize0);
if ((TransferedLen == DescriptorMinSize) && !NT_SUCCESS(Status))
{
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status) && (TransferedLen >= DescriptorMinSize))
{
if ((DeviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR)) &&
(DeviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE))
{
MaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
if (MaxPacketSize == 8 ||
MaxPacketSize == 16 ||
MaxPacketSize == 32 ||
MaxPacketSize == 64)
{
USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle);
*pUsbdDeviceHandle = DeviceHandle;
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
return Status;
}
}
}
DPRINT1("USBPORT_CreateDevice: ERROR!!! TransferedLen - %x, Status - %lx\n",
TransferedLen,
Status);
ErrorExit:
if (TtExtension && TtDeviceHandle)
{
SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_OTHER;
SetupPacket.bmRequestType.Reserved = 0;
SetupPacket.bmRequestType.Type = BMREQUEST_CLASS;
SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
/* Table 11-15. Hub Class Requests */
if (TtDeviceHandle == HubDeviceHandle)
{
SetupPacket.bRequest = USB_REQUEST_RESET_TT;
}
else
{
SetupPacket.bRequest = USB_REQUEST_CLEAR_TT_BUFFER;
}
SetupPacket.wValue.LowByte = 0;
SetupPacket.wValue.HiByte = 0;
SetupPacket.wIndex.W = port;
SetupPacket.wLength = 0;
USBPORT_SendSetupPacket(TtDeviceHandle,
FdoDevice,
&SetupPacket,
NULL,
0,
NULL,
NULL);
}
Status = STATUS_DEVICE_DATA_ERROR;
if (IsOpenedPipe)
{
USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle);
}
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG);
return Status;
}
ULONG
NTAPI
USBPORT_AllocateUsbAddress(IN PDEVICE_OBJECT FdoDevice)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
ULONG BitMapIdx;
ULONG BitNumber;
ULONG ix;
DPRINT("USBPORT_AllocateUsbAddress \n");
FdoExtension = FdoDevice->DeviceExtension;
for (ix = 0; ix < 4; ++ix)
{
BitMapIdx = 1;
for (BitNumber = 0; BitNumber < 32; ++BitNumber)
{
if (!(FdoExtension->UsbAddressBitMap[ix] & BitMapIdx))
{
FdoExtension->UsbAddressBitMap[ix] |= BitMapIdx;
return 32 * ix + BitNumber;
}
BitMapIdx <<= 2;
}
}
return 0;
}
VOID
NTAPI
USBPORT_FreeUsbAddress(IN PDEVICE_OBJECT FdoDevice,
IN USHORT DeviceAddress)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
ULONG ix;
ULONG BitMapIdx;
ULONG BitNumber;
USHORT CurrentAddress;
DPRINT("USBPORT_FreeUsbAddress: DeviceAddress - %x\n", DeviceAddress);
FdoExtension = FdoDevice->DeviceExtension;
for (ix = 0; ix < 4; ++ix)
{
BitMapIdx = 1;
CurrentAddress = 32 * ix;
for (BitNumber = 0; BitNumber < 32; ++BitNumber)
{
if (CurrentAddress == DeviceAddress)
{
FdoExtension->UsbAddressBitMap[ix] &= ~BitMapIdx;
return;
}
BitMapIdx <<= 2;
CurrentAddress++;
}
}
}
NTSTATUS
NTAPI
USBPORT_InitializeDevice(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
IN PDEVICE_OBJECT FdoDevice)
{
PUSBPORT_ENDPOINT Endpoint;
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
ULONG TransferedLen;
USHORT DeviceAddress = 0;
UCHAR MaxPacketSize;
NTSTATUS Status;
PUSBPORT_DEVICE_EXTENSION FdoExtension;
DPRINT("USBPORT_InitializeDevice: ... \n");
ASSERT(DeviceHandle != NULL);
FdoExtension = FdoDevice->DeviceExtension;
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
DeviceAddress = USBPORT_AllocateUsbAddress(FdoDevice);
ASSERT(DeviceHandle->DeviceAddress == USB_DEFAULT_DEVICE_ADDRESS);
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS;
CtrlSetup.wValue.W = DeviceAddress;
Status = USBPORT_SendSetupPacket(DeviceHandle,
FdoDevice,
&CtrlSetup,
NULL,
0,
NULL,
NULL);
DPRINT("USBPORT_InitializeDevice: DeviceAddress - %x. SendSetupPacket Status - %x\n",
DeviceAddress,
Status);
if (!NT_SUCCESS(Status))
goto ExitError;
DeviceHandle->DeviceAddress = DeviceAddress;
Endpoint = DeviceHandle->PipeHandle.Endpoint;
Endpoint->EndpointProperties.TotalMaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
Endpoint->EndpointProperties.DeviceAddress = DeviceAddress;
Status = USBPORT_ReopenPipe(FdoDevice, Endpoint);
if (!NT_SUCCESS(Status))
goto ExitError;
USBPORT_Wait(FdoDevice, 10);
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
CtrlSetup.bmRequestType.B = 0x80;
Status = USBPORT_SendSetupPacket(DeviceHandle,
FdoDevice,
&CtrlSetup,
&DeviceHandle->DeviceDescriptor,
sizeof(USB_DEVICE_DESCRIPTOR),
&TransferedLen,
NULL);
if (NT_SUCCESS(Status))
{
ASSERT(TransferedLen == sizeof(USB_DEVICE_DESCRIPTOR));
ASSERT(DeviceHandle->DeviceDescriptor.bLength >= sizeof(USB_DEVICE_DESCRIPTOR));
ASSERT(DeviceHandle->DeviceDescriptor.bDescriptorType == USB_DEVICE_DESCRIPTOR_TYPE);
MaxPacketSize = DeviceHandle->DeviceDescriptor.bMaxPacketSize0;
ASSERT((MaxPacketSize == 8) ||
(MaxPacketSize == 16) ||
(MaxPacketSize == 32) ||
(MaxPacketSize == 64));
if (DeviceHandle->DeviceSpeed == UsbHighSpeed &&
DeviceHandle->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_HUB)
{
DeviceHandle->Flags |= DEVICE_HANDLE_FLAG_USB2HUB;
}
}
else
{
ExitError:
DPRINT1("USBPORT_InitializeDevice: ExitError. Status - %x\n", Status);
}
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
return Status;
}
NTSTATUS
NTAPI
USBPORT_GetUsbDescriptor(IN PUSBPORT_DEVICE_HANDLE DeviceHandle,
IN PDEVICE_OBJECT FdoDevice,
IN UCHAR Type,
IN PUCHAR ConfigDesc,
IN PULONG ConfigDescSize)
{
USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
DPRINT("USBPORT_GetUsbDescriptor: Type - %x\n");
RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
SetupPacket.bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST;
SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR;
SetupPacket.wValue.HiByte = Type;
SetupPacket.wLength = (USHORT)*ConfigDescSize;
return USBPORT_SendSetupPacket(DeviceHandle,
FdoDevice,
&SetupPacket,
ConfigDesc,
*ConfigDescSize,
ConfigDescSize,
NULL);
}
PUSBPORT_INTERFACE_HANDLE
NTAPI
USBPORT_GetInterfaceHandle(IN PUSBPORT_CONFIGURATION_HANDLE ConfigurationHandle,
IN UCHAR InterfaceNumber)
{
PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
PLIST_ENTRY iHandleList;
UCHAR InterfaceNum;
DPRINT("USBPORT_GetInterfaceHandle: ConfigurationHandle - %p, InterfaceNumber - %p\n",
ConfigurationHandle,
InterfaceNumber);
iHandleList = ConfigurationHandle->InterfaceHandleList.Flink;
while (iHandleList &&
(iHandleList != &ConfigurationHandle->InterfaceHandleList))
{
InterfaceHandle = CONTAINING_RECORD(iHandleList,
USBPORT_INTERFACE_HANDLE,
InterfaceLink);
InterfaceNum = InterfaceHandle->InterfaceDescriptor.bInterfaceNumber;
if (InterfaceNum == InterfaceNumber)
return InterfaceHandle;
iHandleList = InterfaceHandle->InterfaceLink.Flink;
}
return NULL;
}
NTSTATUS
NTAPI
USBPORT_HandleSelectInterface(IN PDEVICE_OBJECT FdoDevice,
IN PIRP Irp,
IN PURB Urb)
{
PUSBPORT_DEVICE_HANDLE DeviceHandle;
PUSBPORT_CONFIGURATION_HANDLE ConfigurationHandle;
PUSBD_INTERFACE_INFORMATION Interface;
PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
PUSBPORT_INTERFACE_HANDLE iHandle;
PUSBPORT_PIPE_HANDLE PipeHandle;
USBD_STATUS USBDStatus;
USHORT Length;
ULONG ix;
PUSBPORT_DEVICE_EXTENSION FdoExtension;
DPRINT("USBPORT_HandleSelectInterface: ... \n");
FdoExtension = FdoDevice->DeviceExtension;
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
ConfigurationHandle = Urb->UrbSelectInterface.ConfigurationHandle;
Interface = &Urb->UrbSelectInterface.Interface;
Length = Interface->Length + sizeof(USBD_PIPE_INFORMATION);
Urb->UrbHeader.Length = Length;
USBDStatus = USBPORT_InitInterfaceInfo(Interface, ConfigurationHandle);
if (USBDStatus)
{
Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1;
return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
}
DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle;
InterfaceHandle = USBPORT_GetInterfaceHandle(ConfigurationHandle,
Interface->InterfaceNumber);
if (InterfaceHandle)
{
RemoveEntryList(&InterfaceHandle->InterfaceLink);
if (InterfaceHandle->InterfaceDescriptor.bNumEndpoints)
{
PipeHandle = &InterfaceHandle->PipeHandle[0];
for (ix = 0;
ix < InterfaceHandle->InterfaceDescriptor.bNumEndpoints;
ix++)
{
USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle);
PipeHandle += 1;
}
}
}
iHandle = 0;
USBDStatus = USBPORT_OpenInterface(Urb,
DeviceHandle,
FdoDevice,
ConfigurationHandle,
Interface,
&iHandle,
1);
if (USBDStatus)
{
Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1;
}
else
{
if (InterfaceHandle)
ExFreePoolWithTag(InterfaceHandle, USB_PORT_TAG);
Interface->InterfaceHandle = iHandle;
InsertTailList(&ConfigurationHandle->InterfaceHandleList,
&iHandle->InterfaceLink);
}
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus);
}
NTSTATUS
NTAPI
USBPORT_RemoveDevice(IN PDEVICE_OBJECT FdoDevice,
IN OUT PUSBPORT_DEVICE_HANDLE DeviceHandle,
IN ULONG Flags)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
PUSB2_TT_EXTENSION TtExtension;
ULONG ix;
KIRQL OldIrql;
DPRINT("USBPORT_RemoveDevice: DeviceHandle - %p, Flags - %x\n",
DeviceHandle,
Flags);
FdoExtension = FdoDevice->DeviceExtension;
if ((Flags & USBD_KEEP_DEVICE_DATA) ||
(Flags & USBD_MARK_DEVICE_BUSY))
{
return STATUS_SUCCESS;
}
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
if (!USBPORT_ValidateDeviceHandle(FdoDevice, DeviceHandle))
{
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
DPRINT1("USBPORT_RemoveDevice: Not valid device handle\n");
return STATUS_DEVICE_NOT_CONNECTED;
}
USBPORT_RemoveDeviceHandle(FdoDevice, DeviceHandle);
DeviceHandle->Flags |= DEVICE_HANDLE_FLAG_REMOVED;
USBPORT_AbortTransfers(FdoDevice, DeviceHandle);
DPRINT("USBPORT_RemoveDevice: DeviceHandleLock - %x\n",
DeviceHandle->DeviceHandleLock);
while (InterlockedDecrement(&DeviceHandle->DeviceHandleLock) >= 0)
{
InterlockedIncrement(&DeviceHandle->DeviceHandleLock);
USBPORT_Wait(FdoDevice, 100);
}
DPRINT("USBPORT_RemoveDevice: DeviceHandleLock ok\n");
if (DeviceHandle->ConfigHandle)
{
USBPORT_CloseConfiguration(DeviceHandle, FdoDevice);
}
USBPORT_ClosePipe(DeviceHandle, FdoDevice, &DeviceHandle->PipeHandle);
if (DeviceHandle->DeviceAddress)
{
USBPORT_FreeUsbAddress(FdoDevice, DeviceHandle->DeviceAddress);
}
if (!IsListEmpty(&DeviceHandle->TtList))
{
DPRINT1("USBPORT_RemoveDevice: DeviceHandle->TtList not empty\n");
}
while (!IsListEmpty(&DeviceHandle->TtList))
{
TtExtension = CONTAINING_RECORD(DeviceHandle->TtList.Flink,
USB2_TT_EXTENSION,
Link);
RemoveHeadList(&DeviceHandle->TtList);
DPRINT("USBPORT_RemoveDevice: TtExtension - %p\n", TtExtension);
KeAcquireSpinLock(&FdoExtension->TtSpinLock, &OldIrql);
TtExtension->Flags |= USB2_TT_EXTENSION_FLAG_DELETED;
if (IsListEmpty(&TtExtension->EndpointList))
{
USBPORT_UpdateAllocatedBwTt(TtExtension);
for (ix = 0; ix < USB2_FRAMES; ix++)
{
FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
}
DPRINT("USBPORT_RemoveDevice: ExFreePoolWithTag TtExtension - %p\n", TtExtension);
ExFreePoolWithTag(TtExtension, USB_PORT_TAG);
}
KeReleaseSpinLock(&FdoExtension->TtSpinLock, OldIrql);
}
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
if (!(DeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB))
{
ExFreePoolWithTag(DeviceHandle, USB_PORT_TAG);
}
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
USBPORT_RestoreDevice(IN PDEVICE_OBJECT FdoDevice,
IN OUT PUSBPORT_DEVICE_HANDLE OldDeviceHandle,
IN OUT PUSBPORT_DEVICE_HANDLE NewDeviceHandle)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
PLIST_ENTRY iHandleList;
PUSBPORT_ENDPOINT Endpoint;
USBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements = {0};
USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
NTSTATUS Status = STATUS_SUCCESS;
USBD_STATUS USBDStatus;
KIRQL OldIrql;
PUSBPORT_INTERFACE_HANDLE InterfaceHandle;
PUSBPORT_PIPE_HANDLE PipeHandle;
PUSBPORT_REGISTRATION_PACKET Packet;
DPRINT("USBPORT_RestoreDevice: OldDeviceHandle - %p, NewDeviceHandle - %p\n",
OldDeviceHandle,
NewDeviceHandle);
FdoExtension = FdoDevice->DeviceExtension;
KeWaitForSingleObject(&FdoExtension->DeviceSemaphore,
Executive,
KernelMode,
FALSE,
NULL);
if (!USBPORT_ValidateDeviceHandle(FdoDevice, OldDeviceHandle))
{
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
#ifndef NDEBUG
DPRINT("USBPORT_RestoreDevice: OldDeviceHandle not valid\n");
DbgBreakPoint();
#endif
return STATUS_DEVICE_NOT_CONNECTED;
}
if (!USBPORT_ValidateDeviceHandle(FdoDevice, NewDeviceHandle))
{
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
#ifndef NDEBUG
DPRINT("USBPORT_RestoreDevice: NewDeviceHandle not valid\n");
DbgBreakPoint();
#endif
return STATUS_DEVICE_NOT_CONNECTED;
}
USBPORT_RemoveDeviceHandle(FdoDevice, OldDeviceHandle);
USBPORT_AbortTransfers(FdoDevice, OldDeviceHandle);
while (InterlockedDecrement(&OldDeviceHandle->DeviceHandleLock) >= 0)
{
InterlockedIncrement(&OldDeviceHandle->DeviceHandleLock);
USBPORT_Wait(FdoDevice, 100);
}
if (sizeof(USB_DEVICE_DESCRIPTOR) == RtlCompareMemory(&NewDeviceHandle->DeviceDescriptor,
&OldDeviceHandle->DeviceDescriptor,
sizeof(USB_DEVICE_DESCRIPTOR)))
{
NewDeviceHandle->ConfigHandle = OldDeviceHandle->ConfigHandle;
if (OldDeviceHandle->ConfigHandle)
{
RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
SetupPacket.bRequest = USB_REQUEST_SET_CONFIGURATION;
SetupPacket.wValue.W = OldDeviceHandle->ConfigHandle->ConfigurationDescriptor->bConfigurationValue;
SetupPacket.wIndex.W = 0;
SetupPacket.wLength = 0;
USBPORT_SendSetupPacket(NewDeviceHandle,
FdoDevice,
&SetupPacket,
NULL,
0,
NULL,
&USBDStatus);
if (USBD_ERROR(USBDStatus))
Status = USBPORT_USBDStatusToNtStatus(NULL, USBDStatus);
if (NT_SUCCESS(Status))
{
iHandleList = NewDeviceHandle->ConfigHandle->InterfaceHandleList.Flink;
while (iHandleList &&
iHandleList != &NewDeviceHandle->ConfigHandle->InterfaceHandleList)
{
InterfaceHandle = CONTAINING_RECORD(iHandleList,
USBPORT_INTERFACE_HANDLE,
InterfaceLink);
if (InterfaceHandle->AlternateSetting)
{
RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
SetupPacket.bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE;
SetupPacket.bmRequestType.Type = BMREQUEST_STANDARD;
SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_INTERFACE;
SetupPacket.bRequest = USB_REQUEST_SET_INTERFACE;
SetupPacket.wValue.W = InterfaceHandle->InterfaceDescriptor.bAlternateSetting;
SetupPacket.wIndex.W = InterfaceHandle->InterfaceDescriptor.bInterfaceNumber;
SetupPacket.wLength = 0;
USBPORT_SendSetupPacket(NewDeviceHandle,
FdoDevice,
&SetupPacket,
NULL,
0,
NULL,
&USBDStatus);
}
iHandleList = iHandleList->Flink;
}
}
}
if (NewDeviceHandle->Flags & DEVICE_HANDLE_FLAG_USB2HUB)
{
DPRINT1("USBPORT_RestoreDevice: FIXME Transaction Translator\n");
NewDeviceHandle->TtCount = OldDeviceHandle->TtCount;
#ifndef NDEBUG
DbgBreakPoint();
#endif
}
while (!IsListEmpty(&OldDeviceHandle->PipeHandleList))
{
PipeHandle = CONTAINING_RECORD(OldDeviceHandle->PipeHandleList.Flink,
USBPORT_PIPE_HANDLE,
PipeLink);
DPRINT("USBPORT_RestoreDevice: PipeHandle - %p\n", PipeHandle);
USBPORT_RemovePipeHandle(OldDeviceHandle, PipeHandle);
if (PipeHandle != &OldDeviceHandle->PipeHandle)
{
USBPORT_AddPipeHandle(NewDeviceHandle, PipeHandle);
if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE))
{
Endpoint = PipeHandle->Endpoint;
Endpoint->DeviceHandle = NewDeviceHandle;
Endpoint->EndpointProperties.DeviceAddress = NewDeviceHandle->DeviceAddress;
Packet = &FdoExtension->MiniPortInterface->Packet;
if (!(Endpoint->Flags & ENDPOINT_FLAG_NUKE))
{
KeAcquireSpinLock(&FdoExtension->MiniportSpinLock,
&OldIrql);
Packet->ReopenEndpoint(FdoExtension->MiniPortExt,
&Endpoint->EndpointProperties,
Endpoint + 1);
Packet->SetEndpointDataToggle(FdoExtension->MiniPortExt,
Endpoint + 1,
0);
Packet->SetEndpointStatus(FdoExtension->MiniPortExt,
Endpoint + 1,
USBPORT_ENDPOINT_RUN);
KeReleaseSpinLock(&FdoExtension->MiniportSpinLock,
OldIrql);
}
else
{
MiniportCloseEndpoint(FdoDevice, Endpoint);
RtlZeroMemory(Endpoint + 1, Packet->MiniPortEndpointSize);
RtlZeroMemory((PVOID)Endpoint->EndpointProperties.BufferVA,
Endpoint->EndpointProperties.BufferLength);
KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt,
&Endpoint->EndpointProperties,
&EndpointRequirements);
KeReleaseSpinLock(&FdoExtension->MiniportSpinLock,
OldIrql);
MiniportOpenEndpoint(FdoDevice, Endpoint);
Endpoint->Flags &= ~(ENDPOINT_FLAG_NUKE |
ENDPOINT_FLAG_ABORTING);
KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
&Endpoint->EndpointOldIrql);
if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE)
{
KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock);
Packet->SetEndpointState(FdoExtension->MiniPortExt,
Endpoint + 1,
USBPORT_ENDPOINT_ACTIVE);
KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock);
}
KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
Endpoint->EndpointOldIrql);
}
}
}
}
USBPORT_AddPipeHandle(OldDeviceHandle, &OldDeviceHandle->PipeHandle);
}
else
{
#ifndef NDEBUG
DPRINT("USBPORT_RestoreDevice: New DeviceDescriptor != Old DeviceDescriptor\n");
DbgBreakPoint();
#endif
Status = STATUS_UNSUCCESSFUL;
}
USBPORT_ClosePipe(OldDeviceHandle, FdoDevice, &OldDeviceHandle->PipeHandle);
if (OldDeviceHandle->DeviceAddress != 0)
USBPORT_FreeUsbAddress(FdoDevice, OldDeviceHandle->DeviceAddress);
KeReleaseSemaphore(&FdoExtension->DeviceSemaphore,
LOW_REALTIME_PRIORITY,
1,
FALSE);
ExFreePoolWithTag(OldDeviceHandle, USB_PORT_TAG);
return Status;
}
NTSTATUS
NTAPI
USBPORT_InitializeTT(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
IN ULONG TtNumber)
{
PUSBPORT_DEVICE_EXTENSION FdoExtension;
PUSB2_TT_EXTENSION TtExtension;
ULONG ix;
DPRINT("USBPORT_InitializeTT: HubDeviceHandle - %p, TtNumber - %X\n",
HubDeviceHandle,
TtNumber);
FdoExtension = FdoDevice->DeviceExtension;
TtExtension = ExAllocatePoolWithTag(NonPagedPool,
sizeof(USB2_TT_EXTENSION),
USB_PORT_TAG);
if (!TtExtension)
{
DPRINT1("USBPORT_InitializeTT: ExAllocatePoolWithTag return NULL\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
DPRINT("USBPORT_InitializeTT: TtExtension - %p\n", TtExtension);
RtlZeroMemory(TtExtension, sizeof(USB2_TT_EXTENSION));
TtExtension->DeviceAddress = HubDeviceHandle->DeviceAddress;
TtExtension->TtNumber = TtNumber;
TtExtension->RootHubPdo = FdoExtension->RootHubPdo;
TtExtension->BusBandwidth = TOTAL_USB11_BUS_BANDWIDTH;
InitializeListHead(&TtExtension->EndpointList);
/* 90% maximum allowed for periodic endpoints */
for (ix = 0; ix < USB2_FRAMES; ix++)
{
TtExtension->Bandwidth[ix] = TtExtension->BusBandwidth -
TtExtension->BusBandwidth / 10;
}
USBPORT_UpdateAllocatedBwTt(TtExtension);
for (ix = 0; ix < USB2_FRAMES; ix++)
{
FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth;
}
USB2_InitTT(FdoExtension->Usb2Extension, &TtExtension->Tt);
InsertTailList(&HubDeviceHandle->TtList, &TtExtension->Link);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
USBPORT_Initialize20Hub(IN PDEVICE_OBJECT FdoDevice,
IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle,
IN ULONG TtCount)
{
NTSTATUS Status;
ULONG ix;
DPRINT("USBPORT_Initialize20Hub: TtCount - %X\n", TtCount);
if (!HubDeviceHandle)
{
return STATUS_INVALID_PARAMETER;
}
if (HubDeviceHandle->Flags & DEVICE_HANDLE_FLAG_ROOTHUB)
{
return STATUS_SUCCESS;
}
if (TtCount == 0)
{
HubDeviceHandle->TtCount = 0;
return STATUS_SUCCESS;
}
for (ix = 0; ix < TtCount; ++ix)
{
Status = USBPORT_InitializeTT(FdoDevice, HubDeviceHandle, ix + 1);
if (!NT_SUCCESS(Status))
break;
}
HubDeviceHandle->TtCount = TtCount;
return Status;
}