reactos/drivers/usb/usbport/device.c
Thomas Faber 36c1cb0910
[USBPORT] Correctly find interface descriptor in USBPORT_ParseConfigurationDescriptor
There can be other descriptors between the config descriptor and the
first interface descriptor, so we specifically need to check for
the interface descriptor type and skip anything before that.
We also need to guard against bLength == 0, which would cause an
infinite loop, instead of doing a second bDescriptorType check.
2019-03-11 08:53:53 +01:00

2026 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 PUCHAR OutAlternate)
{
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 (OutAlternate)
*OutAlternate = 0;
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) && OutAlternate)
*OutAlternate = 1;
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;
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,
&InterfaceInfo->AlternateSetting);
NumEndpoints = InterfaceDescriptor->bNumEndpoints;
Length = FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) +
NumEndpoints * sizeof(USBD_PIPE_INFORMATION);
if (InterfaceInfo->AlternateSetting && 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,
&InterfaceInfo->AlternateSetting);
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;
}