From 098839afecdbbc2eee06a0fc6e0bca32dd6a0188 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Fri, 16 Jun 2017 19:20:03 +0000 Subject: [PATCH] [USBPORT] Bring-in the usbport driver created by Vadim Galyant. CR-111 GitHub PR #27. This is the first module out of many to come, so stay tuned! Many thanks to everyone involved in the code review. Very special thanks for Thomas as his help, insight and reviews helped tremendously. svn path=/trunk/; revision=75062 --- reactos/drivers/usb/CMakeLists.txt | 1 + reactos/drivers/usb/usbport/CMakeLists.txt | 28 + reactos/drivers/usb/usbport/debug.c | 270 ++ reactos/drivers/usb/usbport/device.c | 1821 +++++++++++ reactos/drivers/usb/usbport/endpoint.c | 1560 +++++++++ reactos/drivers/usb/usbport/guid.c | 9 + reactos/drivers/usb/usbport/iface.c | 901 ++++++ reactos/drivers/usb/usbport/ioctl.c | 451 +++ reactos/drivers/usb/usbport/pnp.c | 1792 +++++++++++ reactos/drivers/usb/usbport/power.c | 703 +++++ reactos/drivers/usb/usbport/queue.c | 1389 +++++++++ reactos/drivers/usb/usbport/roothub.c | 1019 ++++++ reactos/drivers/usb/usbport/urb.c | 1061 +++++++ reactos/drivers/usb/usbport/usb2.c | 21 + reactos/drivers/usb/usbport/usbdebug.h | 128 + reactos/drivers/usb/usbport/usbport.c | 2775 +++++++++++++++++ reactos/drivers/usb/usbport/usbport.h | 1121 +++++++ reactos/drivers/usb/usbport/usbport.rc | 5 + reactos/drivers/usb/usbport/usbport.spec | 2 + .../reactos/drivers/usbport/usbmport.h | 653 ++++ 20 files changed, 15710 insertions(+) create mode 100644 reactos/drivers/usb/usbport/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbport/debug.c create mode 100644 reactos/drivers/usb/usbport/device.c create mode 100644 reactos/drivers/usb/usbport/endpoint.c create mode 100644 reactos/drivers/usb/usbport/guid.c create mode 100644 reactos/drivers/usb/usbport/iface.c create mode 100644 reactos/drivers/usb/usbport/ioctl.c create mode 100644 reactos/drivers/usb/usbport/pnp.c create mode 100644 reactos/drivers/usb/usbport/power.c create mode 100644 reactos/drivers/usb/usbport/queue.c create mode 100644 reactos/drivers/usb/usbport/roothub.c create mode 100644 reactos/drivers/usb/usbport/urb.c create mode 100644 reactos/drivers/usb/usbport/usb2.c create mode 100644 reactos/drivers/usb/usbport/usbdebug.h create mode 100644 reactos/drivers/usb/usbport/usbport.c create mode 100644 reactos/drivers/usb/usbport/usbport.h create mode 100644 reactos/drivers/usb/usbport/usbport.rc create mode 100644 reactos/drivers/usb/usbport/usbport.spec create mode 100644 reactos/sdk/include/reactos/drivers/usbport/usbmport.h diff --git a/reactos/drivers/usb/CMakeLists.txt b/reactos/drivers/usb/CMakeLists.txt index 36650c822df..d8e07f9d1ad 100644 --- a/reactos/drivers/usb/CMakeLists.txt +++ b/reactos/drivers/usb/CMakeLists.txt @@ -3,5 +3,6 @@ add_subdirectory(usbd) add_subdirectory(usbehci) add_subdirectory(usbhub) add_subdirectory(usbohci) +add_subdirectory(usbport) add_subdirectory(usbstor) add_subdirectory(usbuhci) diff --git a/reactos/drivers/usb/usbport/CMakeLists.txt b/reactos/drivers/usb/usbport/CMakeLists.txt new file mode 100644 index 00000000000..e37477eaadb --- /dev/null +++ b/reactos/drivers/usb/usbport/CMakeLists.txt @@ -0,0 +1,28 @@ + +spec2def(usbport.sys usbport.spec ADD_IMPORTLIB) + +list(APPEND SOURCE + debug.c + device.c + endpoint.c + iface.c + ioctl.c + pnp.c + power.c + queue.c + roothub.c + urb.c + usb2.c + usbport.c + usbport.h) + +add_library(usbport SHARED + ${SOURCE} + guid.c + usbport.rc + ${CMAKE_CURRENT_BINARY_DIR}/usbport.def) + +add_pch(usbport usbport.h SOURCE) +set_module_type(usbport kernelmodedriver) +add_importlibs(usbport ntoskrnl hal) +add_cd_file(TARGET usbport DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/usb/usbport/debug.c b/reactos/drivers/usb/usbport/debug.c new file mode 100644 index 00000000000..07d2f44533f --- /dev/null +++ b/reactos/drivers/usb/usbport/debug.c @@ -0,0 +1,270 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_MINIPORT +#define NDEBUG_USBPORT_URB +#include "usbdebug.h" + +ULONG +NTAPI +USBPORT_DbgPrint(IN PVOID Context, + IN ULONG Level, + IN PCH Format, + ...) +{ + DPRINT("USBPORT_DbgPrint: UNIMPLEMENTED. FIXME. \n"); + return 0; +} + +ULONG +NTAPI +USBPORT_TestDebugBreak(IN PVOID Context) +{ + DPRINT("USBPORT_TestDebugBreak: UNIMPLEMENTED. FIXME. \n"); + return 0; +} + +ULONG +NTAPI +USBPORT_AssertFailure(PVOID Context, + PVOID FailedAssertion, + PVOID FileName, + ULONG LineNumber, + PCHAR Message) +{ + DPRINT("USBPORT_AssertFailure: ... \n"); + RtlAssert(FailedAssertion, FileName, LineNumber, Message); + return 0; +} + +VOID +NTAPI +USBPORT_BugCheck(IN PVOID Context) +{ + DPRINT1("USBPORT_BugCheck: FIXME \n"); + //KeBugCheckEx(BUGCODE_USB_DRIVER, ...); + ASSERT(FALSE); +} + +ULONG +NTAPI +USBPORT_LogEntry(IN PVOID BusContext, + IN ULONG DriverTag, + IN ULONG EnumTag, + IN ULONG P1, + IN ULONG P2, + IN ULONG P3) +{ + DPRINT_MINIPORT("USBPORT_LogEntry: BusContext - %p, EnumTag - %lx, P1 - %lx, P2 - %lx, P3 - %lx\n", + BusContext, + EnumTag, + P1, + P2, + P3); + + return 0; +} + +VOID +NTAPI +USBPORT_DumpingDeviceDescriptor(IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) +{ + if (!DeviceDescriptor) + { + return; + } + + DPRINT_URB("Dumping Device Descriptor - %p\n", DeviceDescriptor); + DPRINT_URB("bLength - %x\n", DeviceDescriptor->bLength); + DPRINT_URB("bDescriptorType - %x\n", DeviceDescriptor->bDescriptorType); + DPRINT_URB("bcdUSB - %x\n", DeviceDescriptor->bcdUSB); + DPRINT_URB("bDeviceClass - %x\n", DeviceDescriptor->bDeviceClass); + DPRINT_URB("bDeviceSubClass - %x\n", DeviceDescriptor->bDeviceSubClass); + DPRINT_URB("bDeviceProtocol - %x\n", DeviceDescriptor->bDeviceProtocol); + DPRINT_URB("bMaxPacketSize0 - %x\n", DeviceDescriptor->bMaxPacketSize0); + DPRINT_URB("idVendor - %x\n", DeviceDescriptor->idVendor); + DPRINT_URB("idProduct - %x\n", DeviceDescriptor->idProduct); + DPRINT_URB("bcdDevice - %x\n", DeviceDescriptor->bcdDevice); + DPRINT_URB("iManufacturer - %x\n", DeviceDescriptor->iManufacturer); + DPRINT_URB("iProduct - %x\n", DeviceDescriptor->iProduct); + DPRINT_URB("iSerialNumber - %x\n", DeviceDescriptor->iSerialNumber); + DPRINT_URB("bNumConfigurations - %x\n", DeviceDescriptor->bNumConfigurations); +} + +VOID +NTAPI +USBPORT_DumpingConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor) +{ + PUSB_INTERFACE_DESCRIPTOR iDescriptor; + PUSB_ENDPOINT_DESCRIPTOR Descriptor; + ULONG ix; + + if (!ConfigDescriptor || + ConfigDescriptor->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + return; + } + + DPRINT_URB("Dumping ConfigDescriptor - %p\n", ConfigDescriptor); + DPRINT_URB("bLength - %x\n", ConfigDescriptor->bLength); + DPRINT_URB("bDescriptorType - %x\n", ConfigDescriptor->bDescriptorType); + DPRINT_URB("wTotalLength - %x\n", ConfigDescriptor->wTotalLength); + DPRINT_URB("bNumInterfaces - %x\n", ConfigDescriptor->bNumInterfaces); + DPRINT_URB("bConfigurationValue - %x\n", ConfigDescriptor->bConfigurationValue); + DPRINT_URB("iConfiguration - %x\n", ConfigDescriptor->iConfiguration); + DPRINT_URB("bmAttributes - %x\n", ConfigDescriptor->bmAttributes); + DPRINT_URB("MaxPower - %x\n", ConfigDescriptor->MaxPower); + + iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)ConfigDescriptor + + ConfigDescriptor->bLength); + + if (iDescriptor->bLength < sizeof(USB_INTERFACE_DESCRIPTOR)) + { + return; + } + + DPRINT_URB("Dumping iDescriptor - %p\n", iDescriptor); + DPRINT_URB("bLength - %x\n", iDescriptor->bLength); + DPRINT_URB("bDescriptorType - %x\n", iDescriptor->bDescriptorType); + DPRINT_URB("bInterfaceNumber - %x\n", iDescriptor->bInterfaceNumber); + DPRINT_URB("bAlternateSetting - %x\n", iDescriptor->bAlternateSetting); + DPRINT_URB("bNumEndpoints - %x\n", iDescriptor->bNumEndpoints); + DPRINT_URB("bInterfaceClass - %x\n", iDescriptor->bInterfaceClass); + DPRINT_URB("bInterfaceSubClass - %x\n", iDescriptor->bInterfaceSubClass); + DPRINT_URB("bInterfaceProtocol - %x\n", iDescriptor->bInterfaceProtocol); + DPRINT_URB("iInterface - %x\n", iDescriptor->iInterface); + + Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)iDescriptor + + iDescriptor->bLength); + + for (ix = 0; ix < iDescriptor->bNumEndpoints; ix++) + { + if (Descriptor->bLength < sizeof(USB_ENDPOINT_DESCRIPTOR)) + { + return; + } + + DPRINT_URB("Dumping Descriptor - %p\n", Descriptor); + DPRINT_URB("bLength - %x\n", Descriptor->bLength); + DPRINT_URB("bDescriptorType - %x\n", Descriptor->bDescriptorType); + DPRINT_URB("bEndpointAddress - %x\n", Descriptor->bEndpointAddress); + DPRINT_URB("bmAttributes - %x\n", Descriptor->bmAttributes); + DPRINT_URB("wMaxPacketSize - %x\n", Descriptor->wMaxPacketSize); + DPRINT_URB("bInterval - %x\n", Descriptor->bInterval); + + Descriptor += 1; + } +} + +VOID +NTAPI +USBPORT_DumpingCapabilities(IN PDEVICE_CAPABILITIES Capabilities) +{ + if (!Capabilities) + { + return; + } + + DPRINT("Capabilities->Size - %x\n", Capabilities->Size); + DPRINT("Capabilities->Version - %x\n", Capabilities->Version); + + DPRINT("Capabilities->DeviceD1 - %x\n", Capabilities->DeviceD1); + DPRINT("Capabilities->DeviceD2 - %x\n", Capabilities->DeviceD2); + DPRINT("Capabilities->LockSupported - %x\n", Capabilities->LockSupported); + DPRINT("Capabilities->EjectSupported - %x\n", Capabilities->EjectSupported); + DPRINT("Capabilities->Removable - %x\n", Capabilities->Removable); + DPRINT("Capabilities->DockDevice - %x\n", Capabilities->DockDevice); + DPRINT("Capabilities->UniqueID - %x\n", Capabilities->UniqueID); + DPRINT("Capabilities->SilentInstall - %x\n", Capabilities->SilentInstall); + DPRINT("Capabilities->RawDeviceOK - %x\n", Capabilities->RawDeviceOK); + DPRINT("Capabilities->SurpriseRemovalOK - %x\n", Capabilities->SurpriseRemovalOK); + + DPRINT("Capabilities->Address - %x\n", Capabilities->Address); + DPRINT("Capabilities->UINumber - %x\n", Capabilities->UINumber); + + DPRINT("Capabilities->DeviceState[0] - %x\n", Capabilities->DeviceState[0]); + DPRINT("Capabilities->DeviceState[1] - %x\n", Capabilities->DeviceState[1]); + DPRINT("Capabilities->DeviceState[2] - %x\n", Capabilities->DeviceState[2]); + DPRINT("Capabilities->DeviceState[3] - %x\n", Capabilities->DeviceState[3]); + DPRINT("Capabilities->DeviceState[4] - %x\n", Capabilities->DeviceState[4]); + DPRINT("Capabilities->DeviceState[5] - %x\n", Capabilities->DeviceState[5]); + DPRINT("Capabilities->DeviceState[6] - %x\n", Capabilities->DeviceState[6]); + + DPRINT("Capabilities->SystemWake - %x\n", Capabilities->SystemWake); + DPRINT("Capabilities->DeviceWake - %x\n", Capabilities->DeviceWake); + + DPRINT("Capabilities->D1Latency - %x\n", Capabilities->D1Latency); + DPRINT("Capabilities->D2Latency - %x\n", Capabilities->D2Latency); + DPRINT("Capabilities->D3Latency - %x\n", Capabilities->D3Latency); +} + +VOID +NTAPI +USBPORT_DumpingSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket) +{ + DPRINT("SetupPacket->bmRequestType.B - %x\n", SetupPacket->bmRequestType.B); + DPRINT("SetupPacket->bRequest - %x\n", SetupPacket->bRequest); + DPRINT("SetupPacket->wValue.LowByte - %x\n", SetupPacket->wValue.LowByte); + DPRINT("SetupPacket->wValue.HiByte - %x\n", SetupPacket->wValue.HiByte); + DPRINT("SetupPacket->wIndex.W - %x\n", SetupPacket->wIndex.W); + DPRINT("SetupPacket->wLength - %x\n", SetupPacket->wLength); +} + +VOID +NTAPI +USBPORT_DumpingURB(IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + + DPRINT_URB("UrbHeader.Length - %x\n", Urb->UrbHeader.Length); + DPRINT_URB("UrbHeader.Function - %x\n", Urb->UrbHeader.Function); + DPRINT_URB("UrbHeader.Status - %x\n", Urb->UrbHeader.Status); + DPRINT_URB("UrbHeader.UsbdDeviceHandle - %p\n", Urb->UrbHeader.UsbdDeviceHandle); + DPRINT_URB("UrbHeader.UsbdFlags - %x\n", Urb->UrbHeader.UsbdFlags); + + if (Urb->UrbHeader.Length < 0x48) + { + return; + } + + DPRINT_URB("PipeHandle - %p\n", Urb->UrbControlTransfer.PipeHandle); + DPRINT_URB("TransferFlags - %x\n", Urb->UrbControlTransfer.TransferFlags); + DPRINT_URB("TransferBufferLength - %x\n", Urb->UrbControlTransfer.TransferBufferLength); + DPRINT_URB("TransferBuffer - %p\n", Urb->UrbControlTransfer.TransferBuffer); + DPRINT_URB("TransferBufferMDL - %p\n", Urb->UrbControlTransfer.TransferBufferMDL); + DPRINT_URB("UrbLink - %p\n", Urb->UrbControlTransfer.UrbLink); + + if (Urb->UrbHeader.Length < 0x50) + { + return; + } + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET)&Urb->UrbControlTransfer.SetupPacket; + USBPORT_DumpingSetupPacket(SetupPacket); +} + +VOID +NTAPI +USBPORT_DumpingIDs(IN PVOID Buffer) +{ + PWSTR Ptr; + ULONG Length; + ULONG TotalLength = 0; + + Ptr = (PWSTR)Buffer; + + while (*Ptr) + { + DPRINT(" %S\n", Ptr); + Length = (ULONG)wcslen(Ptr) + 1; + + Ptr += Length; + TotalLength += Length; + } + + DPRINT("TotalLength: %hu\n", TotalLength); + DPRINT("\n"); +} + diff --git a/reactos/drivers/usb/usbport/device.c b/reactos/drivers/usb/usbport/device.c new file mode 100644 index 00000000000..6bb8de76604 --- /dev/null +++ b/reactos/drivers/usb/usbport/device.c @@ -0,0 +1,1821 @@ +#include "usbport.h" + +#define NDEBUG +#include + +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_CONFIGURATION_DESCRIPTOR_TYPE && TmpDescriptor->bDescriptorType > 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 NumInterfaces; + 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); + + NumInterfaces = InterfaceDescriptor->bNumEndpoints; + + Length = sizeof(USBD_INTERFACE_INFORMATION) + + (NumInterfaces - 1) * sizeof(USBD_PIPE_INFORMATION); + + if (InterfaceInfo->AlternateSetting && IsSetInterface) + { + DPRINT1("USBPORT_OpenInterface: InterfaceInfo->AlternateSetting && IsSetInterface !\n"); + } + + if (*iHandle) + { + InterfaceHandle = *iHandle; + } + else + { + HandleLength = sizeof(USBPORT_INTERFACE_HANDLE) + + (NumInterfaces - 1) * sizeof(USBPORT_PIPE_HANDLE); + + InterfaceHandle = ExAllocatePoolWithTag(NonPagedPool, + HandleLength, + USB_PORT_TAG); + + if (!InterfaceHandle) + { + USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + RtlZeroMemory(InterfaceHandle, HandleLength); + + if (NumInterfaces > 0) + { + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + for (ix = 0; ix < NumInterfaces; ++ix) + { + PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED; + PipeHandle->Endpoint = NULL; + + PipeHandle += 1; + } + } + + 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); + + if (NumInterfaces) + { + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + for (ix = 0; ix < NumInterfaces; ++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); + + PipeHandle += 1; + } + } + + if (USBD_SUCCESS(USBDStatus)) + { + if (NumInterfaces) + { + PipeInfo = &InterfaceInfo->Pipes[0]; + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + for (ix = 0; ix < NumInterfaces; ++ix) + { + Status = USBPORT_OpenPipe(FdoDevice, + DeviceHandle, + PipeHandle, + &USBDStatus); + + if (!NT_SUCCESS(Status)) + break; + + PipeInfo->PipeHandle = PipeHandle; + + PipeHandle += 1; + PipeInfo += 1; + } + + USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); + } + } + +Exit: + + if (USBD_SUCCESS(USBDStatus)) + { + InterfaceInfo->InterfaceHandle = InterfaceHandle; + *iHandle = InterfaceHandle; + InterfaceInfo->Length = Length; + } + else + { + if (InterfaceHandle) + { + if (NumInterfaces) + { + 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; + USHORT 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 = sizeof(USBD_INTERFACE_INFORMATION) + + (NumberOfPipes - 1) * 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); + } +} + +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 DeviceHandle; + PUSBPORT_PIPE_HANDLE PipeHandle; + BOOL IsOpenedPipe; + PVOID DeviceDescriptor; + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + SIZE_T TransferedLen; + SIZE_T DescriptorMinSize; + UCHAR MaxPacketSize; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + NTSTATUS Status; + + DPRINT("USBPORT_CreateDevice: PortStatus - %p, Port - %x\n", + PortStatus, + Port); + + FdoExtension = FdoDevice->DeviceExtension; + + 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; + } + + if (FdoExtension->MiniPortInterface->Packet.MiniPortFlags & USB_MINIPORT_FLAGS_USB2 && + !(PortStatus & USB_PORT_STATUS_HIGH_SPEED)) + { + DPRINT1("USBPORT_CreateDevice: USB1 device connected to USB2 port. FIXME: Transaction Translator.\n"); + DbgBreakPoint(); + } + + 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->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); + + 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: + + // FIXME: if Transaction Translator + + 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)); + } + 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; + + 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); + } + + 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; + ULONG EndpointRequirements[2] = {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_INITIALIZED) + { + DPRINT1("USBPORT_RestoreDevice: FIXME Transaction Translator\n"); + NewDeviceHandle->TtCount = OldDeviceHandle->TtCount; + } + + 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) +{ + DPRINT1("USBPORT_InitializeTT: UNIMPLEMENTED. FIXME. \n"); + 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 \n"); + + 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; +} \ No newline at end of file diff --git a/reactos/drivers/usb/usbport/endpoint.c b/reactos/drivers/usb/usbport/endpoint.c new file mode 100644 index 00000000000..355d36ea974 --- /dev/null +++ b/reactos/drivers/usb/usbport/endpoint.c @@ -0,0 +1,1560 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_CORE +#include "usbdebug.h" + +ULONG +NTAPI +USBPORT_CalculateUsbBandwidth(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG Bandwidth; + ULONG Additional; + + DPRINT("USBPORT_CalculateUsbBandwidth ... \n"); + + EndpointProperties = &Endpoint->EndpointProperties; + + switch (EndpointProperties->TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + Additional = 9; + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + Additional = 13; + break; + + default: //USBPORT_TRANSFER_TYPE_CONTROL or USBPORT_TRANSFER_TYPE_BULK + Additional = 0; + break; + } + + if (Additional == 0) + { + Bandwidth = 0; + } + else + { + Bandwidth = (EndpointProperties->TotalMaxPacketSize + Additional) * 8 * 7 / 6; + } + + if (EndpointProperties->DeviceSpeed == UsbLowSpeed) + { + Bandwidth *= 8; + } + + return Bandwidth; +} + +BOOLEAN +NTAPI +USBPORT_AllocateBandwidth(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG TransferType; + ULONG TotalBusBandwidth; + ULONG EndpointBandwidth; + ULONG Period; + + DPRINT("USBPORT_AllocateBandwidth: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + EndpointProperties = &Endpoint->EndpointProperties; + TransferType = EndpointProperties->TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) + { + EndpointProperties->ScheduleOffset = 0; + return TRUE; + } + + TotalBusBandwidth = FdoExtension->TotalBusBandwidth; + EndpointBandwidth = EndpointProperties->UsbBandwidth; + Period = EndpointProperties->Period; + + DPRINT1("USBPORT_AllocateBandwidth: FIXME. \n"); + DPRINT1("USBPORT_AllocateBandwidth: Endpoint - %p, Type - %x, TotalBandwidth - %x, EpBandwidth - %x, Period - %x\n", + Endpoint, + TransferType, + TotalBusBandwidth, + EndpointBandwidth, + Period); + + return TRUE; +} + +VOID +NTAPI +USBPORT_FreeBandwidth(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + DPRINT1("USBPORT_FreeBandwidth: UNIMPLEMENTED. FIXME. \n"); +} + +UCHAR +NTAPI +USBPORT_NormalizeHsInterval(UCHAR Interval) +{ + UCHAR interval; + + DPRINT("USBPORT_NormalizeHsInterval: Interval - %x\n", Interval); + + interval = Interval; + + if (Interval) + interval = Interval - 1; + + if (interval > 5) + interval = 5; + + return 1 << interval; +} + +BOOLEAN +NTAPI +USBPORT_EndpointHasQueuedTransfers(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint, + IN PULONG TransferCount) +{ + PLIST_ENTRY Entry; + PUSBPORT_TRANSFER Transfer; + BOOLEAN Result = FALSE; + + DPRINT_CORE("USBPORT_EndpointHasQueuedTransfers: ... \n"); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (!IsListEmpty(&Endpoint->PendingTransferList)) + Result = TRUE; + + if (!IsListEmpty(&Endpoint->TransferList)) + { + Result = TRUE; + + if (TransferCount) + { + *TransferCount = 0; + + for (Entry = Endpoint->TransferList.Flink; + Entry && Entry != &Endpoint->TransferList; + Entry = Transfer->TransferLink.Flink) + { + Transfer = CONTAINING_RECORD(Entry, + USBPORT_TRANSFER, + TransferLink); + + if (Transfer->Flags & TRANSFER_FLAG_SUBMITED) + { + ++*TransferCount; + } + } + } + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + return Result; +} + +VOID +NTAPI +USBPORT_NukeAllEndpoints(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY EndpointList; + PUSBPORT_ENDPOINT Endpoint; + KIRQL OldIrql; + + DPRINT("USBPORT_NukeAllEndpoints \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + EndpointList = FdoExtension->EndpointList.Flink; + + while (EndpointList && (EndpointList != &FdoExtension->EndpointList)) + { + Endpoint = CONTAINING_RECORD(EndpointList, + USBPORT_ENDPOINT, + EndpointLink); + + if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)) + Endpoint->Flags |= ENDPOINT_FLAG_NUKE; + + EndpointList = Endpoint->EndpointLink.Flink; + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); +} + +ULONG +NTAPI +USBPORT_GetEndpointState(IN PUSBPORT_ENDPOINT Endpoint) +{ + ULONG State; + + //DPRINT("USBPORT_GetEndpointState \n"); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); + + if (Endpoint->StateLast != Endpoint->StateNext) + { + State = USBPORT_ENDPOINT_UNKNOWN; + } + else + { + State = Endpoint->StateLast; + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + + if (State != USBPORT_ENDPOINT_ACTIVE) + { + DPRINT("USBPORT_GetEndpointState: Endpoint - %p, State - %x\n", + Endpoint, + State); + } + + return State; +} + +VOID +NTAPI +USBPORT_SetEndpointState(IN PUSBPORT_ENDPOINT Endpoint, + IN ULONG State) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + KIRQL OldIrql; + + DPRINT("USBPORT_SetEndpointState: Endpoint - %p, State - %x\n", + Endpoint, + State); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, + &Endpoint->EndpointStateOldIrql); + + if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)) + { + if (Endpoint->Flags & ENDPOINT_FLAG_NUKE) + { + Endpoint->StateLast = State; + Endpoint->StateNext = State; + + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, + Endpoint->EndpointStateOldIrql); + + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + return; + } + + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, + Endpoint->EndpointStateOldIrql); + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Packet->SetEndpointState(FdoExtension->MiniPortExt, + Endpoint + 1, + State); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + Endpoint->StateNext = State; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Endpoint->FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + ExInterlockedInsertTailList(&FdoExtension->EpStateChangeList, + &Endpoint->StateChangeLink, + &FdoExtension->EpStateChangeSpinLock); + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Packet->InterruptNextSOF(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + else + { + Endpoint->StateLast = State; + Endpoint->StateNext = State; + + if (State == USBPORT_ENDPOINT_REMOVE) + { + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, + Endpoint->EndpointStateOldIrql); + + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + return; + } + + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, + Endpoint->EndpointStateOldIrql); + } +} + +VOID +NTAPI +USBPORT_AddPipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle) +{ + DPRINT("USBPORT_AddPipeHandle: DeviceHandle - %p, PipeHandle - %p\n", + DeviceHandle, + PipeHandle); + + InsertTailList(&DeviceHandle->PipeHandleList, &PipeHandle->PipeLink); +} + +VOID +NTAPI +USBPORT_RemovePipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle) +{ + DPRINT("USBPORT_RemovePipeHandle: PipeHandle - %p\n", PipeHandle); + + RemoveEntryList(&PipeHandle->PipeLink); + + PipeHandle->PipeLink.Flink = NULL; + PipeHandle->PipeLink.Blink = NULL; +} + +BOOLEAN +NTAPI +USBPORT_ValidatePipeHandle(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle) +{ + PLIST_ENTRY HandleList; + PUSBPORT_PIPE_HANDLE CurrentHandle; + + //DPRINT("USBPORT_ValidatePipeHandle: DeviceHandle - %p, PipeHandle - %p\n", + // DeviceHandle, + // PipeHandle); + + HandleList = DeviceHandle->PipeHandleList.Flink; + + while (HandleList != &DeviceHandle->PipeHandleList) + { + CurrentHandle = CONTAINING_RECORD(HandleList, + USBPORT_PIPE_HANDLE, + PipeLink); + + HandleList = HandleList->Flink; + + if (CurrentHandle == PipeHandle) + return TRUE; + } + + return FALSE; +} + +BOOLEAN +NTAPI +USBPORT_DeleteEndpoint(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + BOOLEAN Result; + KIRQL OldIrql; + + DPRINT("USBPORT_DeleteEndpoint: Endpoint - %p\n", Endpoint); + + FdoExtension = FdoDevice->DeviceExtension; + + if ((Endpoint->WorkerLink.Flink && Endpoint->WorkerLink.Blink) || + Endpoint->LockCounter != -1) + { + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList, + &Endpoint->CloseLink, + &FdoExtension->EndpointClosedSpinLock); + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + Result = FALSE; + } + else + { + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + RemoveEntryList(&Endpoint->EndpointLink); + Endpoint->EndpointLink.Flink = NULL; + Endpoint->EndpointLink.Blink = NULL; + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + MiniportCloseEndpoint(FdoDevice, Endpoint); + + if (Endpoint->HeaderBuffer) + { + USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer); + } + + ExFreePoolWithTag(Endpoint, USB_PORT_TAG); + + Result = TRUE; + } + + return Result; +} + +VOID +NTAPI +MiniportCloseEndpoint(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + BOOLEAN IsDoDisablePeriodic; + ULONG TransferType; + KIRQL OldIrql; + + DPRINT("MiniportCloseEndpoint: Endpoint - %p\n", Endpoint); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + if (Endpoint->Flags & ENDPOINT_FLAG_OPENED) + { + TransferType = Endpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT || + TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + --FdoExtension->PeriodicEndpoints; + } + + IsDoDisablePeriodic = FdoExtension->PeriodicEndpoints == 0; + + Packet->CloseEndpoint(FdoExtension->MiniPortExt, + Endpoint + 1, + IsDoDisablePeriodic); + + Endpoint->Flags &= ~ENDPOINT_FLAG_OPENED; + Endpoint->Flags |= ENDPOINT_FLAG_CLOSED; + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); +} + +VOID +NTAPI +USBPORT_ClosePipe(IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_PIPE_HANDLE PipeHandle) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_ENDPOINT Endpoint; + BOOLEAN IsReady; + KIRQL OldIrql; + + DPRINT("USBPORT_ClosePipe \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + if (PipeHandle->Flags & PIPE_HANDLE_FLAG_CLOSED) + return; + + USBPORT_RemovePipeHandle(DeviceHandle, PipeHandle); + + PipeHandle->Flags |= PIPE_HANDLE_FLAG_CLOSED; + + if (PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE) + { + PipeHandle->Flags &= ~PIPE_HANDLE_FLAG_NULL_PACKET_SIZE; + return; + } + + Endpoint = PipeHandle->Endpoint; + DPRINT("USBPORT_ClosePipe: Endpoint - %p\n", Endpoint); + + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + if ((Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) && + (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)) + { + PdoExtension = FdoExtension->RootHubPdo->DeviceExtension; + PdoExtension->Endpoint = NULL; + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + while (TRUE) + { + IsReady = TRUE; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, + &Endpoint->EndpointOldIrql); + + if (!IsListEmpty(&Endpoint->PendingTransferList)) + IsReady = FALSE; + + if (!IsListEmpty(&Endpoint->TransferList)) + IsReady = FALSE; + + if (!IsListEmpty(&Endpoint->CancelList)) + IsReady = FALSE; + + if (!IsListEmpty(&Endpoint->AbortList)) + IsReady = FALSE; + + KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); + if (Endpoint->StateLast != Endpoint->StateNext) + IsReady = FALSE; + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + + if (InterlockedIncrement(&Endpoint->LockCounter)) + IsReady = FALSE; + InterlockedDecrement(&Endpoint->LockCounter); + + if (IsReady == TRUE) + break; + + USBPORT_Wait(FdoDevice, 1); + } + + Endpoint->DeviceHandle = NULL; + + if (FdoExtension->MiniPortInterface->Packet.MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + DPRINT("USBPORT_ClosePipe: FIXME USBPORT_FreeBandwidthUSB20\n"); + //USBPORT_FreeBandwidthUSB20(); + } + else + { + DPRINT("USBPORT_ClosePipe: FIXME USBPORT_FreeBandwidthUSB11\n"); + //USBPORT_FreeBandwidthUSB11(); + } + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + USBPORT_SetEndpointState(Endpoint, USBPORT_ENDPOINT_REMOVE); + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + USBPORT_SignalWorkerThread(FdoDevice); +} + +MPSTATUS +NTAPI +MiniportOpenEndpoint(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + KIRQL OldIrql; + ULONG TransferType; + MPSTATUS MpStatus; + + DPRINT("MiniportOpenEndpoint: Endpoint - %p\n", Endpoint); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Endpoint->Flags &= ~ENDPOINT_FLAG_CLOSED; + + MpStatus = Packet->OpenEndpoint(FdoExtension->MiniPortExt, + &Endpoint->EndpointProperties, + Endpoint + 1); + + if (!MpStatus) + { + TransferType = Endpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT || + TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + ++FdoExtension->PeriodicEndpoints; + } + + Endpoint->Flags |= ENDPOINT_FLAG_OPENED; + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + return MpStatus; +} + +NTSTATUS +NTAPI +USBPORT_OpenPipe(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle, + IN OUT PUSBD_STATUS UsbdStatus) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + ULONG EndpointSize; + PUSBPORT_ENDPOINT Endpoint; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + UCHAR Direction; + UCHAR Interval; + UCHAR Period; + ULONG TransferParams[2] = {0}; + PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer; + MPSTATUS MpStatus; + USBD_STATUS USBDStatus; + NTSTATUS Status; + KIRQL OldIrql; + USHORT MaxPacketSize; + USHORT AdditionalTransaction; + BOOLEAN IsAllocatedBandwidth; + + DPRINT("USBPORT_OpenPipe: DeviceHandle - %p, FdoDevice - %p, PipeHandle - %p\n", + DeviceHandle, + FdoDevice, + PipeHandle); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + EndpointSize = sizeof(USBPORT_ENDPOINT) + Packet->MiniPortEndpointSize; + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + DPRINT1("USBPORT_OpenPipe: FIXME USB2 EndpointSize\n"); + } + + if (PipeHandle->EndpointDescriptor.wMaxPacketSize == 0) + { + USBPORT_AddPipeHandle(DeviceHandle, PipeHandle); + + PipeHandle->Flags = (PipeHandle->Flags & ~PIPE_HANDLE_FLAG_CLOSED) | + PIPE_HANDLE_FLAG_NULL_PACKET_SIZE; + + PipeHandle->Endpoint = (PUSBPORT_ENDPOINT)-1; + + return STATUS_SUCCESS; + } + + Endpoint = ExAllocatePoolWithTag(NonPagedPool, EndpointSize, USB_PORT_TAG); + + if (!Endpoint) + { + DPRINT1("USBPORT_OpenPipe: Not allocated Endpoint!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + return Status; + } + + RtlZeroMemory(Endpoint, EndpointSize); + + Endpoint->FdoDevice = FdoDevice; + Endpoint->DeviceHandle = DeviceHandle; + Endpoint->LockCounter = -1; + + KeInitializeSpinLock(&Endpoint->EndpointSpinLock); + KeInitializeSpinLock(&Endpoint->StateChangeSpinLock); + + InitializeListHead(&Endpoint->PendingTransferList); + InitializeListHead(&Endpoint->TransferList); + InitializeListHead(&Endpoint->CancelList); + InitializeListHead(&Endpoint->AbortList); + + EndpointProperties = &Endpoint->EndpointProperties; + EndpointDescriptor = &PipeHandle->EndpointDescriptor; + + MaxPacketSize = EndpointDescriptor->wMaxPacketSize & 0x7FF; + AdditionalTransaction = (EndpointDescriptor->wMaxPacketSize >> 11) & 3; + + EndpointProperties->DeviceAddress = DeviceHandle->DeviceAddress; + EndpointProperties->DeviceSpeed = DeviceHandle->DeviceSpeed; + EndpointProperties->Period = 0; + EndpointProperties->EndpointAddress = EndpointDescriptor->bEndpointAddress; + EndpointProperties->TransactionPerMicroframe = AdditionalTransaction + 1; + EndpointProperties->MaxPacketSize = MaxPacketSize; + EndpointProperties->TotalMaxPacketSize = MaxPacketSize * + (AdditionalTransaction + 1); + + switch (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) + { + case USB_ENDPOINT_TYPE_CONTROL: + EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_CONTROL; + + if (EndpointProperties->EndpointAddress == 0) + { + EndpointProperties->MaxTransferSize = 0x1000; // OUT Ep0 + } + else + { + EndpointProperties->MaxTransferSize = 0x10000; + } + + break; + + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + DPRINT1("USBPORT_OpenPipe: USB_ENDPOINT_TYPE_ISOCHRONOUS UNIMPLEMENTED. FIXME. \n"); + EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_ISOCHRONOUS; + EndpointProperties->MaxTransferSize = 0x1000000; + break; + + case USB_ENDPOINT_TYPE_BULK: + EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_BULK; + EndpointProperties->MaxTransferSize = 0x10000; + break; + + case USB_ENDPOINT_TYPE_INTERRUPT: + EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_INTERRUPT; + EndpointProperties->MaxTransferSize = 0x400; + break; + } + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + Interval = USBPORT_NormalizeHsInterval(EndpointDescriptor->bInterval); + } + else + { + Interval = EndpointDescriptor->bInterval; + } + + EndpointProperties->Period = 32; + + if (Interval && (Interval < 32)) + { + if ((EndpointProperties->DeviceSpeed != UsbLowSpeed) || + (Interval >= 8)) + { + if (!(Interval & 0x20)) + { + Period = EndpointProperties->Period; + + do + { + Period >>= 1; + } + while (!(Period & Interval)); + + EndpointProperties->Period = Period; + } + } + else + { + EndpointProperties->Period = 8; + } + } + } + + if (EndpointProperties->TransferType == USB_ENDPOINT_TYPE_ISOCHRONOUS) + { + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + EndpointProperties->Period = + USBPORT_NormalizeHsInterval(EndpointDescriptor->bInterval); + } + else + { + EndpointProperties->Period = 1; + } + } + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + IsAllocatedBandwidth = USBPORT_AllocateBandwidthUSB2(FdoDevice, Endpoint); + } + else + { + EndpointProperties->UsbBandwidth = USBPORT_CalculateUsbBandwidth(FdoDevice, + Endpoint); + + IsAllocatedBandwidth = USBPORT_AllocateBandwidth(FdoDevice, Endpoint); + } + + if (!IsAllocatedBandwidth) + { + Status = USBPORT_USBDStatusToNtStatus(NULL, USBD_STATUS_NO_BANDWIDTH); + + if (UsbdStatus) + { + *UsbdStatus = USBD_STATUS_NO_BANDWIDTH; + } + + goto ExitWithError; + } + + Direction = USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress); + EndpointProperties->Direction = Direction; + + if (DeviceHandle->IsRootHub) + { + Endpoint->EndpointWorker = 0; // USBPORT_RootHubEndpointWorker; + + Endpoint->Flags |= ENDPOINT_FLAG_ROOTHUB_EP0; + + Endpoint->StateLast = USBPORT_ENDPOINT_ACTIVE; + Endpoint->StateNext = USBPORT_ENDPOINT_ACTIVE; + + PdoExtension = FdoExtension->RootHubPdo->DeviceExtension; + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + PdoExtension->Endpoint = Endpoint; + } + + USBDStatus = USBD_STATUS_SUCCESS; + } + else + { + Endpoint->EndpointWorker = 1; // USBPORT_DmaEndpointWorker; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt, + &Endpoint->EndpointProperties, + TransferParams); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if ((EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_BULK) || + (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)) + { + EndpointProperties->MaxTransferSize = TransferParams[1]; + } + + if (TransferParams[0]) + { + HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice, + TransferParams[0]); + } + else + { + HeaderBuffer = NULL; + } + + if (HeaderBuffer || (TransferParams[0] == 0)) + { + Endpoint->HeaderBuffer = HeaderBuffer; + + if (HeaderBuffer) + { + EndpointProperties->BufferVA = HeaderBuffer->VirtualAddress; + EndpointProperties->BufferPA = HeaderBuffer->PhysicalAddress; + EndpointProperties->BufferLength = HeaderBuffer->BufferLength; // BufferLength + LengthPadded; + } + + MpStatus = MiniportOpenEndpoint(FdoDevice, Endpoint); + + Endpoint->Flags |= ENDPOINT_FLAG_DMA_TYPE; + Endpoint->Flags |= ENDPOINT_FLAG_QUEUENE_EMPTY; + + if (MpStatus == 0) + { + ULONG State; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, + &Endpoint->EndpointOldIrql); + + Endpoint->StateLast = USBPORT_ENDPOINT_PAUSED; + Endpoint->StateNext = USBPORT_ENDPOINT_PAUSED; + + USBPORT_SetEndpointState(Endpoint, USBPORT_ENDPOINT_ACTIVE); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + + while (TRUE) + { + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, + &Endpoint->EndpointOldIrql); + + State = USBPORT_GetEndpointState(Endpoint); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + + if (State == USBPORT_ENDPOINT_ACTIVE) + { + break; + } + + USBPORT_Wait(FdoDevice, 1); // 1 msec. + } + } + } + else + { + MpStatus = MP_STATUS_NO_RESOURCES; + Endpoint->HeaderBuffer = NULL; + } + + if (MpStatus) + { + USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES; + } + else + { + USBDStatus = USBD_STATUS_SUCCESS; + } + } + + if (UsbdStatus) + { + *UsbdStatus = USBDStatus; + } + + Status = USBPORT_USBDStatusToNtStatus(NULL, USBDStatus); + + if (NT_SUCCESS(Status)) + { + USBPORT_AddPipeHandle(DeviceHandle, PipeHandle); + + ExInterlockedInsertTailList(&FdoExtension->EndpointList, + &Endpoint->EndpointLink, + &FdoExtension->EndpointListSpinLock); + + PipeHandle->Endpoint = Endpoint; + PipeHandle->Flags &= ~PIPE_HANDLE_FLAG_CLOSED; + + return Status; + } + +ExitWithError: + + if (Endpoint) + { + if (IsAllocatedBandwidth) + { + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + USBPORT_FreeBandwidthUSB2(FdoDevice, Endpoint); + } + else + { + USBPORT_FreeBandwidth(FdoDevice, Endpoint); + } + } + + ExFreePoolWithTag(Endpoint, USB_PORT_TAG); + } + + DPRINT1("USBPORT_OpenPipe: Status - %lx\n", Status); + return Status; +} + +NTSTATUS +NTAPI +USBPORT_ReopenPipe(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer; + ULONG EndpointRequirements[2] = {0}; + PUSBPORT_REGISTRATION_PACKET Packet; + KIRQL MiniportOldIrql; + NTSTATUS Status; + + DPRINT("USBPORT_ReopenPipe ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + while (TRUE) + { + if (!InterlockedIncrement(&Endpoint->LockCounter)) + break; + + InterlockedDecrement(&Endpoint->LockCounter); + USBPORT_Wait(FdoDevice, 1); + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql); + + Packet->SetEndpointState(FdoExtension->MiniPortExt, + Endpoint + 1, + USBPORT_ENDPOINT_REMOVE); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql); + + USBPORT_Wait(FdoDevice, 2); + + MiniportCloseEndpoint(FdoDevice, Endpoint); + + RtlZeroMemory(Endpoint + 1, + Packet->MiniPortEndpointSize); + + if (Endpoint->HeaderBuffer) + { + USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer); + Endpoint->HeaderBuffer = NULL; + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql); + + Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt, + &Endpoint->EndpointProperties, + EndpointRequirements); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql); + + if (EndpointRequirements[0]) + { + HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice, + EndpointRequirements[0]); + } + else + { + HeaderBuffer = NULL; + } + + if (HeaderBuffer || EndpointRequirements[0] == 0) + { + Endpoint->HeaderBuffer = HeaderBuffer; + Status = STATUS_SUCCESS; + } + else + { + Endpoint->HeaderBuffer = 0; + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (Endpoint->HeaderBuffer && HeaderBuffer) + { + Endpoint->EndpointProperties.BufferVA = HeaderBuffer->VirtualAddress; + Endpoint->EndpointProperties.BufferPA = HeaderBuffer->PhysicalAddress; + Endpoint->EndpointProperties.BufferLength = HeaderBuffer->BufferLength; + } + + if (NT_SUCCESS(Status)) + { + MiniportOpenEndpoint(FdoDevice, Endpoint); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); + + if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE) + { + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); + + Packet->SetEndpointState(FdoExtension->MiniPortExt, + Endpoint + 1, + USBPORT_ENDPOINT_ACTIVE); + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + } + + InterlockedDecrement(&Endpoint->LockCounter); + + return Status; +} + +VOID +NTAPI +USBPORT_FlushClosedEndpointList(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + PLIST_ENTRY ClosedList; + PUSBPORT_ENDPOINT Endpoint; + + DPRINT("USBPORT_FlushClosedEndpointList: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql); + ClosedList = &FdoExtension->EndpointClosedList; + + while (!IsListEmpty(ClosedList)) + { + Endpoint = CONTAINING_RECORD(ClosedList->Flink, + USBPORT_ENDPOINT, + CloseLink); + + RemoveHeadList(ClosedList); + Endpoint->CloseLink.Flink = NULL; + Endpoint->CloseLink.Blink = NULL; + + KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql); + + USBPORT_DeleteEndpoint(FdoDevice, Endpoint); + + KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql); + } + + KeReleaseSpinLock(&FdoExtension->EndpointClosedSpinLock, OldIrql); +} + +VOID +NTAPI +USBPORT_InvalidateEndpointHandler(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint, + IN ULONG Type) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PLIST_ENTRY Entry; + PLIST_ENTRY WorkerLink; + PUSBPORT_ENDPOINT endpoint; + KIRQL OldIrql; + BOOLEAN IsAddEntry = FALSE; + + DPRINT_CORE("USBPORT_InvalidateEndpointHandler: Endpoint - %p, Type - %x\n", + Endpoint, + Type); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (Endpoint) + { + WorkerLink = &Endpoint->WorkerLink; + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + DPRINT_CORE("USBPORT_InvalidateEndpointHandler: KeAcquireSpinLock \n"); + + if ((!WorkerLink->Flink || !WorkerLink->Blink) && + !(Endpoint->Flags & ENDPOINT_FLAG_IDLE) && + USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_CLOSED) + { + DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n"); + InsertTailList(&FdoExtension->WorkerList, WorkerLink); + IsAddEntry = TRUE; + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) + Type = INVALIDATE_ENDPOINT_WORKER_THREAD; + } + else + { + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + Entry = &FdoExtension->EndpointList; + + while (Entry && Entry != &FdoExtension->EndpointList) + { + endpoint = CONTAINING_RECORD(Entry, + USBPORT_ENDPOINT, + EndpointLink); + + if (!endpoint->WorkerLink.Flink || !endpoint->WorkerLink.Blink) + { + if (!(endpoint->Flags & ENDPOINT_FLAG_IDLE) && + !(endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) && + USBPORT_GetEndpointState(endpoint) != USBPORT_ENDPOINT_CLOSED) + { + DPRINT_CORE("USBPORT_InvalidateEndpointHandler: InsertTailList \n"); + InsertTailList(&FdoExtension->WorkerList, &endpoint->WorkerLink); + IsAddEntry = TRUE; + } + } + + Entry = endpoint->EndpointLink.Flink; + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + } + + if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND) + { + Type = INVALIDATE_ENDPOINT_WORKER_THREAD; + } + else if (IsAddEntry == FALSE && Type == INVALIDATE_ENDPOINT_INT_NEXT_SOF) + { + Type = INVALIDATE_ENDPOINT_ONLY; + } + + switch (Type) + { + case INVALIDATE_ENDPOINT_WORKER_THREAD: + USBPORT_SignalWorkerThread(FdoDevice); + break; + + case INVALIDATE_ENDPOINT_WORKER_DPC: + KeInsertQueueDpc(&FdoExtension->WorkerRequestDpc, NULL, NULL); + break; + + case INVALIDATE_ENDPOINT_INT_NEXT_SOF: + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Packet->InterruptNextSOF(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + break; + } +} + +ULONG +NTAPI +USBPORT_DmaEndpointPaused(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PLIST_ENTRY Entry; + PUSBPORT_TRANSFER Transfer; + PURB Urb; + ULONG Frame; + ULONG CurrentFrame; + ULONG CompletedLen = 0; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_DmaEndpointPaused \n"); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + Entry = Endpoint->TransferList.Flink; + + if (Entry == &Endpoint->TransferList) + return USBPORT_ENDPOINT_ACTIVE; + + while (Entry && Entry != &Endpoint->TransferList) + { + Transfer = CONTAINING_RECORD(Entry, + USBPORT_TRANSFER, + TransferLink); + + if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED)) + { + if (Transfer->Flags & TRANSFER_FLAG_ISO && + Transfer->Flags & TRANSFER_FLAG_SUBMITED && + !(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) + { + Urb = Transfer->Urb; + + Frame = Urb->UrbIsochronousTransfer.StartFrame + + Urb->UrbIsochronousTransfer.NumberOfPackets; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + CurrentFrame = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (Frame + 1 > CurrentFrame) + { + return USBPORT_GetEndpointState(Endpoint); + } + } + + if ((Transfer->Flags & TRANSFER_FLAG_SUBMITED) && + !(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->AbortTransfer(FdoExtension->MiniPortExt, + Endpoint + 1, + Transfer->MiniportTransfer, + &CompletedLen); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (Transfer->Flags & TRANSFER_FLAG_ISO) + { + DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_FlushIsoTransfer\n"); + ASSERT(FALSE); //USBPORT_FlushIsoTransfer(); + } + else + { + Transfer->CompletedTransferLen = CompletedLen; + } + } + + RemoveEntryList(&Transfer->TransferLink); + Entry = Transfer->TransferLink.Flink; + + if (Transfer->Flags & TRANSFER_FLAG_SPLITED) + { + DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_CancelSplitTransfer\n"); + ASSERT(FALSE); //USBPORT_CancelSplitTransfer(); + } + else + { + InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink); + } + } + else + { + Entry = Transfer->TransferLink.Flink; + } + } + + return USBPORT_ENDPOINT_ACTIVE; +} + +ULONG +NTAPI +USBPORT_DmaEndpointActive(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PLIST_ENTRY Entry; + PUSBPORT_TRANSFER Transfer; + LARGE_INTEGER TimeOut; + MPSTATUS MpStatus; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_DmaEndpointActive \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + Entry = Endpoint->TransferList.Flink; + + while (Entry && Entry != &Endpoint->TransferList) + { + Transfer = CONTAINING_RECORD(Entry, + USBPORT_TRANSFER, + TransferLink); + + if (!(Transfer->Flags & TRANSFER_FLAG_SUBMITED) && + !(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (Transfer->Flags & TRANSFER_FLAG_ISO) + { + DPRINT1("USBPORT_DmaEndpointActive: FIXME call SubmitIsoTransfer\n"); + + MpStatus = Packet->SubmitIsoTransfer(FdoExtension->MiniPortExt, + Endpoint + 1, + &Transfer->TransferParameters, + Transfer->MiniportTransfer, + NULL);//&Transfer->IsoTransferParameters); + } + else + { + MpStatus = Packet->SubmitTransfer(FdoExtension->MiniPortExt, + Endpoint + 1, + &Transfer->TransferParameters, + Transfer->MiniportTransfer, + &Transfer->SgList); + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (MpStatus) + { + if ((MpStatus != MP_STATUS_FAILURE) && Transfer->Flags & TRANSFER_FLAG_ISO) + { + DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_ErrorCompleteIsoTransfer\n"); + ASSERT(FALSE); //USBPORT_ErrorCompleteIsoTransfer(); + } + + return USBPORT_ENDPOINT_ACTIVE; + } + + Transfer->Flags |= TRANSFER_FLAG_SUBMITED; + KeQuerySystemTime(&Transfer->Time); + + TimeOut.QuadPart = 10000 * Transfer->TimeOut; + Transfer->Time.QuadPart += TimeOut.QuadPart; + } + + if (Transfer->Flags & (TRANSFER_FLAG_CANCELED | TRANSFER_FLAG_ABORTED)) + { + return USBPORT_ENDPOINT_PAUSED; + } + + Entry = Transfer->TransferLink.Flink; + } + + return USBPORT_ENDPOINT_ACTIVE; +} + +VOID +NTAPI +USBPORT_DmaEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint) +{ + PDEVICE_OBJECT FdoDevice; + ULONG PrevState; + ULONG EndpointState; + BOOLEAN IsPaused = FALSE; + + DPRINT_CORE("USBPORT_DmaEndpointWorker ... \n"); + + FdoDevice = Endpoint->FdoDevice; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + PrevState = USBPORT_GetEndpointState(Endpoint); + + if (PrevState == USBPORT_ENDPOINT_PAUSED) + { + EndpointState = USBPORT_DmaEndpointPaused(FdoDevice, Endpoint); + } + else if (PrevState == USBPORT_ENDPOINT_ACTIVE) + { + EndpointState = USBPORT_DmaEndpointActive(FdoDevice, Endpoint); + } + else + { +#ifndef NDEBUG_USBPORT_CORE + DPRINT1("USBPORT_DmaEndpointWorker: DbgBreakPoint. EndpointState - %x\n", + EndpointState); + DbgBreakPoint(); +#endif + EndpointState = USBPORT_ENDPOINT_UNKNOWN; + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + USBPORT_FlushCancelList(Endpoint); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (EndpointState == PrevState) + { + if (EndpointState == USBPORT_ENDPOINT_PAUSED) + { + IsPaused = TRUE; + } + } + else + { + USBPORT_SetEndpointState(Endpoint, EndpointState); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + if (IsPaused) + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + } + + DPRINT_CORE("USBPORT_DmaEndpointWorker exit \n"); +} + +BOOLEAN +NTAPI +USBPORT_EndpointWorker(IN PUSBPORT_ENDPOINT Endpoint, + IN BOOLEAN LockNotChecked) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + ULONG EndpointState; + + DPRINT_CORE("USBPORT_EndpointWorker: Endpoint - %p, LockNotChecked - %x\n", + Endpoint, + LockNotChecked); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (LockNotChecked == FALSE) + { + if (InterlockedIncrement(&Endpoint->LockCounter)) + { + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: LockCounter > 0\n"); + return TRUE; + } + } + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + + if (USBPORT_GetEndpointState(Endpoint) == USBPORT_ENDPOINT_CLOSED) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_CLOSED. return FALSE\n"); + return FALSE; + } + + if ((Endpoint->Flags & (ENDPOINT_FLAG_ROOTHUB_EP0 | ENDPOINT_FLAG_NUKE)) == 0) + { + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); + Packet->PollEndpoint(FdoExtension->MiniPortExt, Endpoint + 1); + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); + } + + EndpointState = USBPORT_GetEndpointState(Endpoint); + + if (EndpointState == USBPORT_ENDPOINT_REMOVE) + { + KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); + Endpoint->StateLast = USBPORT_ENDPOINT_CLOSED; + Endpoint->StateNext = USBPORT_ENDPOINT_CLOSED; + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + + ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList, + &Endpoint->CloseLink, + &FdoExtension->EndpointClosedSpinLock); + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_REMOVE. return FALSE\n"); + return FALSE; + } + + if (!IsListEmpty(&Endpoint->PendingTransferList) || + !IsListEmpty(&Endpoint->TransferList) || + !IsListEmpty(&Endpoint->CancelList)) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + + EndpointState = USBPORT_GetEndpointState(Endpoint); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); + if (EndpointState == Endpoint->StateNext) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + + if (Endpoint->EndpointWorker) + { + USBPORT_DmaEndpointWorker(Endpoint); + } + else + { + USBPORT_RootHubEndpointWorker(Endpoint); + } + + USBPORT_FlushAbortList(Endpoint); + + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n"); + return FALSE; + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + InterlockedDecrement(&Endpoint->LockCounter); + + DPRINT_CORE("USBPORT_EndpointWorker: return TRUE\n"); + return TRUE; + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + + USBPORT_FlushAbortList(Endpoint); + + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: return FALSE\n"); + return FALSE; +} diff --git a/reactos/drivers/usb/usbport/guid.c b/reactos/drivers/usb/usbport/guid.c new file mode 100644 index 00000000000..50a60369ff3 --- /dev/null +++ b/reactos/drivers/usb/usbport/guid.c @@ -0,0 +1,9 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include +#include +#include +#include +#include + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/reactos/drivers/usb/usbport/iface.c b/reactos/drivers/usb/usbport/iface.c new file mode 100644 index 00000000000..aeacdef0280 --- /dev/null +++ b/reactos/drivers/usb/usbport/iface.c @@ -0,0 +1,901 @@ +#include "usbport.h" + +#define NDEBUG +#include + +VOID +USB_BUSIFFN +USBI_InterfaceReference(IN PVOID BusContext) +{ + DPRINT("USBI_InterfaceReference \n"); +} + +VOID +USB_BUSIFFN +USBI_InterfaceDereference(IN PVOID BusContext) +{ + DPRINT("USBI_InterfaceDereference \n"); +} + +/* USB port driver Interface functions */ + +NTSTATUS +USB_BUSIFFN +USBHI_CreateUsbDevice(IN PVOID BusContext, + IN OUT PUSB_DEVICE_HANDLE *UsbdDeviceHandle, + IN PUSB_DEVICE_HANDLE UsbdHubDeviceHandle, + IN USHORT PortStatus, + IN USHORT PortNumber) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSB_DEVICE_HANDLE deviceHandle = NULL; + NTSTATUS Status; + + DPRINT("USBHI_CreateUsbDevice: ... \n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + + Status = USBPORT_CreateDevice(&deviceHandle, + PdoExtension->FdoDevice, + (PUSBPORT_DEVICE_HANDLE)UsbdHubDeviceHandle, + PortStatus, + PortNumber); + + *UsbdDeviceHandle = deviceHandle; + + return Status; +} + +NTSTATUS +USB_BUSIFFN +USBHI_InitializeUsbDevice(IN PVOID BusContext, + OUT PUSB_DEVICE_HANDLE UsbdDeviceHandle) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + + DPRINT("USBHI_InitializeUsbDevice \n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + + return USBPORT_InitializeDevice((PUSBPORT_DEVICE_HANDLE)UsbdDeviceHandle, + PdoExtension->FdoDevice); +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetUsbDescriptors(IN PVOID BusContext, + IN PUSB_DEVICE_HANDLE UsbdDeviceHandle, + IN PUCHAR DeviceDescBuffer, + IN PULONG DeviceDescBufferLen, + IN PUCHAR ConfigDescBuffer, + IN PULONG ConfigDescBufferLen) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + + NTSTATUS Status; + + DPRINT("USBHI_GetUsbDescriptors ...\n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + DeviceHandle = (PUSBPORT_DEVICE_HANDLE)UsbdDeviceHandle; + + if (DeviceDescBuffer && *DeviceDescBufferLen) + { + if (*DeviceDescBufferLen > sizeof(USB_DEVICE_DESCRIPTOR)) + *DeviceDescBufferLen = sizeof(USB_DEVICE_DESCRIPTOR); + + RtlCopyMemory(DeviceDescBuffer, + &DeviceHandle->DeviceDescriptor, + *DeviceDescBufferLen); + } + + Status = USBPORT_GetUsbDescriptor(DeviceHandle, + PdoExtension->FdoDevice, + USB_CONFIGURATION_DESCRIPTOR_TYPE, + ConfigDescBuffer, + ConfigDescBufferLen); + + USBPORT_DumpingDeviceDescriptor((PUSB_DEVICE_DESCRIPTOR)DeviceDescBuffer); + + return Status; +} + +NTSTATUS +USB_BUSIFFN +USBHI_RemoveUsbDevice(IN PVOID BusContext, + IN OUT PUSB_DEVICE_HANDLE UsbdDeviceHandle, + IN ULONG Flags) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + + DPRINT("USBHI_RemoveUsbDevice: UsbdDeviceHandle - %p, Flags - %x\n", + UsbdDeviceHandle, + Flags); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + + return USBPORT_RemoveDevice(PdoExtension->FdoDevice, + (PUSBPORT_DEVICE_HANDLE)UsbdDeviceHandle, + Flags); +} + +NTSTATUS +USB_BUSIFFN +USBHI_RestoreUsbDevice(IN PVOID BusContext, + OUT PUSB_DEVICE_HANDLE OldUsbdDeviceHandle, + OUT PUSB_DEVICE_HANDLE NewUsbdDeviceHandle) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + + DPRINT("USBHI_RestoreUsbDevice: OldUsbdDeviceHandle - %p, NewUsbdDeviceHandle - %x\n", + OldUsbdDeviceHandle, + NewUsbdDeviceHandle); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + + return USBPORT_RestoreDevice(PdoExtension->FdoDevice, + (PUSBPORT_DEVICE_HANDLE)OldUsbdDeviceHandle, + (PUSBPORT_DEVICE_HANDLE)NewUsbdDeviceHandle); +} + +NTSTATUS +USB_BUSIFFN +USBHI_QueryDeviceInformation(IN PVOID BusContext, + IN PUSB_DEVICE_HANDLE UsbdDeviceHandle, + OUT PVOID DeviceInfoBuffer, + IN ULONG DeviceInfoBufferLen, + OUT PULONG LenDataReturned) +{ + PUSB_DEVICE_INFORMATION_0 DeviceInfo; + PUSBPORT_CONFIGURATION_HANDLE ConfigHandle; + PLIST_ENTRY InterfaceEntry; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + ULONG NumberOfOpenPipes = 0; + PUSB_PIPE_INFORMATION_0 PipeInfo; + PUSBPORT_PIPE_HANDLE PipeHandle; + PUSBPORT_INTERFACE_HANDLE InterfaceHandle; + ULONG ActualLength; + ULONG ix; + + DPRINT("USBHI_QueryDeviceInformation: ... \n"); + + *LenDataReturned = 0; + + if (DeviceInfoBufferLen < sizeof(USB_LEVEL_INFORMATION)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + DeviceInfo = DeviceInfoBuffer; + + if (DeviceInfo->InformationLevel > 0) + { + return STATUS_NOT_SUPPORTED; + } + + DeviceHandle = UsbdDeviceHandle; + ConfigHandle = DeviceHandle->ConfigHandle; + + if (ConfigHandle) + { + InterfaceEntry = ConfigHandle->InterfaceHandleList.Flink; + + while (InterfaceEntry && + InterfaceEntry != &ConfigHandle->InterfaceHandleList) + { + InterfaceHandle = CONTAINING_RECORD(InterfaceEntry, + USBPORT_INTERFACE_HANDLE, + InterfaceLink); + + NumberOfOpenPipes += InterfaceHandle->InterfaceDescriptor.bNumEndpoints; + + InterfaceEntry = InterfaceEntry->Flink; + } + } + + ActualLength = sizeof(USB_DEVICE_INFORMATION_0) + + (NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFORMATION_0); + + if (DeviceInfoBufferLen < ActualLength) + { + DeviceInfo->ActualLength = ActualLength; + *LenDataReturned = sizeof(USB_LEVEL_INFORMATION); + + return STATUS_BUFFER_TOO_SMALL; + } + + RtlZeroMemory(DeviceInfo, ActualLength); + + DeviceInfo->InformationLevel = 0; + DeviceInfo->ActualLength = ActualLength; + DeviceInfo->DeviceAddress = DeviceHandle->DeviceAddress; + DeviceInfo->NumberOfOpenPipes = NumberOfOpenPipes; + DeviceInfo->DeviceSpeed = DeviceHandle->DeviceSpeed; + + RtlCopyMemory(&DeviceInfo->DeviceDescriptor, + &DeviceHandle->DeviceDescriptor, + sizeof(USB_DEVICE_DESCRIPTOR)); + + USBPORT_DumpingDeviceDescriptor(&DeviceInfo->DeviceDescriptor); + + if (DeviceHandle->DeviceSpeed == UsbFullSpeed || + DeviceHandle->DeviceSpeed == UsbLowSpeed) + { + DeviceInfo->DeviceType = Usb11Device; + } + else if (DeviceHandle->DeviceSpeed == UsbHighSpeed) + { + DeviceInfo->DeviceType = Usb20Device; + } + + DeviceInfo->CurrentConfigurationValue = 0; + + if (!ConfigHandle) + { + *LenDataReturned = ActualLength; + return STATUS_SUCCESS; + } + + DeviceInfo->CurrentConfigurationValue = + ConfigHandle->ConfigurationDescriptor->bConfigurationValue; + + InterfaceEntry = ConfigHandle->InterfaceHandleList.Flink; + + while (InterfaceEntry && + InterfaceEntry != &ConfigHandle->InterfaceHandleList) + { + InterfaceHandle = CONTAINING_RECORD(InterfaceEntry, + USBPORT_INTERFACE_HANDLE, + InterfaceLink); + + if (InterfaceHandle->InterfaceDescriptor.bNumEndpoints > 0) + { + PipeInfo = &DeviceInfo->PipeList[0]; + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + for (ix = 0; + ix < InterfaceHandle->InterfaceDescriptor.bNumEndpoints; + ix++) + { + if (PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE) + { + PipeInfo->ScheduleOffset = 1; + } + else + { + PipeInfo->ScheduleOffset = + PipeHandle->Endpoint->EndpointProperties.ScheduleOffset; + } + + RtlCopyMemory(&PipeInfo->EndpointDescriptor, + &PipeHandle->EndpointDescriptor, + sizeof(USB_ENDPOINT_DESCRIPTOR)); + + PipeInfo += 1; + PipeHandle += 1; + } + } + + InterfaceEntry = InterfaceEntry->Flink; + } + + *LenDataReturned = ActualLength; + + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetControllerInformation(IN PVOID BusContext, + OUT PVOID ControllerInfoBuffer, + IN ULONG ControllerInfoBufferLen, + OUT PULONG LenDataReturned) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSB_CONTROLLER_INFORMATION_0 InfoBuffer; + NTSTATUS Status; + + DPRINT("USBHI_GetControllerInformation: ControllerInfoBufferLen - %x\n", + ControllerInfoBufferLen); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + InfoBuffer = ControllerInfoBuffer; + + *LenDataReturned = 0; + + if (ControllerInfoBufferLen < sizeof(USB_LEVEL_INFORMATION)) + { + Status = STATUS_BUFFER_TOO_SMALL; + return Status; + } + + *LenDataReturned = sizeof(USB_LEVEL_INFORMATION); + + if (InfoBuffer->InformationLevel > 0) + { + Status = STATUS_NOT_SUPPORTED; + return Status; + } + + InfoBuffer->ActualLength = sizeof(USB_CONTROLLER_INFORMATION_0); + + if (ControllerInfoBufferLen >= sizeof(USB_CONTROLLER_INFORMATION_0)) + { + InfoBuffer->SelectiveSuspendEnabled = + (FdoExtension->Flags & USBPORT_FLAG_SELECTIVE_SUSPEND) == + USBPORT_FLAG_SELECTIVE_SUSPEND; + } + + *LenDataReturned = sizeof(USB_CONTROLLER_INFORMATION_0); + + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_ControllerSelectiveSuspend(IN PVOID BusContext, + IN BOOLEAN Enable) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + ULONG Flags; + ULONG HcDisable; + NTSTATUS Status; + + DPRINT("USBHI_ControllerSelectiveSuspend: Enable - %x\n", Enable); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + Flags = FdoExtension->Flags; + + if (Flags & USBPORT_FLAG_BIOS_DISABLE_SS) + { + return STATUS_SUCCESS; + } + + if (Enable) + { + FdoExtension->Flags |= USBPORT_FLAG_SELECTIVE_SUSPEND; + HcDisable = 0; + } + else + { + FdoExtension->Flags &= ~USBPORT_FLAG_SELECTIVE_SUSPEND; + HcDisable = 1; + } + + Status = USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + REG_DWORD, + L"HcDisableSelectiveSuspend", + &HcDisable, + sizeof(HcDisable)); + + if (NT_SUCCESS(Status)) + { + if (Enable) + FdoExtension->Flags |= USBPORT_FLAG_SELECTIVE_SUSPEND; + else + FdoExtension->Flags &= ~USBPORT_FLAG_SELECTIVE_SUSPEND; + } + + return Status; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetExtendedHubInformation(IN PVOID BusContext, + IN PDEVICE_OBJECT HubPhysicalDeviceObject, + IN OUT PVOID HubInformationBuffer, + IN ULONG HubInfoLen, + IN OUT PULONG LenDataReturned) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + ULONG NumPorts; + ULONG ix; + PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer; + USBHUB_PORT_STATUS PortStatus; + ULONG PortAttrX; + + DPRINT("USBHI_GetExtendedHubInformation: ... \n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + HubInfoBuffer = HubInformationBuffer; + PortStatus.AsULONG = 0; + + if (HubPhysicalDeviceObject != PdoDevice) + { + *LenDataReturned = 0; + return STATUS_NOT_SUPPORTED; + } + + if (HubInfoLen < sizeof(USB_EXTHUB_INFORMATION_0)) + { + *LenDataReturned = 0; + return STATUS_BUFFER_TOO_SMALL; + } + + NumPorts = PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts; + HubInfoBuffer->NumberOfPorts = NumPorts; + + if (NumPorts == 0) + { + *LenDataReturned = sizeof(USB_EXTHUB_INFORMATION_0); + return STATUS_SUCCESS; + } + + for (ix = 0; ix < HubInfoBuffer->NumberOfPorts; ++ix) + { + HubInfoBuffer->Port[ix].PhysicalPortNumber = ix + 1; + HubInfoBuffer->Port[ix].PortLabelNumber = ix; + HubInfoBuffer->Port[ix].VidOverride = 0; + HubInfoBuffer->Port[ix].PidOverride = 0; + HubInfoBuffer->Port[ix].PortAttributes = 0; + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + HubInfoBuffer->Port[ix].PortAttributes = USB_PORTATTR_SHARED_USB2; + + Packet->RH_GetPortStatus(FdoExtension->MiniPortExt, + ix, + &PortStatus); + + if (PortStatus.UsbPortStatus.Usb20PortStatus.AsUshort16 & 0x8000) + { + HubInfoBuffer->Port[ix].PortAttributes |= USB_PORTATTR_OWNED_BY_CC; + } + } + else + { + if (!(FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC)) + { + continue; + } + + if (USBPORT_FindUSB2Controller(FdoDevice)) + { + HubInfoBuffer->Port[ix].PortAttributes |= USB_PORTATTR_NO_OVERCURRENT_UI; + } + } + } + + for (ix = 0; ix < HubInfoBuffer->NumberOfPorts; ++ix) + { + PortAttrX = 0; + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + FALSE, + L"PortAttrX", + sizeof(L"PortAttrX"), + &PortAttrX, + sizeof(PortAttrX)); + + HubInfoBuffer->Port[ix].PortAttributes |= PortAttrX; + } + + *LenDataReturned = sizeof(USB_EXTHUB_INFORMATION_0); + + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBHI_GetRootHubSymbolicName(IN PVOID BusContext, + IN OUT PVOID HubInfoBuffer, + IN ULONG HubInfoBufferLen, + OUT PULONG HubNameActualLen) +{ + PDEVICE_OBJECT PdoDevice; + UNICODE_STRING HubName; + PUNICODE_STRING InfoBuffer; + NTSTATUS Status; + + DPRINT("USBHI_GetRootHubSymbolicName: ... \n"); + + PdoDevice = BusContext; + + Status = USBPORT_GetSymbolicName(PdoDevice, &HubName); + + if (HubInfoBufferLen < HubName.Length) + { + InfoBuffer = HubInfoBuffer; + InfoBuffer->Length = 0; + } + else + { + RtlCopyMemory(HubInfoBuffer, HubName.Buffer, HubName.Length); + } + + *HubNameActualLen = HubName.Length; + + if (NT_SUCCESS(Status)) + RtlFreeUnicodeString(&HubName); + + return Status; +} + +PVOID +USB_BUSIFFN +USBHI_GetDeviceBusContext(IN PVOID BusContext, + IN PVOID DeviceHandle) +{ + DPRINT1("USBHI_GetDeviceBusContext: UNIMPLEMENTED. FIXME. \n"); + return NULL; +} + +NTSTATUS +USB_BUSIFFN +USBHI_Initialize20Hub(IN PVOID BusContext, + IN PUSB_DEVICE_HANDLE UsbdHubDeviceHandle, + IN ULONG TtCount) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + + DPRINT("USBHI_Initialize20Hub: UsbdHubDeviceHandle - %p, TtCount - %x\n", + UsbdHubDeviceHandle, + TtCount); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + + return USBPORT_Initialize20Hub(PdoExtension->FdoDevice, + (PUSBPORT_DEVICE_HANDLE)UsbdHubDeviceHandle, + TtCount); +} + +NTSTATUS +USB_BUSIFFN +USBHI_RootHubInitNotification(IN PVOID BusContext, + IN PVOID CallbackContext, + IN PRH_INIT_CALLBACK CallbackFunction) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + + DPRINT("USBHI_RootHubInitNotification \n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->RootHubCallbackSpinLock, &OldIrql); + PdoExtension->RootHubInitContext = CallbackContext; + PdoExtension->RootHubInitCallback = CallbackFunction; + KeReleaseSpinLock(&FdoExtension->RootHubCallbackSpinLock, OldIrql); + + return STATUS_SUCCESS; +} + +VOID +USB_BUSIFFN +USBHI_FlushTransfers(IN PVOID BusContext, + OUT PUSB_DEVICE_HANDLE UsbdDeviceHandle) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + + DPRINT("USBHI_FlushTransfers: ... \n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + + USBPORT_BadRequestFlush(PdoExtension->FdoDevice); +} + +VOID +USB_BUSIFFN +USBHI_SetDeviceHandleData(IN PVOID BusContext, + IN PVOID DeviceHandle, + IN PDEVICE_OBJECT UsbDevicePdo) +{ + DPRINT1("USBHI_SetDeviceHandleData: UNIMPLEMENTED. FIXME. \n"); +} + +/* USB bus driver Interface functions */ + +VOID +USB_BUSIFFN +USBDI_GetUSBDIVersion(IN PVOID BusContext, + OUT PUSBD_VERSION_INFORMATION VersionInfo, + OUT PULONG HcdCapabilities) +{ + DPRINT1("USBDI_GetUSBDIVersion: UNIMPLEMENTED. FIXME. \n"); +} + +NTSTATUS +USB_BUSIFFN +USBDI_QueryBusTime(IN PVOID BusContext, + OUT PULONG CurrentFrame) +{ + DPRINT1("USBDI_QueryBusTime: UNIMPLEMENTED. FIXME. \n"); + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBDI_SubmitIsoOutUrb(IN PVOID BusContext, + IN PURB Urb) +{ + DPRINT1("USBDI_SubmitIsoOutUrb: UNIMPLEMENTED. FIXME. \n"); + return STATUS_SUCCESS; +} + +NTSTATUS +USB_BUSIFFN +USBDI_QueryBusInformation(IN PVOID BusContext, + IN ULONG Level, + OUT PVOID BusInfoBuffer, + OUT PULONG BusInfoBufferLen, + OUT PULONG BusInfoActualLen) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + SIZE_T Length; + PUSB_BUS_INFORMATION_LEVEL_1 Buffer1; + + DPRINT("USBDI_QueryBusInformation: Level - %p\n", Level); + + if ((Level != 0) || (Level != 1)) + { + DPRINT1("USBDI_QueryBusInformation: Level should be 0 or 1\n"); + return STATUS_NOT_SUPPORTED; + } + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + if (Level == 0) + { + if (BusInfoActualLen) + *BusInfoActualLen = sizeof(USB_BUS_INFORMATION_LEVEL_0); + + if (*BusInfoBufferLen < sizeof(USB_BUS_INFORMATION_LEVEL_0)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *BusInfoBufferLen = sizeof(USB_BUS_INFORMATION_LEVEL_0); + + //Buffer0 = BusInfoBuffer; + DPRINT1("USBDI_QueryBusInformation: LEVEL_0 UNIMPLEMENTED. FIXME\n"); + //Buffer0->TotalBandwidth = USBPORT_GetTotalBandwidth(); + //Buffer0->ConsumedBandwidth = USBPORT_GetAllocatedBandwidth(); + + return STATUS_SUCCESS; + } + + if (Level == 1) + { + Length = sizeof(USB_BUS_INFORMATION_LEVEL_1) + + FdoExtension->CommonExtension.SymbolicLinkName.Length; + + if (BusInfoActualLen) + *BusInfoActualLen = Length; + + if (*BusInfoBufferLen < Length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + *BusInfoBufferLen = Length; + + Buffer1 = BusInfoBuffer; + DPRINT1("USBDI_QueryBusInformation: LEVEL_1 UNIMPLEMENTED. FIXME\n"); + //Buffer1->TotalBandwidth = USBPORT_GetTotalBandwidth(); + //Buffer1->ConsumedBandwidth = USBPORT_GetAllocatedBandwidth(); + Buffer1->ControllerNameLength = FdoExtension->CommonExtension.SymbolicLinkName.Length; + + RtlCopyMemory(&Buffer1->ControllerNameUnicodeString, + FdoExtension->CommonExtension.SymbolicLinkName.Buffer, + FdoExtension->CommonExtension.SymbolicLinkName.Length); + + return STATUS_SUCCESS; + } + + return STATUS_SUCCESS; +} + +BOOLEAN +USB_BUSIFFN +USBDI_IsDeviceHighSpeed(IN PVOID BusContext) +{ + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + + DPRINT("USBDI_IsDeviceHighSpeed: ... \n"); + + PdoDevice = BusContext; + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + return (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) != 0; +} + +NTSTATUS +USB_BUSIFFN +USBDI_EnumLogEntry(IN PVOID BusContext, + IN ULONG DriverTag, + IN ULONG EnumTag, + IN ULONG P1, + IN ULONG P2) +{ + DPRINT1("USBDI_EnumLogEntry: UNIMPLEMENTED. FIXME. \n"); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_PdoQueryInterface(IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); + PUSB_BUS_INTERFACE_HUB_V5 InterfaceHub; + PUSB_BUS_INTERFACE_USBDI_V2 InterfaceDI; + UNICODE_STRING GuidBuffer; + NTSTATUS Status; + + DPRINT("USBPORT_PdoQueryInterface: ... \n"); + + if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType, + &USB_BUS_INTERFACE_HUB_GUID)) + { + /* Get request parameters */ + InterfaceHub = (PUSB_BUS_INTERFACE_HUB_V5)IoStack->Parameters.QueryInterface.Interface; + InterfaceHub->Version = IoStack->Parameters.QueryInterface.Version; + + /* Check version */ + if (IoStack->Parameters.QueryInterface.Version >= 6) + { + DPRINT1("USB_BUS_INTERFACE_HUB_GUID version %x not supported!\n", + IoStack->Parameters.QueryInterface.Version); + + return STATUS_NOT_SUPPORTED; // Version not supported + } + + /* Interface version 0 */ + InterfaceHub->Size = IoStack->Parameters.QueryInterface.Size; + InterfaceHub->BusContext = PdoDevice; + + InterfaceHub->InterfaceReference = USBI_InterfaceReference; + InterfaceHub->InterfaceDereference = USBI_InterfaceDereference; + + /* Interface version 1 */ + if (IoStack->Parameters.QueryInterface.Version >= 1) + { + InterfaceHub->CreateUsbDevice = USBHI_CreateUsbDevice; + InterfaceHub->InitializeUsbDevice = USBHI_InitializeUsbDevice; + InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors; + InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice; + InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice; + InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation; + } + + /* Interface version 2 */ + if (IoStack->Parameters.QueryInterface.Version >= 2) + { + InterfaceHub->GetControllerInformation = USBHI_GetControllerInformation; + InterfaceHub->ControllerSelectiveSuspend = USBHI_ControllerSelectiveSuspend; + InterfaceHub->GetExtendedHubInformation = USBHI_GetExtendedHubInformation; + InterfaceHub->GetRootHubSymbolicName = USBHI_GetRootHubSymbolicName; + InterfaceHub->GetDeviceBusContext = USBHI_GetDeviceBusContext; + InterfaceHub->Initialize20Hub = USBHI_Initialize20Hub; + } + + /* Interface version 3 */ + if (IoStack->Parameters.QueryInterface.Version >= 3) + InterfaceHub->RootHubInitNotification = USBHI_RootHubInitNotification; + + /* Interface version 4 */ + if (IoStack->Parameters.QueryInterface.Version >= 4) + InterfaceHub->FlushTransfers = USBHI_FlushTransfers; + + /* Interface version 5 */ + if (IoStack->Parameters.QueryInterface.Version >= 5) + InterfaceHub->SetDeviceHandleData = USBHI_SetDeviceHandleData; + + /* Request completed */ + return STATUS_SUCCESS; + } + else if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType, + &USB_BUS_INTERFACE_USBDI_GUID)) + { + /* Get request parameters */ + InterfaceDI = (PUSB_BUS_INTERFACE_USBDI_V2)IoStack->Parameters.QueryInterface.Interface; + InterfaceDI->Version = IoStack->Parameters.QueryInterface.Version; + + /* Check version */ + if (IoStack->Parameters.QueryInterface.Version >= 3) + { + DPRINT1("USB_BUS_INTERFACE_USBDI_GUID version %x not supported!\n", + IoStack->Parameters.QueryInterface.Version); + + return STATUS_NOT_SUPPORTED; // Version not supported + } + + /* Interface version 0 */ + InterfaceDI->Size = IoStack->Parameters.QueryInterface.Size; + InterfaceDI->BusContext = PdoDevice; + InterfaceDI->InterfaceReference = USBI_InterfaceReference; + InterfaceDI->InterfaceDereference = USBI_InterfaceDereference; + InterfaceDI->GetUSBDIVersion = USBDI_GetUSBDIVersion; + InterfaceDI->QueryBusTime = USBDI_QueryBusTime; + InterfaceDI->SubmitIsoOutUrb = USBDI_SubmitIsoOutUrb; + InterfaceDI->QueryBusInformation = USBDI_QueryBusInformation; + + /* Interface version 1 */ + if (IoStack->Parameters.QueryInterface.Version >= 1) + InterfaceDI->IsDeviceHighSpeed = USBDI_IsDeviceHighSpeed; + + /* Interface version 2 */ + if (IoStack->Parameters.QueryInterface.Version >= 2) + InterfaceDI->EnumLogEntry = USBDI_EnumLogEntry; + + return STATUS_SUCCESS; + } + else + { + /* Convert GUID to string */ + Status = RtlStringFromGUID(IoStack->Parameters.QueryInterface.InterfaceType, + &GuidBuffer); + + if (NT_SUCCESS(Status)) + { + /* Print interface */ + DPRINT1("HandleQueryInterface UNKNOWN INTERFACE GUID: %wZ Version %x\n", + &GuidBuffer, + IoStack->Parameters.QueryInterface.Version); + + RtlFreeUnicodeString(&GuidBuffer); // Free GUID buffer + } + } + + return STATUS_NOT_SUPPORTED; +} diff --git a/reactos/drivers/usb/usbport/ioctl.c b/reactos/drivers/usb/usbport/ioctl.c new file mode 100644 index 00000000000..96142c71265 --- /dev/null +++ b/reactos/drivers/usb/usbport/ioctl.c @@ -0,0 +1,451 @@ +#include "usbport.h" + +//#define NDEBUG +#include + +VOID +NTAPI +USBPORT_UserGetHcName(IN PDEVICE_OBJECT FdoDevice, + IN PUSBUSER_CONTROLLER_UNICODE_NAME ControllerName, + IN PUSB_UNICODE_NAME UnicodeName) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + ULONG Length; + NTSTATUS Status; + ULONG ResultLength; + + DPRINT("USBPORT_UserGetHcName: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + Length = ControllerName->Header.RequestBufferLength - + sizeof(USBUSER_CONTROLLER_UNICODE_NAME); + + RtlZeroMemory(UnicodeName, Length); + + Status = IoGetDeviceProperty(FdoExtension->CommonExtension.LowerPdoDevice, + DevicePropertyDriverKeyName, + Length, + UnicodeName->String, + &ResultLength); + + if (!NT_SUCCESS(Status)) + { + if (Status == STATUS_BUFFER_TOO_SMALL) + { + ControllerName->Header.UsbUserStatusCode = UsbUserBufferTooSmall; + } + else + { + ControllerName->Header.UsbUserStatusCode = UsbUserInvalidParameter; + } + } + else + { + ControllerName->Header.UsbUserStatusCode = UsbUserSuccess; + UnicodeName->Length = ResultLength + sizeof(UNICODE_NULL); + } + + ControllerName->Header.ActualBufferLength = sizeof(USBUSER_CONTROLLER_UNICODE_NAME) + + ResultLength; +} + +NTSTATUS +NTAPI +USBPORT_GetSymbolicName(IN PDEVICE_OBJECT RootHubPdo, + IN PUNICODE_STRING DestinationString) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUNICODE_STRING RootHubName; + PWCHAR Buffer; + SIZE_T LengthName; + SIZE_T Length; + PWSTR SourceString; + WCHAR Character; + + DPRINT("USBPORT_GetSymbolicName: ... \n"); + + PdoExtension = RootHubPdo->DeviceExtension; + RootHubName = &PdoExtension->CommonExtension.SymbolicLinkName; + Buffer = RootHubName->Buffer; + + if (!Buffer) + { + return STATUS_UNSUCCESSFUL; + } + + LengthName = RootHubName->Length; + + SourceString = ExAllocatePoolWithTag(PagedPool, LengthName, USB_PORT_TAG); + + if (!SourceString) + { + RtlInitUnicodeString(DestinationString, NULL); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(SourceString, LengthName); + + if (*Buffer == L'\\') + { + Buffer += 1; + + if (*Buffer == L'\\') + { + Buffer += 1; + goto Exit; + } + + Character = *Buffer; + + do + { + if (Character == UNICODE_NULL) + { + break; + } + + Buffer += 1; + Character = *Buffer; + } + while (*Buffer != L'\\'); + + if (*Buffer == L'\\') + { + Buffer += 1; + } + +Exit: + Length = (ULONG_PTR)Buffer - (ULONG_PTR)RootHubName->Buffer; + } + else + { + Length = 0; + } + + RtlCopyMemory(SourceString, + (PVOID)((ULONG_PTR)RootHubName->Buffer + Length), + RootHubName->Length - Length); + + RtlInitUnicodeString(DestinationString, SourceString); + + DPRINT("USBPORT_RegisterDeviceInterface: DestinationString - %wZ\n", + DestinationString); + + return STATUS_SUCCESS; +} + +VOID +NTAPI +USBPORT_UserGetRootHubName(IN PDEVICE_OBJECT FdoDevice, + IN PUSBUSER_CONTROLLER_UNICODE_NAME RootHubName, + IN PUSB_UNICODE_NAME UnicodeName) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + UNICODE_STRING UnicodeString; + ULONG Length; + ULONG ResultLength = 0; + NTSTATUS Status; + + DPRINT("USBPORT_UserGetRootHubName: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + Length = RootHubName->Header.RequestBufferLength - + sizeof(USBUSER_CONTROLLER_UNICODE_NAME); + + RtlZeroMemory(UnicodeName, Length); + + Status = USBPORT_GetSymbolicName(FdoExtension->RootHubPdo, &UnicodeString); + + if (NT_SUCCESS(Status)) + { + ResultLength = UnicodeString.Length; + + if (UnicodeString.Length > Length) + { + UnicodeString.Length = Length; + Status = STATUS_BUFFER_TOO_SMALL; + } + + if (UnicodeString.Length) + { + RtlCopyMemory(UnicodeName->String, + UnicodeString.Buffer, + UnicodeString.Length); + } + + RtlFreeUnicodeString(&UnicodeString); + } + + if (!NT_SUCCESS(Status)) + { + if (Status == STATUS_BUFFER_TOO_SMALL) + { + RootHubName->Header.UsbUserStatusCode = UsbUserBufferTooSmall; + } + else + { + RootHubName->Header.UsbUserStatusCode = UsbUserInvalidParameter; + } + } + else + { + RootHubName->Header.UsbUserStatusCode = UsbUserSuccess; + UnicodeName->Length = ResultLength + sizeof(UNICODE_NULL); + } + + RootHubName->Header.ActualBufferLength = sizeof(USBUSER_CONTROLLER_UNICODE_NAME) + + ResultLength; +} + +NTSTATUS +NTAPI +USBPORT_GetUnicodeName(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PULONG Information) +{ + PUSB_HCD_DRIVERKEY_NAME DriverKey; + PIO_STACK_LOCATION IoStack; + ULONG OutputBufferLength; + ULONG IoControlCode; + ULONG Length; + PUSBUSER_CONTROLLER_UNICODE_NAME ControllerName; + PUSB_UNICODE_NAME UnicodeName; + ULONG ActualLength; + + DPRINT("USBPORT_GetUnicodeName: ... \n"); + + *Information = 0; + DriverKey = Irp->AssociatedIrp.SystemBuffer; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + IoControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + + if (OutputBufferLength < sizeof(USB_UNICODE_NAME)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + Length = sizeof(USBUSER_CONTROLLER_UNICODE_NAME); + + while (TRUE) + { + ControllerName = ExAllocatePoolWithTag(PagedPool, + Length, + USB_PORT_TAG); + + if (!ControllerName) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(ControllerName, Length); + + ControllerName->Header.RequestBufferLength = Length; + UnicodeName = &ControllerName->UnicodeName; + + if (IoControlCode == IOCTL_GET_HCD_DRIVERKEY_NAME) + { + ControllerName->Header.UsbUserRequest = USBUSER_GET_CONTROLLER_DRIVER_KEY; + USBPORT_UserGetHcName(FdoDevice, ControllerName, UnicodeName); + } + else + { + ControllerName->Header.UsbUserRequest = USBUSER_GET_ROOTHUB_SYMBOLIC_NAME; + USBPORT_UserGetRootHubName(FdoDevice, ControllerName, UnicodeName); + } + + if (ControllerName->Header.UsbUserStatusCode != UsbUserBufferTooSmall) + { + break; + } + + Length = ControllerName->Header.ActualBufferLength; + + ExFreePoolWithTag(ControllerName, USB_PORT_TAG); + } + + if (ControllerName->Header.UsbUserStatusCode != UsbUserSuccess) + { + return STATUS_UNSUCCESSFUL; + } + + ActualLength = sizeof(ULONG) + ControllerName->UnicodeName.Length; + + DriverKey->ActualLength = ActualLength; + + if (OutputBufferLength < ActualLength) + { + DriverKey->DriverKeyName[0] = UNICODE_NULL; + *Information = sizeof(USB_UNICODE_NAME); + } + else + { + RtlCopyMemory(DriverKey->DriverKeyName, + ControllerName->UnicodeName.String, + ControllerName->UnicodeName.Length); + + *Information = DriverKey->ActualLength; + } + + ExFreePoolWithTag(ControllerName, USB_PORT_TAG); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_PdoDeviceControl(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + DPRINT1("USBPORT_PdoDeviceControl: UNIMPLEMENTED. FIXME. \n"); + return 0; +} + +NTSTATUS +NTAPI +USBPORT_PdoInternalDeviceControl(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PIO_STACK_LOCATION IoStack; + ULONG IoCtl; + NTSTATUS Status; + + PdoExtension = PdoDevice->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + IoCtl = IoStack->Parameters.DeviceIoControl.IoControlCode; + + DPRINT("USBPORT_PdoInternalDeviceControl: PdoDevice - %p, Irp - %p, IoCtl - %x\n", + PdoDevice, + Irp, + IoCtl); + + if (IoCtl == IOCTL_INTERNAL_USB_SUBMIT_URB) + { + return USBPORT_HandleSubmitURB(PdoDevice, Irp, URB_FROM_IRP(Irp)); + } + + if (IoCtl == IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO) + { + DPRINT("USBPORT_PdoInternalDeviceControl: IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n"); + + if (IoStack->Parameters.Others.Argument1) + *(PVOID *)IoStack->Parameters.Others.Argument1 = PdoDevice; + + if (IoStack->Parameters.Others.Argument2) + *(PVOID *)IoStack->Parameters.Others.Argument2 = PdoDevice; + + Status = STATUS_SUCCESS; + goto Exit; + } + + if (IoCtl == IOCTL_INTERNAL_USB_GET_HUB_COUNT) + { + DPRINT("USBPORT_PdoInternalDeviceControl: IOCTL_INTERNAL_USB_GET_HUB_COUNT\n"); + + if (IoStack->Parameters.Others.Argument1) + { + ++*(PULONG)IoStack->Parameters.Others.Argument1; + } + + Status = STATUS_SUCCESS; + goto Exit; + } + + if (IoCtl == IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE) + { + DPRINT("USBPORT_PdoInternalDeviceControl: IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n"); + + if (IoStack->Parameters.Others.Argument1) + { + *(PVOID *)IoStack->Parameters.Others.Argument1 = &PdoExtension->DeviceHandle; + } + + Status = STATUS_SUCCESS; + goto Exit; + } + + if (IoCtl == IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION) + { + DPRINT("USBPORT_PdoInternalDeviceControl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n"); + return USBPORT_IdleNotification(PdoDevice, Irp); + } + + DPRINT("USBPORT_PdoInternalDeviceControl: INVALID INTERNAL DEVICE CONTROL\n"); + Status = STATUS_INVALID_DEVICE_REQUEST; + +Exit: + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +NTSTATUS +NTAPI +USBPORT_FdoDeviceControl(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIO_STACK_LOCATION IoStack; + ULONG ControlCode; + NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST; + ULONG_PTR Information = 0; + + DPRINT("USBPORT_FdoDeviceControl: Irp - %p\n", Irp); + + FdoExtension = FdoDevice->DeviceExtension; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + + switch (ControlCode) + { + case IOCTL_USB_DIAGNOSTIC_MODE_ON: + DPRINT("USBPORT_FdoDeviceControl: IOCTL_USB_DIAGNOSTIC_MODE_ON\n"); + FdoExtension->Flags |= USBPORT_FLAG_DIAGNOSTIC_MODE; + break; + + case IOCTL_USB_DIAGNOSTIC_MODE_OFF: + DPRINT("USBPORT_FdoDeviceControl: IOCTL_USB_DIAGNOSTIC_MODE_OFF\n"); + FdoExtension->Flags &= ~USBPORT_FLAG_DIAGNOSTIC_MODE; + break; + + case IOCTL_USB_GET_NODE_INFORMATION: + DPRINT1("USBPORT_FdoDeviceControl: IOCTL_USB_GET_NODE_INFORMATION\n"); + Status = USBPORT_GetUnicodeName(FdoDevice, Irp, &Information); + break; + + case IOCTL_GET_HCD_DRIVERKEY_NAME: + DPRINT1("USBPORT_FdoDeviceControl: IOCTL_GET_HCD_DRIVERKEY_NAME\n"); + Status = USBPORT_GetUnicodeName(FdoDevice, Irp, &Information); + break; + + case IOCTL_USB_USER_REQUEST: + DPRINT1("USBPORT_FdoDeviceControl: IOCTL_USB_USER_REQUEST UNIMPLEMENTED. FIXME\n"); + break; + + default: + DPRINT1("USBPORT_FdoDeviceControl: Not supported IoControlCode - %x\n", + ControlCode); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = Information; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_FdoInternalDeviceControl(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + DPRINT1("USBPORT_FdoInternalDeviceControl: UNIMPLEMENTED. FIXME. \n"); + return 0; +} diff --git a/reactos/drivers/usb/usbport/pnp.c b/reactos/drivers/usb/usbport/pnp.c new file mode 100644 index 00000000000..844e7db3e28 --- /dev/null +++ b/reactos/drivers/usb/usbport/pnp.c @@ -0,0 +1,1792 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_CORE +#include "usbdebug.h" + +IO_COMPLETION_ROUTINE USBPORT_FdoStartCompletion; + +NTSTATUS +NTAPI +USBPORT_FdoStartCompletion(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + KeSetEvent((PKEVENT)Context, EVENT_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBPORT_RegisterDeviceInterface(IN PDEVICE_OBJECT PdoDevice, + IN PDEVICE_OBJECT DeviceObject, + IN CONST GUID *InterfaceClassGuid, + IN BOOLEAN Enable) +{ + PUSBPORT_RHDEVICE_EXTENSION DeviceExtension; + PUNICODE_STRING SymbolicLinkName; + NTSTATUS Status; + + DPRINT("USBPORT_RegisterDeviceInterface: Enable - %x\n", Enable); + + DeviceExtension = DeviceObject->DeviceExtension; + SymbolicLinkName = &DeviceExtension->CommonExtension.SymbolicLinkName; + + if (Enable) + { + Status = IoRegisterDeviceInterface(PdoDevice, + InterfaceClassGuid, + NULL, + SymbolicLinkName); + + if (NT_SUCCESS(Status)) + { + DeviceExtension->CommonExtension.IsInterfaceEnabled = 1; + + Status = USBPORT_SetRegistryKeyValue(PdoDevice, + FALSE, + REG_SZ, + L"SymbolicName", + SymbolicLinkName->Buffer, + SymbolicLinkName->Length); + + if (NT_SUCCESS(Status)) + { + DPRINT("USBPORT_RegisterDeviceInterface: LinkName - %wZ\n", + &DeviceExtension->CommonExtension.SymbolicLinkName); + + Status = IoSetDeviceInterfaceState(SymbolicLinkName, TRUE); + } + } + } + else + { + /* Disable device interface */ + Status = IoSetDeviceInterfaceState(SymbolicLinkName, FALSE); + + if (NT_SUCCESS(Status)) + { + RtlFreeUnicodeString(SymbolicLinkName); + DeviceExtension->CommonExtension.IsInterfaceEnabled = 0; // Disabled interface + } + } + + return Status; +} + +BOOLEAN +NTAPI +USBPORT_IsSelectiveSuspendEnabled(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + ULONG Disabled = 0; + + DPRINT("USBPORT_IsSelectiveSuspendEnabled: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + L"HcDisableSelectiveSuspend", + sizeof(L"HcDisableSelectiveSuspend"), + &Disabled, + sizeof(Disabled)); + + return (Disabled == 0); +} + +NTSTATUS +NTAPI +USBPORT_GetConfigValue(IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext) +{ + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("USBPORT_GetConfigValue \n"); + + if (ValueType == REG_DWORD) + { + *(PULONG)EntryContext = *(PULONG)ValueData; + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_GetDefaultBIOSx(IN PDEVICE_OBJECT FdoDevice, + IN PULONG UsbBIOSx, + IN PULONG DisableSelectiveSuspend, + IN PULONG DisableCcDetect, + IN PULONG IdleEpSupport, + IN PULONG IdleEpSupportEx, + IN PULONG SoftRetry) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[7]; + + DPRINT("USBPORT_GetDefaultBIOS_X: ... \n"); + + RtlZeroMemory(QueryTable, sizeof(QueryTable)); + + *UsbBIOSx = 2; + + QueryTable[0].QueryRoutine = USBPORT_GetConfigValue; + QueryTable[0].Flags = 0; + QueryTable[0].Name = L"UsbBIOSx"; + QueryTable[0].EntryContext = UsbBIOSx; + QueryTable[0].DefaultType = REG_DWORD; + QueryTable[0].DefaultData = UsbBIOSx; + QueryTable[0].DefaultLength = sizeof(ULONG); + + QueryTable[1].QueryRoutine = USBPORT_GetConfigValue; + QueryTable[1].Flags = 0; + QueryTable[1].Name = L"DisableSelectiveSuspend"; + QueryTable[1].EntryContext = DisableSelectiveSuspend; + QueryTable[1].DefaultType = REG_DWORD; + QueryTable[1].DefaultData = DisableSelectiveSuspend; + QueryTable[1].DefaultLength = sizeof(ULONG); + + QueryTable[2].QueryRoutine = USBPORT_GetConfigValue; + QueryTable[2].Flags = 0; + QueryTable[2].Name = L"DisableCcDetect"; + QueryTable[2].EntryContext = DisableCcDetect; + QueryTable[2].DefaultType = REG_DWORD; + QueryTable[2].DefaultData = DisableCcDetect; + QueryTable[2].DefaultLength = sizeof(ULONG); + + QueryTable[3].QueryRoutine = USBPORT_GetConfigValue; + QueryTable[3].Flags = 0; + QueryTable[3].Name = L"EnIdleEndpointSupport"; + QueryTable[3].EntryContext = IdleEpSupport; + QueryTable[3].DefaultType = REG_DWORD; + QueryTable[3].DefaultData = IdleEpSupport; + QueryTable[3].DefaultLength = sizeof(ULONG); + + QueryTable[4].QueryRoutine = USBPORT_GetConfigValue; + QueryTable[4].Flags = 0; + QueryTable[4].Name = L"EnIdleEndpointSupportEx"; + QueryTable[4].EntryContext = IdleEpSupportEx; + QueryTable[4].DefaultType = REG_DWORD; + QueryTable[4].DefaultData = IdleEpSupportEx; + QueryTable[4].DefaultLength = sizeof(ULONG); + + QueryTable[5].QueryRoutine = USBPORT_GetConfigValue; + QueryTable[5].Flags = 0; + QueryTable[5].Name = L"EnSoftRetry"; + QueryTable[5].EntryContext = SoftRetry; + QueryTable[5].DefaultType = REG_DWORD; + QueryTable[5].DefaultData = SoftRetry; + QueryTable[5].DefaultLength = sizeof(ULONG); + + return RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, + L"usb", + QueryTable, + NULL, + NULL); +} + +NTSTATUS +NTAPI +USBPORT_IsCompanionController(IN PDEVICE_OBJECT DeviceObject, + IN BOOLEAN *IsCompanion) +{ + PDEVICE_OBJECT HighestDevice; + PIRP Irp; + KEVENT Event; + PIO_STACK_LOCATION IoStack; + PCI_DEVICE_PRESENT_INTERFACE PciInterface = {0}; + PCI_DEVICE_PRESENCE_PARAMETERS Parameters = {0}; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + BOOLEAN IsPresent; + + DPRINT("USBPORT_IsCompanionController: ... \n"); + + *IsCompanion = FALSE; + + KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + + HighestDevice = IoGetAttachedDeviceReference(DeviceObject); + + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, + HighestDevice, + NULL, + 0, + NULL, + &Event, + &IoStatusBlock); + + if (!Irp) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + ObDereferenceObject(HighestDevice); + return Status; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + Irp->IoStatus.Information = 0; + + IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + + IoStack->Parameters.QueryInterface.InterfaceType = &GUID_PCI_DEVICE_PRESENT_INTERFACE; + IoStack->Parameters.QueryInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE); + IoStack->Parameters.QueryInterface.Version = 1; + IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)&PciInterface; + IoStack->Parameters.QueryInterface.InterfaceSpecificData = 0; + + Status = IoCallDriver(HighestDevice, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatusBlock.Status; + } + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_IsCompanionController: query interface failed\\n"); + ObDereferenceObject(HighestDevice); + return Status; + } + + DPRINT("USBPORT_IsCompanionController: query interface succeeded\n"); + + if (PciInterface.Size < sizeof(PCI_DEVICE_PRESENT_INTERFACE)) + { + DPRINT1("USBPORT_IsCompanionController: old version\n"); + ObDereferenceObject(HighestDevice); + return Status; + } + + Parameters.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE); + + Parameters.BaseClass = PCI_CLASS_SERIAL_BUS_CTLR; + Parameters.SubClass = PCI_SUBCLASS_SB_USB; + Parameters.ProgIf = PCI_INTERFACE_USB_ID_EHCI; + + Parameters.Flags = PCI_USE_LOCAL_BUS | + PCI_USE_LOCAL_DEVICE | + PCI_USE_CLASS_SUBCLASS | + PCI_USE_PROGIF; + + IsPresent = (PciInterface.IsDevicePresentEx)(PciInterface.Context, + &Parameters); + + if (IsPresent) + { + DPRINT("USBPORT_IsCompanionController: Present EHCI controller for FDO - %p\n", + DeviceObject); + } + else + { + DPRINT("USBPORT_IsCompanionController: No EHCI controller for FDO - %p\n", + DeviceObject); + } + + *IsCompanion = IsPresent; + + (PciInterface.InterfaceDereference)(PciInterface.Context); + + ObDereferenceObject(HighestDevice); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_QueryPciBusInterface(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PBUS_INTERFACE_STANDARD BusInterface; + PIO_STACK_LOCATION IoStack; + IO_STATUS_BLOCK IoStatusBlock; + PDEVICE_OBJECT HighestDevice; + KEVENT Event; + PIRP Irp; + NTSTATUS Status; + + DPRINT("USBPORT_QueryPciBusInterface: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + BusInterface = &FdoExtension->BusInterface; + + RtlZeroMemory(BusInterface, sizeof(BUS_INTERFACE_STANDARD)); + KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + HighestDevice = IoGetAttachedDeviceReference(FdoDevice); + + Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, + HighestDevice, + NULL, + 0, + NULL, + &Event, + &IoStatusBlock); + + if (Irp) + { + IoStack = IoGetNextIrpStackLocation(Irp); + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + Irp->IoStatus.Information = 0; + + IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + + IoStack->Parameters.QueryInterface.InterfaceType = &GUID_BUS_INTERFACE_STANDARD; + IoStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD); + IoStack->Parameters.QueryInterface.Version = 1; + IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface; + IoStack->Parameters.QueryInterface.InterfaceSpecificData = 0; + + Status = IoCallDriver(HighestDevice, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatusBlock.Status; + } + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + ObDereferenceObject(HighestDevice); + + DPRINT("USBPORT_QueryPciBusInterface: return Status - %x\n", Status); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_QueryCapabilities(IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_CAPABILITIES Capabilities) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtention; + PIRP Irp; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + KEVENT Event; + + DPRINT("USBPORT_QueryCapabilities: ... \n"); + + FdoExtention = FdoDevice->DeviceExtension; + + RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES)); + + Capabilities->Size = sizeof(DEVICE_CAPABILITIES); + Capabilities->Version = 1; + Capabilities->Address = MAXULONG; + Capabilities->UINumber = MAXULONG; + + Irp = IoAllocateIrp(FdoExtention->CommonExtension.LowerDevice->StackSize, + FALSE); + + if (!Irp) + { + DPRINT1("USBPORT_QueryCapabilities: No resources - IoAllocateIrp!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->MajorFunction = IRP_MJ_PNP; + IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + IoSetCompletionRoutine(Irp, + USBPORT_FdoStartCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities; + + Status = IoCallDriver(FdoExtention->CommonExtension.LowerDevice, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); + Status = Irp->IoStatus.Status; + } + + if (NT_SUCCESS(Status) && Capabilities) + { + USBPORT_DumpingCapabilities(Capabilities); + } + + IoFreeIrp(Irp); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_CreateLegacySymbolicLink(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + WCHAR CharName[255] = {0}; + WCHAR CharDosName[255] = {0}; + UNICODE_STRING DeviceName; + NTSTATUS Status; + + FdoExtension = FdoDevice->DeviceExtension; + + RtlStringCbPrintfW(CharName, + sizeof(CharName), + L"\\Device\\USBFDO-%d", + FdoExtension->FdoNameNumber); + + RtlInitUnicodeString(&DeviceName, CharName); + + RtlStringCbPrintfW(CharDosName, + sizeof(CharDosName), + L"\\DosDevices\\HCD%d", + FdoExtension->FdoNameNumber); + + RtlInitUnicodeString(&FdoExtension->DosDeviceSymbolicName, CharDosName); + + DPRINT("USBPORT_CreateLegacySymbolicLink: DeviceName - %wZ, DosSymbolicName - %wZ\n", + &DeviceName, + &FdoExtension->DosDeviceSymbolicName); + + Status = IoCreateSymbolicLink(&FdoExtension->DosDeviceSymbolicName, + &DeviceName); + + if (NT_SUCCESS(Status)) + { + FdoExtension->Flags |= USBPORT_FLAG_DOS_SYMBOLIC_NAME; + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_StopDevice(IN PDEVICE_OBJECT FdoDevice) +{ + DPRINT1("USBPORT_StopDevice: UNIMPLEMENTED. FIXME\n"); + DbgBreakPoint(); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_StartDevice(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_RESOURCES UsbPortResources) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + NTSTATUS Status; + PCI_COMMON_CONFIG PciConfig; + ULONG BytesRead; + DEVICE_DESCRIPTION DeviceDescription; + PDMA_ADAPTER DmaAdapter = NULL; + ULONG MiniPortStatus; + PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer; + ULONG ResultLength; + ULONG DisableSelectiveSuspend = 0; + ULONG DisableCcDetect = 0; + ULONG IdleEpSupport = 0; + ULONG IdleEpSupportEx = 0; + ULONG SoftRetry = 0; + ULONG Limit2GB = 0; + ULONG TotalBusBandwidth = 0; + BOOLEAN IsCompanion = FALSE; + ULONG LegacyBIOS; + ULONG MiniportFlags; + + DPRINT("USBPORT_StartDevice: FdoDevice - %p, UsbPortResources - %p\n", + FdoDevice, + UsbPortResources); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + Status = USBPORT_QueryPciBusInterface(FdoDevice); + if (!NT_SUCCESS(Status)) + goto ExitWithError; + + BytesRead = (*FdoExtension->BusInterface.GetBusData)(FdoExtension->BusInterface.Context, + PCI_WHICHSPACE_CONFIG, + &PciConfig, + 0, + PCI_COMMON_HDR_LENGTH); + + if (BytesRead != PCI_COMMON_HDR_LENGTH) + { + DPRINT1("USBPORT_StartDevice: Failed to get pci config information!\n"); + goto ExitWithError; + } + + FdoExtension->VendorID = PciConfig.VendorID; + FdoExtension->DeviceID = PciConfig.DeviceID; + FdoExtension->RevisionID = PciConfig.RevisionID; + FdoExtension->ProgIf = PciConfig.ProgIf; + FdoExtension->SubClass = PciConfig.SubClass; + FdoExtension->BaseClass = PciConfig.BaseClass; + + RtlZeroMemory(&DeviceDescription, sizeof(DeviceDescription)); + + DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; + DeviceDescription.Master = TRUE; + DeviceDescription.ScatterGather = TRUE; + DeviceDescription.Dma32BitAddresses = TRUE; + DeviceDescription.InterfaceType = PCIBus; + DeviceDescription.DmaWidth = Width32Bits; + DeviceDescription.DmaSpeed = Compatible; + DeviceDescription.MaximumLength = MAXULONG; + + DmaAdapter = IoGetDmaAdapter(FdoExtension->CommonExtension.LowerPdoDevice, + &DeviceDescription, + &FdoExtension->NumberMapRegs); + + FdoExtension->DmaAdapter = DmaAdapter; + + if (!DmaAdapter) + { + DPRINT1("USBPORT_StartDevice: Failed to get DmaAdapter!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ExitWithError; + } + + Status = USBPORT_CreateWorkerThread(FdoDevice); + if (!NT_SUCCESS(Status)) + goto ExitWithError; + + Status = USBPORT_QueryCapabilities(FdoDevice, &FdoExtension->Capabilities); + if (!NT_SUCCESS(Status)) + goto ExitWithError; + + FdoExtension->PciDeviceNumber = FdoExtension->Capabilities.Address >> 16; + FdoExtension->PciFunctionNumber = FdoExtension->Capabilities.Address & 0xFFFF; + + Status = IoGetDeviceProperty(FdoExtension->CommonExtension.LowerPdoDevice, + DevicePropertyBusNumber, + sizeof(ULONG), + &FdoExtension->BusNumber, + &ResultLength); + + if (!NT_SUCCESS(Status)) + goto ExitWithError; + + KeInitializeSpinLock(&FdoExtension->EndpointListSpinLock); + KeInitializeSpinLock(&FdoExtension->EpStateChangeSpinLock); + KeInitializeSpinLock(&FdoExtension->EndpointClosedSpinLock); + KeInitializeSpinLock(&FdoExtension->DeviceHandleSpinLock); + KeInitializeSpinLock(&FdoExtension->IdleIoCsqSpinLock); + KeInitializeSpinLock(&FdoExtension->BadRequestIoCsqSpinLock); + KeInitializeSpinLock(&FdoExtension->MapTransferSpinLock); + KeInitializeSpinLock(&FdoExtension->FlushTransferSpinLock); + KeInitializeSpinLock(&FdoExtension->FlushPendingTransferSpinLock); + KeInitializeSpinLock(&FdoExtension->DoneTransferSpinLock); + KeInitializeSpinLock(&FdoExtension->WorkerThreadEventSpinLock); + KeInitializeSpinLock(&FdoExtension->MiniportSpinLock); + KeInitializeSpinLock(&FdoExtension->TimerFlagsSpinLock); + KeInitializeSpinLock(&FdoExtension->PowerWakeSpinLock); + KeInitializeSpinLock(&FdoExtension->SetPowerD0SpinLock); + KeInitializeSpinLock(&FdoExtension->RootHubCallbackSpinLock); + + KeInitializeDpc(&FdoExtension->IsrDpc, USBPORT_IsrDpc, FdoDevice); + + KeInitializeDpc(&FdoExtension->TransferFlushDpc, + USBPORT_TransferFlushDpc, + FdoDevice); + + KeInitializeDpc(&FdoExtension->WorkerRequestDpc, + USBPORT_WorkerRequestDpc, + FdoDevice); + + KeInitializeDpc(&FdoExtension->HcWakeDpc, + USBPORT_HcWakeDpc, + FdoDevice); + + IoCsqInitialize(&FdoExtension->IdleIoCsq, + USBPORT_InsertIdleIrp, + USBPORT_RemoveIdleIrp, + USBPORT_PeekNextIdleIrp, + USBPORT_AcquireIdleLock, + USBPORT_ReleaseIdleLock, + USBPORT_CompleteCanceledIdleIrp); + + IoCsqInitialize(&FdoExtension->BadRequestIoCsq, + USBPORT_InsertBadRequest, + USBPORT_RemoveBadRequest, + USBPORT_PeekNextBadRequest, + USBPORT_AcquireBadRequestLock, + USBPORT_ReleaseBadRequestLock, + USBPORT_CompleteCanceledBadRequest); + + FdoExtension->IsrDpcCounter = -1; + FdoExtension->IsrDpcHandlerCounter = -1; + FdoExtension->IdleLockCounter = -1; + FdoExtension->BadRequestLockCounter = -1; + FdoExtension->ChirpRootPortLock = -1; + + FdoExtension->RHInitCallBackLock = 0; + + FdoExtension->UsbAddressBitMap[0] = 1; + FdoExtension->UsbAddressBitMap[1] = 0; + FdoExtension->UsbAddressBitMap[2] = 0; + FdoExtension->UsbAddressBitMap[3] = 0; + + USBPORT_GetDefaultBIOSx(FdoDevice, + &FdoExtension->UsbBIOSx, + &DisableSelectiveSuspend, + &DisableCcDetect, + &IdleEpSupport, + &IdleEpSupportEx, + &SoftRetry); + + if (DisableSelectiveSuspend) + FdoExtension->Flags |= USBPORT_FLAG_BIOS_DISABLE_SS; + + if (!DisableSelectiveSuspend && + USBPORT_IsSelectiveSuspendEnabled(FdoDevice)) + { + FdoExtension->Flags |= USBPORT_FLAG_SELECTIVE_SUSPEND; + } + + MiniportFlags = Packet->MiniPortFlags; + + if (MiniportFlags & USB_MINIPORT_FLAGS_POLLING) + FdoExtension->Flags |= USBPORT_FLAG_HC_POLLING; + + if (MiniportFlags & USB_MINIPORT_FLAGS_WAKE_SUPPORT) + FdoExtension->Flags |= USBPORT_FLAG_HC_WAKE_SUPPORT; + + if (MiniportFlags & USB_MINIPORT_FLAGS_DISABLE_SS) + FdoExtension->Flags = (FdoExtension->Flags & ~USBPORT_FLAG_SELECTIVE_SUSPEND) | + USBPORT_FLAG_BIOS_DISABLE_SS; + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + REG_DWORD, + L"EnIdleEndpointSupport", + &IdleEpSupport, + sizeof(IdleEpSupport)); + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + REG_DWORD, + L"EnIdleEndpointSupportEx", + &IdleEpSupportEx, + sizeof(IdleEpSupportEx)); + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + REG_DWORD, + L"EnSoftRetry", + &SoftRetry, + sizeof(SoftRetry)); + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + L"CommonBuffer2GBLimit", + sizeof(L"CommonBuffer2GBLimit"), + &Limit2GB, + sizeof(Limit2GB)); + + FdoExtension->CommonBufferLimit = (Limit2GB != 0); + + if (FdoExtension->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR && + FdoExtension->SubClass == PCI_SUBCLASS_SB_USB && + FdoExtension->ProgIf < PCI_INTERFACE_USB_ID_EHCI) + { + Status = USBPORT_IsCompanionController(FdoDevice, &IsCompanion); + + if (!NT_SUCCESS(Status)) + { + if (IsCompanion) + { + FdoExtension->Flags |= USBPORT_FLAG_COMPANION_HC; + } + else + { + FdoExtension->Flags &= ~USBPORT_FLAG_COMPANION_HC; + } + } + } + + if (DisableCcDetect) + { + FdoExtension->Flags &= ~USBPORT_FLAG_COMPANION_HC; + } + + TotalBusBandwidth = Packet->MiniPortBusBandwidth; + FdoExtension->TotalBusBandwidth = TotalBusBandwidth; + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + TRUE, + L"TotalBusBandwidth", + sizeof(L"TotalBusBandwidth"), + &TotalBusBandwidth, + sizeof(TotalBusBandwidth)); + + if (TotalBusBandwidth != FdoExtension->TotalBusBandwidth) + { + FdoExtension->TotalBusBandwidth = TotalBusBandwidth; + } + + FdoExtension->ActiveIrpTable = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBPORT_IRP_TABLE), + USB_PORT_TAG); + + if (!FdoExtension->ActiveIrpTable) + { + DPRINT1("USBPORT_StartDevice: Allocate ActiveIrpTable failed!\n"); + goto ExitWithError; + } + + RtlZeroMemory(FdoExtension->ActiveIrpTable, sizeof(USBPORT_IRP_TABLE)); + + FdoExtension->PendingIrpTable = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBPORT_IRP_TABLE), + USB_PORT_TAG); + + if (!FdoExtension->PendingIrpTable) + { + DPRINT1("USBPORT_StartDevice: Allocate PendingIrpTable failed!\n"); + goto ExitWithError; + } + + RtlZeroMemory(FdoExtension->PendingIrpTable, sizeof(USBPORT_IRP_TABLE)); + + Status = IoConnectInterrupt(&FdoExtension->InterruptObject, + USBPORT_InterruptService, + (PVOID)FdoDevice, + 0, + UsbPortResources->InterruptVector, + UsbPortResources->InterruptLevel, + UsbPortResources->InterruptLevel, + UsbPortResources->InterruptMode, + UsbPortResources->ShareVector, + UsbPortResources->InterruptAffinity, + 0); + + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_StartDevice: IoConnectInterrupt failed!\n"); + goto ExitWithError; + } + + FdoExtension->Flags &= ~USBPORT_FLAG_INT_CONNECTED; + + if (Packet->MiniPortExtensionSize) + { + RtlZeroMemory(FdoExtension->MiniPortExt, Packet->MiniPortExtensionSize); + } + + if (Packet->MiniPortResourcesSize) + { + HeaderBuffer = USBPORT_AllocateCommonBuffer(FdoDevice, + Packet->MiniPortResourcesSize); + + if (!HeaderBuffer) + { + DPRINT1("USBPORT_StartDevice: Failed to AllocateCommonBuffer!\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ExitWithError; + } + + UsbPortResources->StartVA = (PVOID)HeaderBuffer->VirtualAddress; + UsbPortResources->StartPA = (PVOID)HeaderBuffer->PhysicalAddress; + + FdoExtension->MiniPortCommonBuffer = HeaderBuffer; + } + else + { + FdoExtension->MiniPortCommonBuffer = NULL; + } + + MiniPortStatus = Packet->StartController(FdoExtension->MiniPortExt, + UsbPortResources); + + if (UsbPortResources->LegacySupport) + { + FdoExtension->Flags |= USBPORT_FLAG_LEGACY_SUPPORT; + LegacyBIOS = 1; + } + else + { + LegacyBIOS = 0; + } + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + FALSE, + REG_DWORD, + L"DetectedLegacyBIOS", + &LegacyBIOS, + sizeof(LegacyBIOS)); + + if (MiniPortStatus) + { + DPRINT1("USBPORT_StartDevice: Failed to Start MiniPort. MiniPortStatus - %x\n", + MiniPortStatus); + + if (FdoExtension->Flags & USBPORT_FLAG_INT_CONNECTED) + { + IoDisconnectInterrupt(FdoExtension->InterruptObject); + FdoExtension->Flags &= ~USBPORT_FLAG_INT_CONNECTED; + } + + if (FdoExtension->MiniPortCommonBuffer) + { + USBPORT_FreeCommonBuffer(FdoDevice, FdoExtension->MiniPortCommonBuffer); + FdoExtension->MiniPortCommonBuffer = NULL; + } + + goto ExitWithError; + } + else + { + FdoExtension->MiniPortFlags |= USBPORT_MPFLAG_INTERRUPTS_ENABLED; + USBPORT_MiniportInterrupts(FdoDevice, TRUE); + } + + FdoExtension->TimerValue = 500; + USBPORT_StartTimer((PVOID)FdoDevice, 500); + + Status = USBPORT_RegisterDeviceInterface(FdoExtension->CommonExtension.LowerPdoDevice, + FdoDevice, + &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, + TRUE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_StartDevice: RegisterDeviceInterface failed!\n"); + goto ExitWithError; + } + + USBPORT_CreateLegacySymbolicLink(FdoDevice); + + FdoExtension->Flags |= USBPORT_FLAG_HC_STARTED; + + DPRINT("USBPORT_StartDevice: Exit Status - %p\n", Status); + return Status; + +ExitWithError: + USBPORT_StopDevice(FdoDevice); + + DPRINT1("USBPORT_StartDevice: ExitWithError Status - %lx\n", Status); + return Status; +} + +NTSTATUS +NTAPI +USBPORT_ParseResources(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PUSBPORT_RESOURCES UsbPortResources) +{ + PCM_RESOURCE_LIST AllocatedResourcesTranslated; + PCM_PARTIAL_RESOURCE_LIST ResourceList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PortDescriptor = NULL; + PCM_PARTIAL_RESOURCE_DESCRIPTOR MemoryDescriptor = NULL; + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDescriptor = NULL; + PIO_STACK_LOCATION IoStack; + ULONG ix; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("USBPORT_ParseResources: ... \n"); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + AllocatedResourcesTranslated = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; + + if (AllocatedResourcesTranslated) + { + RtlZeroMemory(UsbPortResources, sizeof(USBPORT_RESOURCES)); + + ResourceList = &AllocatedResourcesTranslated->List[0].PartialResourceList; + + PartialDescriptor = &ResourceList->PartialDescriptors[0]; + + for (ix = 0; ix < ResourceList->Count; ++ix) + { + if (PartialDescriptor->Type == CmResourceTypePort) + { + if (!PortDescriptor) + PortDescriptor = PartialDescriptor; + } + else if (PartialDescriptor->Type == CmResourceTypeInterrupt) + { + if (!InterruptDescriptor) + InterruptDescriptor = PartialDescriptor; + } + else if (PartialDescriptor->Type == CmResourceTypeMemory) + { + if (!MemoryDescriptor) + MemoryDescriptor = PartialDescriptor; + } + + PartialDescriptor += 1; + } + + if (PortDescriptor) + { + if (PortDescriptor->Flags & CM_RESOURCE_PORT_IO) + { + UsbPortResources->ResourceBase = (PVOID)PortDescriptor->u.Port.Start.LowPart; + } + else + { + UsbPortResources->ResourceBase = MmMapIoSpace(PortDescriptor->u.Port.Start, + PortDescriptor->u.Port.Length, + 0); + } + + UsbPortResources->IoSpaceLength = PortDescriptor->u.Port.Length; + + if (UsbPortResources->ResourceBase) + { + UsbPortResources->ResourcesTypes |= USBPORT_RESOURCES_PORT; + } + else + { + Status = STATUS_NONE_MAPPED; + } + } + + if (MemoryDescriptor && NT_SUCCESS(Status)) + { + UsbPortResources->IoSpaceLength = MemoryDescriptor->u.Memory.Length; + + UsbPortResources->ResourceBase = MmMapIoSpace(MemoryDescriptor->u.Memory.Start, + MemoryDescriptor->u.Memory.Length, + 0); + + if (UsbPortResources->ResourceBase) + { + UsbPortResources->ResourcesTypes |= USBPORT_RESOURCES_MEMORY; + } + else + { + Status = STATUS_NONE_MAPPED; + } + } + + if (InterruptDescriptor && NT_SUCCESS(Status)) + { + UsbPortResources->ResourcesTypes |= USBPORT_RESOURCES_INTERRUPT; + + UsbPortResources->InterruptVector = InterruptDescriptor->u.Interrupt.Vector; + UsbPortResources->InterruptLevel = InterruptDescriptor->u.Interrupt.Level; + UsbPortResources->InterruptAffinity = InterruptDescriptor->u.Interrupt.Affinity; + + UsbPortResources->ShareVector = InterruptDescriptor->ShareDisposition == + CmResourceShareShared; + + UsbPortResources->InterruptMode = InterruptDescriptor->Flags == + CM_RESOURCE_INTERRUPT_LATCHED; + } + } + else + { + Status = STATUS_NONE_MAPPED; + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_CreatePdo(IN PDEVICE_OBJECT FdoDevice, + OUT PDEVICE_OBJECT *RootHubPdo) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + UNICODE_STRING DeviceName; + ULONG DeviceNumber = 0; + PDEVICE_OBJECT DeviceObject = NULL; + WCHAR CharDeviceName[64]; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("USBPORT_CreatePdo: FdoDevice - %p, RootHubPdo - %p\n", + FdoDevice, + RootHubPdo); + + FdoExtension = FdoDevice->DeviceExtension; + + do + { + RtlStringCbPrintfW(CharDeviceName, + sizeof(CharDeviceName), + L"\\Device\\USBPDO-%d", + DeviceNumber); + + RtlInitUnicodeString(&DeviceName, CharDeviceName); + + DPRINT("USBPORT_CreatePdo: DeviceName - %wZ\n", &DeviceName); + + Status = IoCreateDevice(FdoExtension->MiniPortInterface->DriverObject, + sizeof(USBPORT_RHDEVICE_EXTENSION), + &DeviceName, + FILE_DEVICE_BUS_EXTENDER, + 0, + FALSE, + &DeviceObject); + + ++DeviceNumber; + } + while (Status == STATUS_OBJECT_NAME_COLLISION); + + if (!NT_SUCCESS(Status)) + { + *RootHubPdo = NULL; + DPRINT1("USBPORT_CreatePdo: Filed create HubPdo!\n"); + return Status; + } + + if (DeviceObject) + { + PdoExtension = DeviceObject->DeviceExtension; + + RtlZeroMemory(PdoExtension, sizeof(USBPORT_RHDEVICE_EXTENSION)); + + PdoExtension->CommonExtension.SelfDevice = DeviceObject; + PdoExtension->CommonExtension.IsPDO = TRUE; + + PdoExtension->FdoDevice = FdoDevice; + PdoExtension->PdoNameNumber = DeviceNumber; + + USBPORT_AdjustDeviceCapabilities(FdoDevice, DeviceObject); + + DeviceObject->StackSize = FdoDevice->StackSize; + + DeviceObject->Flags |= DO_POWER_PAGABLE; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + } + else + { + Status = STATUS_UNSUCCESSFUL; + } + + if (!NT_SUCCESS(Status)) + *RootHubPdo = NULL; + else + *RootHubPdo = DeviceObject; + + DPRINT("USBPORT_CreatePdo: HubPdo - %p\n", DeviceObject); + return Status; +} + +NTSTATUS +NTAPI +USBPORT_FdoPnP(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_COMMON_DEVICE_EXTENSION FdoCommonExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PUSBPORT_RESOURCES UsbPortResources; + PIO_STACK_LOCATION IoStack; + UCHAR Minor; + KEVENT Event; + NTSTATUS Status; + DEVICE_RELATION_TYPE RelationType; + PDEVICE_RELATIONS DeviceRelations; + PDEVICE_OBJECT RootHubPdo; + + FdoExtension = FdoDevice->DeviceExtension; + FdoCommonExtension = &FdoExtension->CommonExtension; + UsbPortResources = &FdoExtension->UsbPortResources; + Packet = &FdoExtension->MiniPortInterface->Packet; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Minor = IoStack->MinorFunction; + + DPRINT("USBPORT_FdoPnP: FdoDevice - %p, Minor - %x\n", FdoDevice, Minor); + + RelationType = IoStack->Parameters.QueryDeviceRelations.Type; + + switch (Minor) + { + case IRP_MN_START_DEVICE: + DPRINT("IRP_MN_START_DEVICE\n"); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBPORT_FdoStartCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + Status = IoCallDriver(FdoCommonExtension->LowerDevice, + Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + + Status = Irp->IoStatus.Status; + } + + if (!NT_SUCCESS(Status)) + { + goto Exit; + } + + Status = USBPORT_ParseResources(FdoDevice, + Irp, + UsbPortResources); + + if (!NT_SUCCESS(Status)) + { + FdoCommonExtension->PnpStateFlags |= USBPORT_PNP_STATE_STOPPED; + goto Exit; + } + + Status = USBPORT_StartDevice(FdoDevice, UsbPortResources); + + if (!NT_SUCCESS(Status)) + { + FdoCommonExtension->PnpStateFlags |= USBPORT_PNP_STATE_STOPPED; + goto Exit; + } + + FdoCommonExtension->PnpStateFlags &= ~USBPORT_PNP_STATE_NOT_INIT; + FdoCommonExtension->PnpStateFlags |= USBPORT_PNP_STATE_STARTED; + + FdoCommonExtension->DevicePowerState = PowerDeviceD0; + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + USBPORT_AddUSB2Fdo(FdoDevice); + } + else + { + USBPORT_AddUSB1Fdo(FdoDevice); + } + +Exit: + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + + case IRP_MN_QUERY_REMOVE_DEVICE: + DPRINT("IRP_MN_QUERY_REMOVE_DEVICE\n"); + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + DPRINT1("USBPORT_FdoPnP: Haction registry write FIXME\n"); + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_REMOVE_DEVICE: + DPRINT("USBPORT_FdoPnP: IRP_MN_REMOVE_DEVICE\n"); + FdoCommonExtension->PnpStateFlags |= USBPORT_PNP_STATE_FAILED; + + if (FdoCommonExtension->PnpStateFlags & USBPORT_PNP_STATE_STARTED && + !(FdoCommonExtension->PnpStateFlags & USBPORT_PNP_STATE_NOT_INIT)) + { + DPRINT1("USBPORT_FdoPnP: stop fdo FIXME\n"); + FdoCommonExtension->PnpStateFlags |= USBPORT_PNP_STATE_NOT_INIT; + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(FdoCommonExtension->LowerDevice, Irp); + + IoDetachDevice(FdoCommonExtension->LowerDevice); + + RootHubPdo = FdoExtension->RootHubPdo; + + IoDeleteDevice(FdoDevice); + + if (RootHubPdo) + { + IoDeleteDevice(RootHubPdo); + } + + return Status; + + case IRP_MN_CANCEL_REMOVE_DEVICE: + DPRINT("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_STOP_DEVICE: + DPRINT("IRP_MN_STOP_DEVICE\n"); + if (FdoCommonExtension->PnpStateFlags & USBPORT_PNP_STATE_STARTED) + { + DPRINT1("USBPORT_FdoPnP: stop fdo FIXME\n"); + + FdoCommonExtension->PnpStateFlags &= ~USBPORT_PNP_STATE_STARTED; + FdoCommonExtension->PnpStateFlags |= USBPORT_PNP_STATE_NOT_INIT; + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_QUERY_STOP_DEVICE: + DPRINT("IRP_MN_QUERY_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_CANCEL_STOP_DEVICE: + DPRINT("IRP_MN_CANCEL_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n"); + if (RelationType == BusRelations) + { + DeviceRelations = ExAllocatePoolWithTag(PagedPool, + sizeof(DEVICE_RELATIONS), + USB_PORT_TAG); + + if (!DeviceRelations) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + DeviceRelations->Count = 0; + DeviceRelations->Objects[0] = NULL; + + if (!FdoExtension->RootHubPdo) + { + Status = USBPORT_CreatePdo(FdoDevice, + &FdoExtension->RootHubPdo); + + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(DeviceRelations, USB_PORT_TAG); + goto ForwardIrp; + } + } + else + { + Status = STATUS_SUCCESS; + } + + DeviceRelations->Count = 1; + DeviceRelations->Objects[0] = FdoExtension->RootHubPdo; + + ObReferenceObject(FdoExtension->RootHubPdo); + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + } + else + { + if (RelationType == RemovalRelations) + { + DPRINT1("USBPORT_FdoPnP: FIXME IRP_MN_QUERY_DEVICE_RELATIONS/RemovalRelations\n"); + } + + goto ForwardIrp; + } + + Irp->IoStatus.Status = Status; + goto ForwardIrp; + + case IRP_MN_QUERY_INTERFACE: + DPRINT("IRP_MN_QUERY_INTERFACE\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_CAPABILITIES: + DPRINT("IRP_MN_QUERY_CAPABILITIES\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_RESOURCES: + DPRINT("IRP_MN_QUERY_RESOURCES\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_DEVICE_TEXT: + DPRINT("IRP_MN_QUERY_DEVICE_TEXT\n"); + goto ForwardIrp; + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: + DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + goto ForwardIrp; + + case IRP_MN_READ_CONFIG: + DPRINT("IRP_MN_READ_CONFIG\n"); + goto ForwardIrp; + + case IRP_MN_WRITE_CONFIG: + DPRINT("IRP_MN_WRITE_CONFIG\n"); + goto ForwardIrp; + + case IRP_MN_EJECT: + DPRINT("IRP_MN_EJECT\n"); + goto ForwardIrp; + + case IRP_MN_SET_LOCK: + DPRINT("IRP_MN_SET_LOCK\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_ID: + DPRINT("IRP_MN_QUERY_ID\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_PNP_DEVICE_STATE: + DPRINT("IRP_MN_QUERY_PNP_DEVICE_STATE\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_BUS_INFORMATION: + DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n"); + goto ForwardIrp; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + DPRINT("IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); + goto ForwardIrp; + + case IRP_MN_SURPRISE_REMOVAL: + DPRINT1("IRP_MN_SURPRISE_REMOVAL\n"); + if (!(FdoCommonExtension->PnpStateFlags & USBPORT_PNP_STATE_FAILED)) + { + USBPORT_InvalidateControllerHandler(FdoDevice, + INVALIDATE_CONTROLLER_SURPRISE_REMOVE); + } + goto ForwardIrp; + + default: + DPRINT("unknown IRP_MN_???\n"); +ForwardIrp: + /* forward irp to next device object */ + IoSkipCurrentIrpStackLocation(Irp); + break; + } + + return IoCallDriver(FdoCommonExtension->LowerDevice, Irp); +} + +PVOID +NTAPI +USBPORT_GetDeviceHwIds(IN PDEVICE_OBJECT FdoDevice, + IN USHORT VendorID, + IN USHORT DeviceID, + IN USHORT RevisionID) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PVOID Id; + WCHAR Buffer[300] = {0}; + ULONG Length = 0; + size_t Remaining = sizeof(Buffer); + PWCHAR EndBuffer; + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + DPRINT("USBPORT_GetDeviceHwIds: FdoDevice - %p, Packet->MiniPortFlags - %p\n", + FdoDevice, + Packet->MiniPortFlags); + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + RtlStringCbPrintfExW(Buffer, + Remaining, + &EndBuffer, + &Remaining, + 0, + L"USB\\ROOT_HUB20&VID%04x&PID%04x&REV%04x", + VendorID, + DeviceID, + RevisionID); + + EndBuffer++; + Remaining -= sizeof(UNICODE_NULL); + + RtlStringCbPrintfExW(EndBuffer, + Remaining, + &EndBuffer, + &Remaining, + 0, + L"USB\\ROOT_HUB20&VID%04x&PID%04x", + VendorID, + DeviceID); + + EndBuffer++; + Remaining -= sizeof(UNICODE_NULL); + + RtlStringCbPrintfExW(EndBuffer, + Remaining, + NULL, + &Remaining, + 0, + L"USB\\ROOT_HUB20"); + } + else + { + RtlStringCbPrintfExW(Buffer, + Remaining, + &EndBuffer, + &Remaining, + 0, + L"USB\\ROOT_HUB&VID%04x&PID%04x&REV%04x", + VendorID, + DeviceID, + RevisionID); + + EndBuffer++; + Remaining -= sizeof(UNICODE_NULL); + + RtlStringCbPrintfExW(EndBuffer, + Remaining, + &EndBuffer, + &Remaining, + 0, + L"USB\\ROOT_HUB&VID%04x&PID%04x", + VendorID, + DeviceID); + + EndBuffer++; + Remaining -= sizeof(UNICODE_NULL); + + RtlStringCbPrintfExW(EndBuffer, + Remaining, + NULL, + &Remaining, + 0, + L"USB\\ROOT_HUB"); + } + + Length = (sizeof(Buffer) - Remaining + sizeof(UNICODE_NULL)); + + /* for debug only */ + if (FALSE) + { + DPRINT("Hardware IDs:\n"); + USBPORT_DumpingIDs(Buffer); + } + + Id = ExAllocatePoolWithTag(PagedPool, Length, USB_PORT_TAG); + + if (!Id) + return NULL; + + RtlMoveMemory(Id, Buffer, Length); + + return Id; +} + +NTSTATUS +NTAPI +USBPORT_PdoPnP(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_COMMON_DEVICE_EXTENSION PdoCommonExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIO_STACK_LOCATION IoStack; + UCHAR Minor; + NTSTATUS Status; + PPNP_BUS_INFORMATION BusInformation; + PDEVICE_CAPABILITIES DeviceCapabilities; + + PdoExtension = PdoDevice->DeviceExtension; + PdoCommonExtension = &PdoExtension->CommonExtension; + + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Minor = IoStack->MinorFunction; + + Status = Irp->IoStatus.Status; + + DPRINT("USBPORT_PdoPnP: PdoDevice - %p, Minor - %x\n", PdoDevice, Minor); + + switch (Minor) + { + case IRP_MN_START_DEVICE: + DPRINT("IRP_MN_START_DEVICE\n"); + + Status = USBPORT_RootHubCreateDevice(FdoDevice, PdoDevice); + + if (NT_SUCCESS(Status)) + { + Status = USBPORT_RegisterDeviceInterface(PdoDevice, + PdoDevice, + &GUID_DEVINTERFACE_USB_HUB, + TRUE); + + if (NT_SUCCESS(Status)) + { + PdoCommonExtension->DevicePowerState = PowerDeviceD0; + PdoCommonExtension->PnpStateFlags = USBPORT_PNP_STATE_STARTED; + } + } + + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: + DPRINT("USBPORT_PdoPnP: IRP_MN_QUERY_REMOVE_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_REMOVE_DEVICE: + DPRINT1("USBPORT_PdoPnP: IRP_MN_REMOVE_DEVICE UNIMPLEMENTED. FIXME. \n"); + //USBPORT_StopRootHub(); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: + DPRINT("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_STOP_DEVICE: + DPRINT1("USBPORT_PdoPnP: IRP_MN_STOP_DEVICE UNIMPLEMENTED. FIXME. \n"); + //USBPORT_StopRootHub(); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_STOP_DEVICE: + DPRINT("IRP_MN_QUERY_STOP_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_CANCEL_STOP_DEVICE: + DPRINT("IRP_MN_CANCEL_STOP_DEVICE\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + { + PDEVICE_RELATIONS DeviceRelations; + + DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n"); + if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + { + break; + } + + DeviceRelations = ExAllocatePoolWithTag(PagedPool, + sizeof(DEVICE_RELATIONS), + USB_PORT_TAG); + + if (!DeviceRelations) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Information = 0; + break; + } + + DeviceRelations->Count = 1; + DeviceRelations->Objects[0] = PdoDevice; + + ObReferenceObject(PdoDevice); + + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + break; + } + + case IRP_MN_QUERY_INTERFACE: + DPRINT("IRP_MN_QUERY_INTERFACE\n"); + Status = USBPORT_PdoQueryInterface(FdoDevice, PdoDevice, Irp); + break; + + case IRP_MN_QUERY_CAPABILITIES: + DPRINT("IRP_MN_QUERY_CAPABILITIES\n"); + + DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities; + + RtlCopyMemory(DeviceCapabilities, + &PdoExtension->Capabilities, + sizeof(DEVICE_CAPABILITIES)); + + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_RESOURCES: + DPRINT("USBPORT_PdoPnP: IRP_MN_QUERY_RESOURCES\n"); + break; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + break; + + case IRP_MN_QUERY_DEVICE_TEXT: + DPRINT("IRP_MN_QUERY_DEVICE_TEXT\n"); + break; + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: + DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + break; + + case IRP_MN_READ_CONFIG: + DPRINT("IRP_MN_READ_CONFIG\n"); + ASSERT(FALSE); + break; + + case IRP_MN_WRITE_CONFIG: + DPRINT("IRP_MN_WRITE_CONFIG\n"); + ASSERT(FALSE); + break; + + case IRP_MN_EJECT: + DPRINT("IRP_MN_EJECT\n"); + ASSERT(FALSE); + break; + + case IRP_MN_SET_LOCK: + DPRINT("IRP_MN_SET_LOCK\n"); + ASSERT(FALSE); + break; + + case IRP_MN_QUERY_ID: + { + ULONG IdType; + LONG Length; + WCHAR Buffer[64] = {0}; + PVOID Id; + + Status = STATUS_SUCCESS; + IdType = IoStack->Parameters.QueryId.IdType; + + DPRINT("IRP_MN_QUERY_ID/Type %x\n", IdType); + + if (IdType == BusQueryDeviceID) + { + PUSBPORT_REGISTRATION_PACKET Packet; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + RtlStringCbPrintfW(Buffer, + sizeof(Buffer), + L"USB\\ROOT_HUB20"); + } + else + { + RtlStringCbPrintfW(Buffer, + sizeof(Buffer), + L"USB\\ROOT_HUB"); + } + + Length = (wcslen(Buffer) + 1); + + Id = ExAllocatePoolWithTag(PagedPool, + Length * sizeof(WCHAR), + USB_PORT_TAG); + + if (Id) + { + RtlZeroMemory(Id, Length * sizeof(WCHAR)); + RtlStringCbCopyW(Id, Length * sizeof(WCHAR), Buffer); + + DPRINT("BusQueryDeviceID - %S, TotalLength - %hu\n", + Id, + Length); + } + + Irp->IoStatus.Information = (ULONG_PTR)Id; + break; + } + + if (IdType == BusQueryHardwareIDs) + { + Id = USBPORT_GetDeviceHwIds(FdoDevice, + FdoExtension->VendorID, + FdoExtension->DeviceID, + FdoExtension->RevisionID); + + Irp->IoStatus.Information = (ULONG_PTR)Id; + break; + } + + if (IdType == BusQueryCompatibleIDs || + IdType == BusQueryInstanceID) + { + Irp->IoStatus.Information = 0; + break; + } + + /* IdType == BusQueryDeviceSerialNumber */ + Status = Irp->IoStatus.Status; + break; + } + + case IRP_MN_QUERY_PNP_DEVICE_STATE: + DPRINT("IRP_MN_QUERY_PNP_DEVICE_STATE\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_BUS_INFORMATION: + DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n"); + + /* Allocate buffer for bus information */ + BusInformation = ExAllocatePoolWithTag(PagedPool, + sizeof(PNP_BUS_INFORMATION), + USB_PORT_TAG); + + if (!BusInformation) + { + /* No memory */ + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + RtlZeroMemory(BusInformation, sizeof(PNP_BUS_INFORMATION)); + + /* Copy BUS GUID */ + RtlMoveMemory(&BusInformation->BusTypeGuid, + &GUID_BUS_TYPE_USB, + sizeof(GUID)); + + /* Set bus type */ + BusInformation->LegacyBusType = PNPBus; + BusInformation->BusNumber = 0; + + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = (ULONG_PTR)BusInformation; + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + DPRINT("IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); + break; + + case IRP_MN_SURPRISE_REMOVAL: + DPRINT("USBPORT_PdoPnP: IRP_MN_SURPRISE_REMOVAL\n"); + Status = STATUS_SUCCESS; + break; + + default: + DPRINT("unknown IRP_MN_???\n"); + break; + } + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} diff --git a/reactos/drivers/usb/usbport/power.c b/reactos/drivers/usb/usbport/power.c new file mode 100644 index 00000000000..2a8c4607cf9 --- /dev/null +++ b/reactos/drivers/usb/usbport/power.c @@ -0,0 +1,703 @@ +#include "usbport.h" + +#define NDEBUG +#include + +VOID +NTAPI +USBPORT_CompletePdoWaitWake(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PIRP Irp; + KIRQL OldIrql; + + DPRINT("USBPORT_CompletePdoWaitWake: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + PdoDevice = FdoExtension->RootHubPdo; + PdoExtension = PdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql); + + Irp = PdoExtension->WakeIrp; + + if (Irp && IoSetCancelRoutine(Irp, NULL)) + { + PdoExtension->WakeIrp = NULL; + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + + DPRINT("USBPORT_CompletePdoWaitWake: Complete Irp - %p\n", Irp); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return; + } + + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); +} + +VOID +NTAPI +USBPORT_HcWakeDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + DPRINT("USBPORT_HcWakeDpc: ... \n"); + USBPORT_CompletePdoWaitWake((PDEVICE_OBJECT)DeferredContext); +} + +VOID +NTAPI +USBPORT_HcQueueWakeDpc(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_HcQueueWakeDpc: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + KeInsertQueueDpc(&FdoExtension->HcWakeDpc, NULL, NULL); +} + +VOID +NTAPI +USBPORT_CompletePendingIdleIrp(IN PDEVICE_OBJECT PdoDevice) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIRP Irp; + + DPRINT("USBPORT_CompletePendingIdleIrp: ... \n"); + + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + Irp = IoCsqRemoveNextIrp(&FdoExtension->IdleIoCsq, 0); + + if (Irp) + { + InterlockedDecrement(&FdoExtension->IdleLockCounter); + + DPRINT("USBPORT_CompletePendingIdleIrp: Complete Irp - %p\n", Irp); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } +} + +VOID +NTAPI +USBPORT_DoSetPowerD0(IN PDEVICE_OBJECT FdoDevice) +{ + DPRINT("USBPORT_DoSetPowerD0: FIXME!\n"); + return; + DbgBreakPoint(); + //ASSERT(FALSE); +} + +VOID +NTAPI +USBPORT_SuspendController(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + + DPRINT1("USBPORT_SuspendController \n"); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + FdoExtension->TimerFlags |= USBPORT_TMFLAG_RH_SUSPENDED; + + USBPORT_FlushController(FdoDevice); + + if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND) + { + return; + } + + FdoExtension->TimerFlags |= USBPORT_TMFLAG_HC_SUSPENDED; + + if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) + { + FdoExtension->MiniPortFlags |= USBPORT_MPFLAG_SUSPENDED; + + USBPORT_Wait(FdoDevice, 10); + Packet->SuspendController(FdoExtension->MiniPortExt); + } + + FdoExtension->Flags |= USBPORT_FLAG_HC_SUSPEND; +} + +NTSTATUS +NTAPI +USBPORT_ResumeController(IN PDEVICE_OBJECT FdoDevice) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + KIRQL OldIrql; + MPSTATUS MpStatus; + + DPRINT1("USBPORT_ResumeController: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) + { + return Status; + } + + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql); + + FdoExtension->TimerFlags &= ~(USBPORT_TMFLAG_HC_SUSPENDED | + USBPORT_TMFLAG_RH_SUSPENDED); + + KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql); + + if (!(FdoExtension->MiniPortFlags & USBPORT_MPFLAG_SUSPENDED)) + { + FdoExtension->Flags &= ~USBPORT_FLAG_HC_SUSPEND; + return Status; + } + + FdoExtension->MiniPortFlags &= ~USBPORT_MPFLAG_SUSPENDED; + + if (!Packet->ResumeController(FdoExtension->MiniPortExt)) + { + Status = USBPORT_Wait(FdoDevice, 100); + + FdoExtension->Flags &= ~USBPORT_FLAG_HC_SUSPEND; + return Status; + } + + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql); + FdoExtension->TimerFlags |= (USBPORT_TMFLAG_HC_SUSPENDED | + USBPORT_TMFLAG_HC_RESUME); + KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql); + + USBPORT_MiniportInterrupts(FdoDevice, FALSE); + + Packet->StopController(FdoExtension->MiniPortExt, 1); + + USBPORT_NukeAllEndpoints(FdoDevice); + + RtlZeroMemory(FdoExtension->MiniPortExt, Packet->MiniPortExtensionSize); + + RtlZeroMemory(FdoExtension->UsbPortResources.StartVA, + Packet->MiniPortResourcesSize); + + FdoExtension->UsbPortResources.IsChirpHandled = TRUE; + + MpStatus = Packet->StartController(FdoExtension->MiniPortExt, + &FdoExtension->UsbPortResources); + + FdoExtension->UsbPortResources.IsChirpHandled = FALSE; + + if (!MpStatus) + { + USBPORT_MiniportInterrupts(FdoDevice, TRUE); + } + + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql); + + FdoExtension->TimerFlags &= ~(USBPORT_TMFLAG_HC_SUSPENDED | + USBPORT_TMFLAG_HC_RESUME | + USBPORT_TMFLAG_RH_SUSPENDED); + + KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql); + + Status = USBPORT_Wait(FdoDevice, 100); + + FdoExtension->Flags &= ~USBPORT_FLAG_HC_SUSPEND; + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_PdoDevicePowerState(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status = STATUS_SUCCESS; + POWER_STATE State; + + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + + State = IoStack->Parameters.Power.State; + + DPRINT1("USBPORT_PdoDevicePowerState: Irp - %p, State - %x\n", + Irp, + State.DeviceState); + + if (State.DeviceState == PowerDeviceD0) + { + if (FdoExtension->CommonExtension.DevicePowerState == PowerDeviceD0) + { + // FIXME FdoExtension->Flags + while (FdoExtension->SetPowerLockCounter) + { + USBPORT_Wait(FdoDevice, 10); + } + + USBPORT_ResumeController(FdoDevice); + + PdoExtension->CommonExtension.DevicePowerState = PowerDeviceD0; + + USBPORT_CompletePdoWaitWake(FdoDevice); + USBPORT_CompletePendingIdleIrp(PdoDevice); + } + else + { + DPRINT1("USBPORT_PdoDevicePowerState: FdoExtension->Flags - %lx\n", + FdoExtension->Flags); + + DbgBreakPoint(); + Status = STATUS_UNSUCCESSFUL; + } + } + else if (State.DeviceState == PowerDeviceD1 || + State.DeviceState == PowerDeviceD2 || + State.DeviceState == PowerDeviceD3) + { + FdoExtension->TimerFlags |= USBPORT_TMFLAG_WAKE; + USBPORT_SuspendController(FdoDevice); + PdoExtension->CommonExtension.DevicePowerState = State.DeviceState; + } + + return Status; +} + +VOID +NTAPI +USBPORT_CancelPendingWakeIrp(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + + DPRINT("USBPORT_CancelPendingWakeIrp: ... \n"); + + IoReleaseCancelSpinLock(Irp->CancelIrql); + PdoExtension = PdoDevice->DeviceExtension; + FdoExtension = PdoExtension->FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql); + + if (PdoExtension->WakeIrp == Irp) + { + PdoExtension->WakeIrp = NULL; + } + + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +NTSTATUS +NTAPI +USBPORT_PdoPower(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PIO_STACK_LOCATION IoStack; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + NTSTATUS Status; + KIRQL OldIrql; + + DPRINT("USBPORT_PdoPower: Irp - %p\n", Irp); + + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + + Status = Irp->IoStatus.Status; + + switch (IoStack->MinorFunction) + { + case IRP_MN_WAIT_WAKE: + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE\n"); + + if (!(FdoExtension->Flags & USBPORT_FLAG_HC_STARTED)) + { + /* The device does not support wake-up */ + Status = STATUS_NOT_SUPPORTED; + break; + } + + KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql); + + IoSetCancelRoutine(Irp, USBPORT_CancelPendingWakeIrp); + + /* Check if the IRP has been cancelled */ + if (Irp->Cancel) + { + if (IoSetCancelRoutine(Irp, NULL)) + { + /* IRP has been cancelled, release cancel spinlock */ + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - STATUS_CANCELLED\n"); + + /* IRP is cancelled */ + Status = STATUS_CANCELLED; + break; + } + } + + if (!PdoExtension->WakeIrp) + { + /* The driver received the IRP + and is waiting for the device to signal wake-up. */ + + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - No WakeIrp\n"); + + IoMarkIrpPending(Irp); + PdoExtension->WakeIrp = Irp; + + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + return STATUS_PENDING; + } + else + { + /* An IRP_MN_WAIT_WAKE request is already pending and must be + completed or canceled before another IRP_MN_WAIT_WAKE request + can be issued. */ + + if (IoSetCancelRoutine(Irp, NULL)) + { + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - STATUS_DEVICE_BUSY\n"); + + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + PoStartNextPowerIrp(Irp); + Status = STATUS_DEVICE_BUSY; + break; + } + else + { + ASSERT(FALSE); + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + return Status; + } + } + + case IRP_MN_POWER_SEQUENCE: + DPRINT("USBPORT_PdoPower: IRP_MN_POWER_SEQUENCE\n"); + PoStartNextPowerIrp(Irp); + break; + + case IRP_MN_SET_POWER: + DPRINT("USBPORT_PdoPower: IRP_MN_SET_POWER\n"); + + if (IoStack->Parameters.Power.Type == DevicePowerState) + { + DPRINT("USBPORT_PdoPower: IRP_MN_SET_POWER/DevicePowerState\n"); + Status = USBPORT_PdoDevicePowerState(PdoDevice, Irp); + PoStartNextPowerIrp(Irp); + break; + } + + DPRINT("USBPORT_PdoPower: IRP_MN_SET_POWER/SystemPowerState \n"); + + if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking) + { + FdoExtension->TimerFlags |= USBPORT_TMFLAG_WAKE; + } + else + { + FdoExtension->TimerFlags &= ~USBPORT_TMFLAG_WAKE; + } + + Status = STATUS_SUCCESS; + + PoStartNextPowerIrp(Irp); + break; + + case IRP_MN_QUERY_POWER: + DPRINT("USBPORT_PdoPower: IRP_MN_QUERY_POWER\n"); + Status = STATUS_SUCCESS; + PoStartNextPowerIrp(Irp); + break; + + default: + DPRINT1("USBPORT_PdoPower: unknown IRP_MN_POWER!\n"); + PoStartNextPowerIrp(Irp); + break; + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_HcWake(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + DPRINT1("USBPORT_HcWake: UNIMPLEMENTED. FIXME. \n"); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_DevicePowerState(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + DPRINT1("USBPORT_DevicePowerState: UNIMPLEMENTED. FIXME. \n"); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_SystemPowerState(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + DPRINT1("USBPORT_SystemPowerState: UNIMPLEMENTED. FIXME. \n"); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_FdoPower(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + + DPRINT("USBPORT_FdoPower: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + + switch (IoStack->MinorFunction) + { + case IRP_MN_WAIT_WAKE: + DPRINT("USBPORT_FdoPower: IRP_MN_WAIT_WAKE\n"); + Status = USBPORT_HcWake(FdoDevice, Irp); + return Status; + + case IRP_MN_POWER_SEQUENCE: + DPRINT("USBPORT_FdoPower: IRP_MN_POWER_SEQUENCE\n"); + break; + + case IRP_MN_SET_POWER: + DPRINT("USBPORT_FdoPower: IRP_MN_SET_POWER\n"); + if (IoStack->Parameters.Power.Type == DevicePowerState) + { + Status = USBPORT_DevicePowerState(FdoDevice, Irp); + } + else + { + Status = USBPORT_SystemPowerState(FdoDevice, Irp); + } + + if (Status != STATUS_PENDING) + break; + + return Status; + + case IRP_MN_QUERY_POWER: + DPRINT("USBPORT_FdoPower: IRP_MN_QUERY_POWER\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + default: + DPRINT1("USBPORT_FdoPower: unknown IRP_MN_POWER!\n"); + break; + } + + IoCopyCurrentIrpStackLocationToNext(Irp); + PoStartNextPowerIrp(Irp); + return PoCallDriver(FdoExtension->CommonExtension.LowerDevice, Irp); +} + +VOID +NTAPI +USBPORT_DoIdleNotificationCallback(IN PVOID Context) +{ + PIO_STACK_LOCATION IoStack; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PIRP NextIrp; + LARGE_INTEGER CurrentTime = {{0, 0}}; + PTIMER_WORK_QUEUE_ITEM IdleQueueItem; + PDEVICE_OBJECT PdoDevice; + PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo; + KIRQL OldIrql; + + DPRINT("USBPORT_DoIdleNotificationCallback \n"); + + IdleQueueItem = Context; + + FdoDevice = IdleQueueItem->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + PdoDevice = FdoExtension->RootHubPdo; + PdoExtension = PdoDevice->DeviceExtension; + + KeQuerySystemTime(&CurrentTime); + + if ((FdoExtension->IdleTime.QuadPart == 0) || + (((CurrentTime.QuadPart - FdoExtension->IdleTime.QuadPart) / 10000) >= 500)) + { + if (PdoExtension->CommonExtension.DevicePowerState == PowerDeviceD0 && + FdoExtension->CommonExtension.DevicePowerState == PowerDeviceD0) + { + NextIrp = IoCsqRemoveNextIrp(&FdoExtension->IdleIoCsq, NULL); + + if (NextIrp) + { + IoStack = IoGetCurrentIrpStackLocation(NextIrp); + IdleCallbackInfo = IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + if (IdleCallbackInfo && IdleCallbackInfo->IdleCallback) + { + IdleCallbackInfo->IdleCallback(IdleCallbackInfo->IdleContext); + } + + if (NextIrp->Cancel) + { + InterlockedDecrement(&FdoExtension->IdleLockCounter); + + NextIrp->IoStatus.Status = STATUS_CANCELLED; + NextIrp->IoStatus.Information = 0; + IoCompleteRequest(NextIrp, IO_NO_INCREMENT); + } + else + { + IoCsqInsertIrp(&FdoExtension->IdleIoCsq, NextIrp, NULL); + } + } + } + } + + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql); + FdoExtension->TimerFlags &= ~USBPORT_TMFLAG_IDLE_QUEUEITEM_ON; + KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql); + + ExFreePoolWithTag(IdleQueueItem, USB_PORT_TAG); +} + +NTSTATUS +NTAPI +USBPORT_IdleNotification(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + LONG LockCounter; + NTSTATUS Status = STATUS_PENDING; + + DPRINT("USBPORT_IdleNotification: Irp - %p\n", Irp); + + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + LockCounter = InterlockedIncrement(&FdoExtension->IdleLockCounter); + + if (LockCounter != 0) + { + if (Status != STATUS_PENDING) + { + InterlockedDecrement(&FdoExtension->IdleLockCounter); + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; + } + + Status = STATUS_DEVICE_BUSY; + } + + if (Status != STATUS_PENDING) + { + InterlockedDecrement(&FdoExtension->IdleLockCounter); + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; + } + + Irp->IoStatus.Status = STATUS_PENDING; + IoMarkIrpPending(Irp); + + KeQuerySystemTime(&FdoExtension->IdleTime); + + IoCsqInsertIrp(&FdoExtension->IdleIoCsq, Irp, 0); + + return Status; +} + +VOID +NTAPI +USBPORT_AdjustDeviceCapabilities(IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_CAPABILITIES Capabilities; + + DPRINT("USBPORT_AdjustDeviceCapabilities: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + PdoExtension = PdoDevice->DeviceExtension; + Capabilities = &PdoExtension->Capabilities; + + RtlCopyMemory(Capabilities, + &FdoExtension->Capabilities, + sizeof(DEVICE_CAPABILITIES)); + + Capabilities->DeviceD1 = FALSE; + Capabilities->DeviceD2 = TRUE; + + Capabilities->Removable = FALSE; + Capabilities->UniqueID = FALSE; + + Capabilities->WakeFromD0 = TRUE; + Capabilities->WakeFromD1 = FALSE; + Capabilities->WakeFromD2 = TRUE; + Capabilities->WakeFromD3 = FALSE; + + Capabilities->Address = 0; + Capabilities->UINumber = 0; + + if (Capabilities->SystemWake == PowerSystemUnspecified) + Capabilities->SystemWake = PowerSystemWorking; + + Capabilities->DeviceWake = PowerDeviceD2; + + Capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; + Capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; + Capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + Capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3; +} diff --git a/reactos/drivers/usb/usbport/queue.c b/reactos/drivers/usb/usbport/queue.c new file mode 100644 index 00000000000..3ef29a98b33 --- /dev/null +++ b/reactos/drivers/usb/usbport/queue.c @@ -0,0 +1,1389 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_CORE +#define NDEBUG_USBPORT_QUEUE +#define NDEBUG_USBPORT_URB +#include "usbdebug.h" + +VOID +NTAPI +USBPORT_InsertIdleIrp(IN PIO_CSQ Csq, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_InsertIdleIrp: Irp - %p\n", Irp); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + IdleIoCsq); + + InsertTailList(&FdoExtension->IdleIrpList, + &Irp->Tail.Overlay.ListEntry); +} + +VOID +NTAPI +USBPORT_RemoveIdleIrp(IN PIO_CSQ Csq, + IN PIRP Irp) +{ + DPRINT_QUEUE("USBPORT_RemoveIdleIrp: Irp - %p\n", Irp); + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + +PIRP +NTAPI +USBPORT_PeekNextIdleIrp(IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY NextEntry; + PLIST_ENTRY ListHead; + PIRP NextIrp = NULL; + + DPRINT_QUEUE("USBPORT_PeekNextIdleIrp: Irp - %p, PeekContext - %p\n", + Irp, + PeekContext); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + IdleIoCsq); + + ListHead = &FdoExtension->IdleIrpList; + + if (Irp) + { + NextEntry = Irp->Tail.Overlay.ListEntry.Flink; + } + else + { + NextEntry = ListHead->Flink; + } + + while (NextEntry != ListHead) + { + NextIrp = CONTAINING_RECORD(NextEntry, + IRP, + Tail.Overlay.ListEntry); + + if (!PeekContext) + break; + + NextEntry = NextEntry->Flink; + } + + return NextIrp; +} + +VOID +NTAPI +USBPORT_AcquireIdleLock(IN PIO_CSQ Csq, + IN PKIRQL Irql) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_AcquireIdleLock: ... \n"); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + IdleIoCsq); + + KeAcquireSpinLock(&FdoExtension->IdleIoCsqSpinLock, Irql); +} + +VOID +NTAPI +USBPORT_ReleaseIdleLock(IN PIO_CSQ Csq, + IN KIRQL Irql) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_ReleaseIdleLock: ... \n"); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + IdleIoCsq); + + KeReleaseSpinLock(&FdoExtension->IdleIoCsqSpinLock, Irql); +} + +VOID +NTAPI +USBPORT_CompleteCanceledIdleIrp(IN PIO_CSQ Csq, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_CompleteCanceledIdleIrp: ... \n"); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + IdleIoCsq); + + InterlockedDecrement(&FdoExtension->IdleLockCounter); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +VOID +NTAPI +USBPORT_InsertBadRequest(IN PIO_CSQ Csq, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_InsertBadRequest: Irp - %p\n", Irp); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + BadRequestIoCsq); + + InsertTailList(&FdoExtension->BadRequestList, + &Irp->Tail.Overlay.ListEntry); +} + +VOID +NTAPI +USBPORT_RemoveBadRequest(IN PIO_CSQ Csq, + IN PIRP Irp) +{ + DPRINT_QUEUE("USBPORT_RemoveBadRequest: Irp - %p\n", Irp); + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + +PIRP +NTAPI +USBPORT_PeekNextBadRequest(IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY NextEntry; + PLIST_ENTRY ListHead; + PIRP NextIrp = NULL; + + DPRINT_QUEUE("USBPORT_PeekNextBadRequest: Irp - %p, PeekContext - %p\n", + Irp, + PeekContext); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + BadRequestIoCsq); + + ListHead = &FdoExtension->BadRequestList; + + if (Irp) + { + NextEntry = Irp->Tail.Overlay.ListEntry.Flink; + } + else + { + NextEntry = ListHead->Flink; + } + + while (NextEntry != ListHead) + { + NextIrp = CONTAINING_RECORD(NextEntry, + IRP, + Tail.Overlay.ListEntry); + + if (!PeekContext) + break; + + NextEntry = NextEntry->Flink; + } + + return NextIrp; +} + +VOID +NTAPI +USBPORT_AcquireBadRequestLock(IN PIO_CSQ Csq, + IN PKIRQL Irql) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_AcquireBadRequestLock: ... \n"); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + BadRequestIoCsq); + + KeAcquireSpinLock(&FdoExtension->BadRequestIoCsqSpinLock, Irql); +} + +VOID +NTAPI +USBPORT_ReleaseBadRequestLock(IN PIO_CSQ Csq, + IN KIRQL Irql) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_ReleaseBadRequestLock: ... \n"); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + BadRequestIoCsq); + + KeReleaseSpinLock(&FdoExtension->BadRequestIoCsqSpinLock, Irql); +} + +VOID +NTAPI +USBPORT_CompleteCanceledBadRequest(IN PIO_CSQ Csq, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_QUEUE("USBPORT_CompleteCanceledBadRequest: Irp - %p\n", Irp); + + FdoExtension = CONTAINING_RECORD(Csq, + USBPORT_DEVICE_EXTENSION, + BadRequestIoCsq); + + InterlockedDecrement(&FdoExtension->BadRequestLockCounter); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +VOID +NTAPI +USBPORT_InsertIrpInTable(IN PUSBPORT_IRP_TABLE IrpTable, + IN PIRP Irp) +{ + ULONG ix; + + DPRINT_CORE("USBPORT_InsertIrpInTable: IrpTable - %p, Irp - %p\n", + IrpTable, + Irp); + + ASSERT(IrpTable != NULL); + + while (TRUE) + { + for (ix = 0; ix < 0x200; ix++) + { + if (IrpTable->irp[ix] == NULL) + { + IrpTable->irp[ix] = Irp; + + if (ix > 0) + { + DPRINT_CORE("USBPORT_InsertIrpInTable: ix - %x\n", ix); + } + + return; + } + } + + if (ix != 0x200) + { + KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0); + } + + IrpTable->LinkNextTable = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBPORT_IRP_TABLE), + USB_PORT_TAG); + + if (IrpTable->LinkNextTable == NULL) + { + KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0); + } + + RtlZeroMemory(IrpTable->LinkNextTable, sizeof(USBPORT_IRP_TABLE)); + + IrpTable = IrpTable->LinkNextTable; + } +} + +PIRP +NTAPI +USBPORT_RemoveIrpFromTable(IN PUSBPORT_IRP_TABLE IrpTable, + IN PIRP Irp) +{ + ULONG ix; + + DPRINT_CORE("USBPORT_RemoveIrpFromTable: IrpTable - %p, Irp - %p\n", + IrpTable, + Irp); + + ASSERT(IrpTable != NULL); + + while (TRUE) + { + for (ix = 0; ix < 0x200; ix++) + { + if (IrpTable->irp[ix] == Irp) + { + IrpTable->irp[ix] = NULL; + + if (ix > 0) + { + DPRINT_CORE("USBPORT_RemoveIrpFromTable: ix - %x\n", ix); + } + + return Irp; + } + } + + if (IrpTable->LinkNextTable == NULL) + break; + + IrpTable = IrpTable->LinkNextTable; + continue; + } + + DPRINT1("USBPORT_RemoveIrpFromTable: return NULL. ix - %x\n", ix); + return NULL; +} + +PIRP +NTAPI +USBPORT_RemoveActiveTransferIrp(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_RemoveActiveTransferIrp: Irp - %p\n", Irp); + FdoExtension = FdoDevice->DeviceExtension; + return USBPORT_RemoveIrpFromTable(FdoExtension->ActiveIrpTable, Irp); +} + +PIRP +NTAPI +USBPORT_RemovePendingTransferIrp(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_RemovePendingTransferIrp: Irp - %p\n", Irp); + FdoExtension = FdoDevice->DeviceExtension; + return USBPORT_RemoveIrpFromTable(FdoExtension->PendingIrpTable, Irp); +} + +VOID +NTAPI +USBPORT_FindUrbInIrpTable(IN PUSBPORT_IRP_TABLE IrpTable, + IN PURB Urb, + IN PIRP Irp) +{ + ULONG ix; + PIRP irp; + PURB urbIn; + + DPRINT_CORE("USBPORT_FindUrbInIrpTable: IrpTable - %p, Urb - %p, Irp - %p\n", + IrpTable, + Urb, + Irp); + + ASSERT(IrpTable != NULL); + + do + { + for (ix = 0; ix < 0x200; ix++) + { + irp = IrpTable->irp[ix]; + + if (irp) + { + urbIn = URB_FROM_IRP(irp); + + if (urbIn == Urb) + { + if (irp == Irp) + { + KeBugCheckEx(BUGCODE_USB_DRIVER, + 4, + (ULONG_PTR)irp, + (ULONG_PTR)urbIn, + 0); + } + + KeBugCheckEx(BUGCODE_USB_DRIVER, + 2, + (ULONG_PTR)irp, + (ULONG_PTR)Irp, + (ULONG_PTR)urbIn); + } + } + } + + IrpTable = IrpTable->LinkNextTable; + } + while (IrpTable); +} + +PIRP +NTAPI +USBPORT_FindIrpInTable(IN PUSBPORT_IRP_TABLE IrpTable, + IN PIRP Irp) +{ + ULONG ix; + PIRP irp; + + DPRINT_CORE("USBPORT_FindIrpInTable: IrpTable - %p, Irp - %p\n", + IrpTable, + Irp); + + ASSERT(IrpTable != NULL); + + do + { + for (ix = 0; ix < 0x200; ix++) + { + irp = IrpTable->irp[ix]; + + if (irp && irp == Irp) + { + return irp; + } + } + + IrpTable = IrpTable->LinkNextTable; + } + while (IrpTable->LinkNextTable); + + DPRINT_CORE("USBPORT_FindIrpInTable: Not found!!!\n"); + return NULL; +} + +PIRP +NTAPI +USBPORT_FindActiveTransferIrp(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_FindActiveTransferIrp: Irp - %p\n", Irp); + FdoExtension = FdoDevice->DeviceExtension; + return USBPORT_FindIrpInTable(FdoExtension->ActiveIrpTable, Irp); +} + +VOID +NTAPI +USBPORT_CancelPendingTransferIrp(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PURB Urb; + PUSBPORT_TRANSFER Transfer; + PUSBPORT_ENDPOINT Endpoint; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + PIRP irp; + + DPRINT_CORE("USBPORT_CancelPendingTransferIrp: DeviceObject - %p, Irp - %p\n", + DeviceObject, + Irp); + + Urb = URB_FROM_IRP(Irp); + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + Endpoint = Transfer->Endpoint; + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = DeviceObject->DeviceExtension; + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + KeAcquireSpinLock(&FdoExtension->FlushPendingTransferSpinLock, &OldIrql); + + irp = USBPORT_RemovePendingTransferIrp(FdoDevice, Irp); + + if (!irp) + { + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + OldIrql); + return; + } + + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + + RemoveEntryList(&Transfer->TransferLink); + + Transfer->TransferLink.Flink = NULL; + Transfer->TransferLink.Blink = NULL; + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, OldIrql); + + USBPORT_CompleteTransfer(Transfer->Urb, USBD_STATUS_CANCELED); +} + +VOID +NTAPI +USBPORT_CancelActiveTransferIrp(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PURB Urb; + PUSBPORT_TRANSFER Transfer; + PUSBPORT_ENDPOINT Endpoint; + PIRP irp; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_CancelTransferIrp: Irp - %p\n", Irp); + + PdoExtension = DeviceObject->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + + irp = USBPORT_FindActiveTransferIrp(FdoDevice, Irp); + + if (irp) + { + Urb = URB_FROM_IRP(irp); + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + Endpoint = Transfer->Endpoint; + + DPRINT_CORE("USBPORT_CancelTransferIrp: irp - %p, Urb - %p, Transfer - %p\n", + irp, + Urb, + Transfer); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + Transfer->Flags |= TRANSFER_FLAG_CANCELED; + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); + + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + return; + } + + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); +} + +VOID +NTAPI +USBPORT_FlushAbortList(IN PUSBPORT_ENDPOINT Endpoint) +{ + PLIST_ENTRY Entry; + PUSBPORT_TRANSFER Transfer; + PLIST_ENTRY AbortList; + LIST_ENTRY List; + NTSTATUS Status; + PIRP Irp; + PURB Urb; + PUSBPORT_DEVICE_HANDLE DeviceHandle = NULL; + + DPRINT_CORE("USBPORT_FlushAbortList: Endpoint - %p\n", Endpoint); + + InitializeListHead(&List); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (IsListEmpty(&Endpoint->AbortList)) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + return; + } + + Entry = Endpoint->PendingTransferList.Flink; + + while (Entry && Entry != &Endpoint->PendingTransferList) + { + Transfer = CONTAINING_RECORD(Entry, + USBPORT_TRANSFER, + TransferLink); + + if (Transfer->Flags & TRANSFER_FLAG_ABORTED) + { + DPRINT_CORE("USBPORT_FlushAbortList: Aborted PendingTransfer - %p\n", + Transfer); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + return; + } + + Entry = Transfer->TransferLink.Flink; + } + + Entry = Endpoint->TransferList.Flink; + + while (Entry && Entry != &Endpoint->TransferList) + { + Transfer = CONTAINING_RECORD(Entry, + USBPORT_TRANSFER, + TransferLink); + + if (Transfer->Flags & TRANSFER_FLAG_ABORTED) + { + DPRINT_CORE("USBPORT_FlushAbortList: Aborted ActiveTransfer - %p\n", + Transfer); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + return; + } + + Entry = Transfer->TransferLink.Flink; + } + + AbortList = &Endpoint->AbortList; + + while (!IsListEmpty(AbortList)) + { + //DbgBreakPoint(); + + Irp = CONTAINING_RECORD(AbortList->Flink, + IRP, + Tail.Overlay.ListEntry); + + RemoveHeadList(AbortList); + InsertTailList(&List, &Irp->Tail.Overlay.ListEntry); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + while (!IsListEmpty(&List)) + { + //DbgBreakPoint(); + + Irp = CONTAINING_RECORD(List.Flink, + IRP, + Tail.Overlay.ListEntry); + + RemoveHeadList(&List); + + Urb = URB_FROM_IRP(Irp); + + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + InterlockedDecrement(&DeviceHandle->DeviceHandleLock); + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); + + DPRINT_CORE("USBPORT_FlushAbortList: complete Irp - %p\n", Irp); + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } +} + +VOID +NTAPI +USBPORT_FlushCancelList(IN PUSBPORT_ENDPOINT Endpoint) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_TRANSFER Transfer; + PIRP Irp; + KIRQL OldIrql; + KIRQL PrevIrql; + + DPRINT_CORE("USBPORT_FlushCancelList: ... \n"); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + + while (!IsListEmpty(&Endpoint->CancelList)) + { + Transfer = CONTAINING_RECORD(Endpoint->CancelList.Flink, + USBPORT_TRANSFER, + TransferLink); + + RemoveHeadList(&Endpoint->CancelList); + + Irp = Transfer->Irp; + + if (Irp) + { + DPRINT("USBPORT_FlushCancelList: Irp - %p\n", Irp); + + IoAcquireCancelSpinLock(&PrevIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(PrevIrql); + + USBPORT_RemoveActiveTransferIrp(FdoDevice, Irp); + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); + + if (Endpoint->Flags & ENDPOINT_FLAG_NUKE) + { + USBPORT_CompleteTransfer(Transfer->Urb, USBD_STATUS_DEVICE_GONE); + } + else + { + if (Transfer->Flags & TRANSFER_FLAG_DEVICE_GONE) + { + USBPORT_CompleteTransfer(Transfer->Urb, + USBD_STATUS_DEVICE_GONE); + } + else + { + USBPORT_CompleteTransfer(Transfer->Urb, + USBD_STATUS_CANCELED); + } + } + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); + + USBPORT_FlushAbortList(Endpoint); +} + +VOID +NTAPI +USBPORT_FlushPendingTransfers(IN PUSBPORT_ENDPOINT Endpoint) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + BOOLEAN IsMapTransfer; + BOOLEAN IsEnd = FALSE; + PLIST_ENTRY List; + PUSBPORT_TRANSFER Transfer; + KIRQL PrevIrql; + PURB Urb; + PIRP Irp; + PIRP irp; + KIRQL OldIrql; + BOOLEAN Result; + + DPRINT_CORE("USBPORT_FlushPendingTransfers: Endpoint - %p\n", Endpoint); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + if (InterlockedCompareExchange(&Endpoint->FlushPendingLock, 1, 0)) + { + DPRINT_CORE("USBPORT_FlushPendingTransfers: Endpoint Locked \n"); + return; + } + + while (TRUE) + { + IsMapTransfer = 0; + + KeAcquireSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + &OldIrql); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + + if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND) + { + IsEnd = TRUE; + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + OldIrql); + goto Next; + } + + if (!(Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)) + { + if (!IsListEmpty(&Endpoint->TransferList)) + { + List = Endpoint->TransferList.Flink; + + while (List && List != &Endpoint->TransferList) + { + Transfer = CONTAINING_RECORD(List, + USBPORT_TRANSFER, + TransferLink); + + if (!(Transfer->Flags & TRANSFER_FLAG_SUBMITED)) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + OldIrql); + + IsEnd = TRUE; + goto Worker; + } + + List = Transfer->TransferLink.Flink; + } + } + } + + List = Endpoint->PendingTransferList.Flink; + + if (List == NULL || IsListEmpty(&Endpoint->PendingTransferList)) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + OldIrql); + + IsEnd = TRUE; + goto Worker; + } + + Transfer = CONTAINING_RECORD(List, + USBPORT_TRANSFER, + TransferLink); + + if (Transfer->Irp) + { + DPRINT_CORE("USBPORT_FlushPendingTransfers: Transfer->Irp->CancelRoutine - %p\n", + Transfer->Irp->CancelRoutine); + } + + if (Transfer->Irp && + (IoSetCancelRoutine(Transfer->Irp, NULL) == NULL)) + { + DPRINT_CORE("USBPORT_FlushPendingTransfers: Transfer->Irp - %p\n", + Transfer->Irp); + + Transfer = NULL; + IsEnd = TRUE; + } + + if (!Transfer) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + OldIrql); + + if (IsMapTransfer) + { + USBPORT_FlushMapTransfers(FdoDevice); + goto Next; + } + + goto Worker; + } + + Irp = Transfer->Irp; + Urb = Transfer->Urb; + + RemoveEntryList(&Transfer->TransferLink); + Transfer->TransferLink.Flink = NULL; + Transfer->TransferLink.Blink = NULL; + + irp = Irp; + + if (Irp) + { + irp = USBPORT_RemovePendingTransferIrp(FdoDevice, Irp); + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, + OldIrql); + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + + if (irp) + { + IoSetCancelRoutine(irp, USBPORT_CancelActiveTransferIrp); + + if (Irp->Cancel && IoSetCancelRoutine(irp, NULL)) + { + DPRINT_CORE("USBPORT_FlushPendingTransfers: irp - %p\n", irp); + + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, + OldIrql); + + USBPORT_CompleteTransfer(Transfer->Urb, USBD_STATUS_CANCELED); + goto Worker; + } + + USBPORT_FindUrbInIrpTable(FdoExtension->ActiveIrpTable, Urb, irp); + USBPORT_InsertIrpInTable(FdoExtension->ActiveIrpTable, irp); + } + + IsMapTransfer = USBPORT_QueueActiveUrbToEndpoint(Endpoint, Urb); + + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); + + if (IsMapTransfer) + { + USBPORT_FlushMapTransfers(FdoDevice); + goto Next; + } + +Worker: + KeRaiseIrql(DISPATCH_LEVEL, &PrevIrql); + Result = USBPORT_EndpointWorker(Endpoint, FALSE); + KeLowerIrql(PrevIrql); + + if (Result) + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + +Next: + if (IsEnd) + { + InterlockedDecrement(&Endpoint->FlushPendingLock); + DPRINT_CORE("USBPORT_FlushPendingTransfers: Endpoint Unlocked. Exit\n"); + return; + } + } +} + +VOID +NTAPI +USBPORT_QueuePendingUrbToEndpoint(IN PUSBPORT_ENDPOINT Endpoint, + IN PURB Urb) +{ + PUSBPORT_TRANSFER Transfer; + + DPRINT_CORE("USBPORT_QueuePendingUrbToEndpoint: Endpoint - %p, Urb - %p\n", + Endpoint, + Urb); + + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + //FIXME USBPORT_ResetEndpointIdle(); + InsertTailList(&Endpoint->PendingTransferList, &Transfer->TransferLink); + Urb->UrbHeader.Status = USBD_STATUS_PENDING; +} + +BOOLEAN +NTAPI +USBPORT_QueueActiveUrbToEndpoint(IN PUSBPORT_ENDPOINT Endpoint, + IN PURB Urb) +{ + PUSBPORT_TRANSFER Transfer; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_QueueActiveUrbToEndpoint: Endpoint - %p, Urb - %p\n", + Endpoint, + Urb); + + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, + &Endpoint->EndpointOldIrql); + + if ((Endpoint->Flags & ENDPOINT_FLAG_NUKE) || + (Transfer->Flags & TRANSFER_FLAG_ABORTED)) + { + InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + + //DPRINT_CORE("USBPORT_QueueActiveUrbToEndpoint: return FALSE\n"); + return FALSE; + } + + if (Transfer->TransferParameters.TransferBufferLength == 0 || + !(Endpoint->Flags & ENDPOINT_FLAG_DMA_TYPE)) + { + InsertTailList(&Endpoint->TransferList, &Transfer->TransferLink); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + + //DPRINT_CORE("USBPORT_QueueActiveUrbToEndpoint: return FALSE\n"); + return FALSE; + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + KeAcquireSpinLock(&FdoExtension->MapTransferSpinLock, &OldIrql); + + InsertTailList(&FdoExtension->MapTransferList, &Transfer->TransferLink); + + DeviceHandle = Transfer->Urb->UrbHeader.UsbdDeviceHandle; + InterlockedIncrement(&DeviceHandle->DeviceHandleLock); + + KeReleaseSpinLock(&FdoExtension->MapTransferSpinLock, OldIrql); + + //DPRINT_CORE("USBPORT_QueueActiveUrbToEndpoint: return TRUE\n"); + return TRUE; +} + +VOID +NTAPI +USBPORT_QueuePendingTransferIrp(IN PIRP Irp) +{ + PURB Urb; + PUSBPORT_TRANSFER Transfer; + PUSBPORT_ENDPOINT Endpoint; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_QueuePendingTransferIrp: Irp - %p\n", Irp); + + Urb = URB_FROM_IRP(Irp); + + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + Endpoint = Transfer->Endpoint; + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + Irp->IoStatus.Status = STATUS_PENDING; + IoMarkIrpPending(Irp); + + IoSetCancelRoutine(Irp, USBPORT_CancelPendingTransferIrp); + + if (Irp->Cancel && !IoSetCancelRoutine(Irp, NULL)) + { + USBPORT_CompleteTransfer(Urb, USBD_STATUS_CANCELED); + } + else + { + USBPORT_InsertIrpInTable(FdoExtension->PendingIrpTable, Irp); + USBPORT_QueuePendingUrbToEndpoint(Endpoint, Urb); + } +} + +VOID +NTAPI +USBPORT_QueueTransferUrb(IN PURB Urb) +{ + PUSBPORT_TRANSFER Transfer; + PUSBPORT_ENDPOINT Endpoint; + PIRP Irp; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + PUSBPORT_TRANSFER_PARAMETERS Parameters; + + DPRINT_CORE("USBPORT_QueueTransferUrb: Urb - %p\n", Urb); + + if (Urb->UrbControlTransfer.TransferFlags & USBD_DEFAULT_PIPE_TRANSFER) + Urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER; + + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + Parameters = &Transfer->TransferParameters; + + Endpoint = Transfer->Endpoint; + Endpoint->Flags &= ~ENDPOINT_FLAG_QUEUENE_EMPTY; + + Parameters->TransferBufferLength = Urb->UrbControlTransfer.TransferBufferLength; + Parameters->TransferFlags = Urb->UrbControlTransfer.TransferFlags; + + Transfer->TransferBufferMDL = Urb->UrbControlTransfer.TransferBufferMDL; + + if (Urb->UrbControlTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + Transfer->Direction = USBPORT_DMA_DIRECTION_FROM_DEVICE; + } + else + { + Transfer->Direction = USBPORT_DMA_DIRECTION_TO_DEVICE; + } + + if (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + RtlCopyMemory(&Parameters->SetupPacket, + Urb->UrbControlTransfer.SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + } + + DPRINT_URB("... URB TransferBufferLength - %x\n", + Urb->UrbControlTransfer.TransferBufferLength); + + Urb->UrbControlTransfer.TransferBufferLength = 0; + + Irp = Transfer->Irp; + + if (Irp) + { + USBPORT_QueuePendingTransferIrp(Irp); + } + else + { + USBPORT_QueuePendingUrbToEndpoint(Endpoint, Urb); + } + + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + InterlockedDecrement(&DeviceHandle->DeviceHandleLock); + + USBPORT_FlushPendingTransfers(Endpoint); + + DPRINT_URB("... URB TransferBufferLength - %x\n", + Urb->UrbControlTransfer.TransferBufferLength); + + if (Urb->UrbControlTransfer.TransferBufferLength) + { + PULONG Buffer; + ULONG BufferLength; + ULONG_PTR BufferEnd; + ULONG ix; + + Buffer = Urb->UrbControlTransfer.TransferBuffer; + BufferLength = Urb->UrbControlTransfer.TransferBufferLength; + BufferEnd = (ULONG_PTR)Buffer + BufferLength; + + DPRINT_URB("URB TransferBuffer - %p\n", Buffer); + + for (ix = 0; (ULONG_PTR)(Buffer + ix) < BufferEnd; ix++) + { + DPRINT_URB("Buffer[%02X] - %p\n", ix, Buffer[ix]); + } + } +} + +VOID +NTAPI +USBPORT_FlushAllEndpoints(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY Entry; + PUSBPORT_ENDPOINT Endpoint; + LIST_ENTRY List; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_FlushAllEndpoints: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + InitializeListHead(&List); + + Entry = FdoExtension->EndpointList.Flink; + + while (Entry && Entry != &FdoExtension->EndpointList) + { + Endpoint = CONTAINING_RECORD(Entry, + USBPORT_ENDPOINT, + EndpointLink); + + if (USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_CLOSED) + { + InsertTailList(&List, &Endpoint->FlushLink); + } + + Entry = Endpoint->EndpointLink.Flink; + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + while (!IsListEmpty(&List)) + { + Endpoint = CONTAINING_RECORD(List.Flink, + USBPORT_ENDPOINT, + FlushLink); + + RemoveHeadList(&List); + + Endpoint->FlushLink.Flink = NULL; + Endpoint->FlushLink.Blink = NULL; + + if (!IsListEmpty(&Endpoint->PendingTransferList)) + { + USBPORT_FlushPendingTransfers(Endpoint); + } + } + + DPRINT_CORE("USBPORT_FlushAllEndpoints: exit\n"); +} + +ULONG +NTAPI +USBPORT_KillEndpointActiveTransfers(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + PLIST_ENTRY ActiveList; + PUSBPORT_TRANSFER Transfer; + ULONG KilledTransfers = 0; + + DPRINT_CORE("USBPORT_KillEndpointActiveTransfers \n"); + + ActiveList = Endpoint->TransferList.Flink; + + while (ActiveList && ActiveList != &Endpoint->TransferList) + { + ++KilledTransfers; + + Transfer = CONTAINING_RECORD(ActiveList, + USBPORT_TRANSFER, + TransferLink); + + Transfer->Flags |= TRANSFER_FLAG_ABORTED; + + ActiveList = Transfer->TransferLink.Flink; + } + + USBPORT_FlushPendingTransfers(Endpoint); + USBPORT_FlushCancelList(Endpoint); + + return KilledTransfers; +} + +VOID +NTAPI +USBPORT_FlushController(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY Entry; + PUSBPORT_ENDPOINT Endpoint; + ULONG KilledTransfers = 0; + PLIST_ENTRY EndpointList; + KIRQL OldIrql; + LIST_ENTRY FlushList; + + DPRINT_CORE("USBPORT_FlushController \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + EndpointList = &FdoExtension->EndpointList; + + while (TRUE) + { + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + InitializeListHead(&FlushList); + + Entry = EndpointList->Flink; + + if (!IsListEmpty(EndpointList)) + { + while (Entry && Entry != EndpointList) + { + Endpoint = CONTAINING_RECORD(Entry, + USBPORT_ENDPOINT, + EndpointLink); + + if (Endpoint->StateLast != USBPORT_ENDPOINT_REMOVE && + Endpoint->StateLast != USBPORT_ENDPOINT_CLOSED) + { + InterlockedIncrement(&Endpoint->LockCounter); + InsertTailList(&FlushList, &Endpoint->FlushControllerLink); + } + + Entry = Endpoint->EndpointLink.Flink; + } + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + while (!IsListEmpty(&FlushList)) + { + Endpoint = CONTAINING_RECORD(FlushList.Flink, + USBPORT_ENDPOINT, + FlushControllerLink); + + RemoveHeadList(&FlushList); + + KilledTransfers += USBPORT_KillEndpointActiveTransfers(FdoDevice, + Endpoint); + + InterlockedDecrement(&Endpoint->LockCounter); + } + + if (!KilledTransfers) + break; + + USBPORT_Wait(FdoDevice, 100); + } +} + +VOID +NTAPI +USBPORT_BadRequestFlush(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIRP Irp; + + DPRINT_QUEUE("USBPORT_BadRequestFlush: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + while (TRUE) + { + Irp = IoCsqRemoveNextIrp(&FdoExtension->BadRequestIoCsq, 0); + + if (!Irp) + break; + + DPRINT1("USBPORT_BadRequestFlush: Irp - %p\n", Irp); + + Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } +} + +VOID +NTAPI +USBPORT_AbortEndpoint(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint, + IN PIRP Irp) +{ + PLIST_ENTRY PendingList; + PUSBPORT_TRANSFER PendingTransfer; + PLIST_ENTRY ActiveList; + PUSBPORT_TRANSFER ActiveTransfer; + + DPRINT_CORE("USBPORT_AbortEndpoint: Irp - %p\n", Irp); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (Irp) + { + InsertTailList(&Endpoint->AbortList, &Irp->Tail.Overlay.ListEntry); + } + + PendingList = Endpoint->PendingTransferList.Flink; + + while (PendingList && PendingList != &Endpoint->PendingTransferList) + { + PendingTransfer = CONTAINING_RECORD(PendingList, + USBPORT_TRANSFER, + TransferLink); + + DPRINT_CORE("USBPORT_AbortEndpoint: Abort PendingTransfer - %p\n", + PendingTransfer); + + PendingTransfer->Flags |= TRANSFER_FLAG_ABORTED; + + PendingList = PendingTransfer->TransferLink.Flink; + } + + ActiveList = Endpoint->TransferList.Flink; + + while (ActiveList && ActiveList != &Endpoint->TransferList) + { + ActiveTransfer = CONTAINING_RECORD(ActiveList, + USBPORT_TRANSFER, + TransferLink); + + DPRINT_CORE("USBPORT_AbortEndpoint: Abort ActiveTransfer - %p\n", + ActiveTransfer); + + ActiveTransfer->Flags |= TRANSFER_FLAG_ABORTED; + + if (Endpoint->Flags & ENDPOINT_FLAG_ABORTING) + { + ActiveTransfer->Flags |= TRANSFER_FLAG_DEVICE_GONE; + } + + ActiveList = ActiveTransfer->TransferLink.Flink; + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_INT_NEXT_SOF); + + USBPORT_FlushPendingTransfers(Endpoint); + USBPORT_FlushCancelList(Endpoint); +} \ No newline at end of file diff --git a/reactos/drivers/usb/usbport/roothub.c b/reactos/drivers/usb/usbport/roothub.c new file mode 100644 index 00000000000..5dd44f5f108 --- /dev/null +++ b/reactos/drivers/usb/usbport/roothub.c @@ -0,0 +1,1019 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_CORE +#include "usbdebug.h" + +RHSTATUS +NTAPI +USBPORT_MPStatusToRHStatus(IN MPSTATUS MPStatus) +{ + RHSTATUS RHStatus = RH_STATUS_SUCCESS; + + //DPRINT("USBPORT_MPStatusToRHStatus: MPStatus - %x\n", MPStatus); + + if (MPStatus) + { + RHStatus = (MPStatus != MP_STATUS_FAILURE); + ++RHStatus; + } + + return RHStatus; +} + +MPSTATUS +NTAPI +USBPORT_RH_SetFeatureUSB2PortPower(IN PDEVICE_OBJECT FdoDevice, + IN USHORT Port) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PDEVICE_RELATIONS CompanionControllersList; + PUSBPORT_REGISTRATION_PACKET CompanionPacket; + PDEVICE_OBJECT CompanionFdoDevice; + PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + USHORT ix; + PDEVICE_OBJECT * Entry; + ULONG NumController = 0; + + DPRINT("USBPORT_RootHub_PowerUsb2Port: FdoDevice - %p, Port - %p\n", + FdoDevice, + Port); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice, + FALSE, + TRUE); + + if (!CompanionControllersList) + { + Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port); + return MP_STATUS_SUCCESS; + } + + Entry = &CompanionControllersList->Objects[0]; + + while (NumController < CompanionControllersList->Count) + { + CompanionFdoDevice = *Entry; + + CompanionFdoExtension = CompanionFdoDevice->DeviceExtension; + CompanionPacket = &CompanionFdoExtension->MiniPortInterface->Packet; + + PdoExtension = CompanionFdoExtension->RootHubPdo->DeviceExtension; + + for (ix = 0; + (PdoExtension->CommonExtension.PnpStateFlags & USBPORT_PNP_STATE_STARTED) && + ix < PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts; + ++ix) + { + CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt, + ix + 1); + } + + ++NumController; + ++Entry; + } + + Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port); + + if (CompanionControllersList) + { + ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG); + } + + return MP_STATUS_SUCCESS; +} + +RHSTATUS +NTAPI +USBPORT_RootHubClassCommand(IN PDEVICE_OBJECT FdoDevice, + IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, + IN PVOID Buffer, + IN PULONG BufferLength) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + USHORT Port; + USHORT Feature; + MPSTATUS MPStatus; + RHSTATUS RHStatus = RH_STATUS_UNSUCCESSFUL; + KIRQL OldIrql; + + DPRINT("USBPORT_RootHubClassCommand: USB command - %x, *BufferLength - %x\n", + SetupPacket->bRequest, + *BufferLength); + + FdoExtension = FdoDevice->DeviceExtension; + PdoExtension = FdoExtension->RootHubPdo->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + Port = SetupPacket->wIndex.W; + + switch (SetupPacket->bRequest) + { + case USB_REQUEST_GET_STATUS: + { + if (!Buffer) + { + return RHStatus; + } + + *(PULONG)Buffer = 0; + + if (SetupPacket->bmRequestType.Recipient == BMREQUEST_TO_OTHER) + { + ASSERT(*BufferLength >= 4); + + if (Port > PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts || + Port <= 0 || + SetupPacket->wLength < 4) + { + return RHStatus; + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + MPStatus = Packet->RH_GetPortStatus(FdoExtension->MiniPortExt, + SetupPacket->wIndex.W, + Buffer); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + else + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + MPStatus = Packet->RH_GetHubStatus(FdoExtension->MiniPortExt, + Buffer); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + break; + } + + case USB_REQUEST_CLEAR_FEATURE: + Feature = SetupPacket->wValue.W; + + if ((SetupPacket->bmRequestType.Recipient) != USBPORT_RECIPIENT_ROOT_PORT) + { + if (Feature == FEATURE_C_HUB_LOCAL_POWER) + { + RHStatus = RH_STATUS_SUCCESS; + return RHStatus; + } + + if (Feature == FEATURE_C_HUB_OVER_CURRENT) + { + MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt, + 0); + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + return RHStatus; + } + + DbgBreakPoint(); + return RHStatus; + } + + switch (Feature) + { + case FEATURE_PORT_ENABLE: + MPStatus = Packet->RH_ClearFeaturePortEnable(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_SUSPEND: + MPStatus = Packet->RH_ClearFeaturePortSuspend(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_POWER: + MPStatus = Packet->RH_ClearFeaturePortPower(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_CONNECTION: + MPStatus = Packet->RH_ClearFeaturePortConnectChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_ENABLE: + MPStatus = Packet->RH_ClearFeaturePortEnableChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_SUSPEND: + MPStatus = Packet->RH_ClearFeaturePortSuspendChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_OVER_CURRENT: + MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_RESET: + MPStatus = Packet->RH_ClearFeaturePortResetChange(FdoExtension->MiniPortExt, + Port); + break; + + default: + DPRINT1("USBPORT_RootHubClassCommand: Not supported feature - %x\n", + Feature); + return RHStatus; + } + + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + break; + + case USB_REQUEST_SET_FEATURE: + if (SetupPacket->bmRequestType.Recipient != USBPORT_RECIPIENT_ROOT_PORT) + { + return RHStatus; + } + + Feature = SetupPacket->wValue.W; + + switch (Feature) + { + case FEATURE_PORT_ENABLE: + MPStatus = Packet->RH_SetFeaturePortEnable(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_SUSPEND: + MPStatus = Packet->RH_SetFeaturePortSuspend(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_RESET: + MPStatus = Packet->RH_SetFeaturePortReset(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_POWER: + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + MPStatus = USBPORT_RH_SetFeatureUSB2PortPower(FdoDevice, Port); + } + else + { + MPStatus = Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, + Port); + } + + break; + + default: + DPRINT1("USBPORT_RootHubClassCommand: Not supported feature - %x\n", + Feature); + return RHStatus; + } + + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + break; + + case USB_REQUEST_GET_DESCRIPTOR: + if (Buffer && + SetupPacket->wValue.W == 0 && + SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST) + { + SIZE_T DescriptorLength; + + DescriptorLength = PdoExtension->RootHubDescriptors->Descriptor.bDescriptorLength; + + if (*BufferLength < DescriptorLength) + DescriptorLength = *BufferLength; + + RtlCopyMemory(Buffer, + &PdoExtension->RootHubDescriptors->Descriptor, + DescriptorLength); + + *BufferLength = DescriptorLength; + RHStatus = RH_STATUS_SUCCESS; + } + + break; + + default: + DPRINT1("USBPORT_RootHubClassCommand: Not supported USB request - %x\n", + SetupPacket->bRequest); + //USB_REQUEST_SET_ADDRESS 0x05 + //USB_REQUEST_SET_DESCRIPTOR 0x07 + //USB_REQUEST_GET_CONFIGURATION 0x08 + //USB_REQUEST_SET_CONFIGURATION 0x09 + //USB_REQUEST_GET_INTERFACE 0x0A + //USB_REQUEST_SET_INTERFACE 0x0B + //USB_REQUEST_SYNC_FRAME 0x0C + break; + } + + return RHStatus; +} + +RHSTATUS +NTAPI +USBPORT_RootHubStandardCommand(IN PDEVICE_OBJECT FdoDevice, + IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, + IN PVOID Buffer, + IN OUT PULONG TransferLength) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + SIZE_T Length; + PVOID Descriptor; + SIZE_T DescriptorLength; + MPSTATUS MPStatus; + RHSTATUS RHStatus = RH_STATUS_UNSUCCESSFUL; + KIRQL OldIrql; + + DPRINT("USBPORT_RootHubStandardCommand: USB command - %x, TransferLength - %p\n", + SetupPacket->bRequest, + TransferLength); + + FdoExtension = FdoDevice->DeviceExtension; + PdoExtension = FdoExtension->RootHubPdo->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + switch (SetupPacket->bRequest) + { + case USB_REQUEST_GET_DESCRIPTOR: + if (SetupPacket->wValue.LowByte || + !(SetupPacket->bmRequestType.Dir)) + { + return RHStatus; + } + + switch (SetupPacket->wValue.HiByte) + { + case USB_DEVICE_DESCRIPTOR_TYPE: + Descriptor = &PdoExtension->RootHubDescriptors->DeviceDescriptor; + DescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR); + break; + + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + Descriptor = &PdoExtension->RootHubDescriptors->ConfigDescriptor; + DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR) + + sizeof(USB_INTERFACE_DESCRIPTOR) + + sizeof(USB_ENDPOINT_DESCRIPTOR); + break; + + default: + DPRINT1("USBPORT_RootHubStandardCommand: Not supported Descriptor Type - %x\n", + SetupPacket->wValue.HiByte); + return RHStatus; + } + + if (!Descriptor) + { + return RHStatus; + } + + if (*TransferLength >= DescriptorLength) + Length = DescriptorLength; + else + Length = *TransferLength; + + RtlCopyMemory(Buffer, Descriptor, Length); + *TransferLength = Length; + + RHStatus = RH_STATUS_SUCCESS; + break; + + case USB_REQUEST_GET_STATUS: + if (!SetupPacket->wValue.W && + SetupPacket->wLength == sizeof(USHORT) && + !SetupPacket->wIndex.W && + SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + MPStatus = Packet->RH_GetStatus(FdoExtension->MiniPortExt, + Buffer); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + *TransferLength = sizeof(USHORT); + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + } + + break; + + case USB_REQUEST_GET_CONFIGURATION: + if (SetupPacket->wValue.W || + SetupPacket->wIndex.W || + SetupPacket->wLength != 1 || + SetupPacket->bmRequestType.Dir == BMREQUEST_HOST_TO_DEVICE) + { + return RHStatus; + } + + Length = 0; + + if (*TransferLength >= 1) + { + Length = 1; + RtlCopyMemory(Buffer, &PdoExtension->ConfigurationValue, Length); + } + + *TransferLength = Length; + + RHStatus = RH_STATUS_SUCCESS; + break; + + case USB_REQUEST_SET_CONFIGURATION: + if (!SetupPacket->wIndex.W && + !SetupPacket->wLength && + !(SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST)) + { + if (SetupPacket->wValue.W == 0 || + SetupPacket->wValue.W == + PdoExtension->RootHubDescriptors->ConfigDescriptor.bConfigurationValue) + { + PdoExtension->ConfigurationValue = SetupPacket->wValue.LowByte; + RHStatus = RH_STATUS_SUCCESS; + } + } + + break; + + case USB_REQUEST_SET_ADDRESS: + if (!SetupPacket->wIndex.W && + !SetupPacket->wLength && + !(SetupPacket->bmRequestType.Dir)) + { + PdoExtension->DeviceHandle.DeviceAddress = SetupPacket->wValue.LowByte; + RHStatus = RH_STATUS_SUCCESS; + break; + } + + break; + + default: + DPRINT1("USBPORT_RootHubStandardCommand: Not supported USB request - %x\n", + SetupPacket->bRequest); + //USB_REQUEST_CLEAR_FEATURE 0x01 + //USB_REQUEST_SET_FEATURE 0x03 + //USB_REQUEST_SET_DESCRIPTOR 0x07 + //USB_REQUEST_GET_INTERFACE 0x0A + //USB_REQUEST_SET_INTERFACE 0x0B + //USB_REQUEST_SYNC_FRAME 0x0C + break; + } + + return RHStatus; +} + +RHSTATUS +NTAPI +USBPORT_RootHubEndpoint0(IN PUSBPORT_TRANSFER Transfer) +{ + PDEVICE_OBJECT FdoDevice; + SIZE_T TransferLength; + PVOID Buffer; + PURB Urb; + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + UCHAR Type; + RHSTATUS RHStatus; + + DPRINT("USBPORT_RootHubEndpoint0: Transfer - %p\n", Transfer); + + TransferLength = Transfer->TransferParameters.TransferBufferLength; + Urb = Transfer->Urb; + FdoDevice = Transfer->Endpoint->FdoDevice; + + if (TransferLength > 0) + Buffer = Urb->UrbControlTransfer.TransferBufferMDL->MappedSystemVa; + else + Buffer = NULL; + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET)Urb->UrbControlTransfer.SetupPacket; + + Type = SetupPacket->bmRequestType.Type; + + if (Type == BMREQUEST_STANDARD) + { + RHStatus = USBPORT_RootHubStandardCommand(FdoDevice, + SetupPacket, + Buffer, + &TransferLength); + } + else if (Type == BMREQUEST_CLASS) + { + RHStatus = USBPORT_RootHubClassCommand(FdoDevice, + SetupPacket, + Buffer, + &TransferLength); + } + else + { + return RH_STATUS_UNSUCCESSFUL; + } + + if (RHStatus == RH_STATUS_SUCCESS) + Transfer->CompletedTransferLen = TransferLength; + + return RHStatus; +} + +RHSTATUS +NTAPI +USBPORT_RootHubSCE(IN PUSBPORT_TRANSFER Transfer) +{ + PUSBPORT_ENDPOINT Endpoint; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + ULONG TransferLength; + USBHUB_PORT_STATUS PortStatus; + USB_HUB_STATUS HubStatus; + PVOID Buffer; + PULONG AddressBitMap; + ULONG Port; + PURB Urb; + RHSTATUS RHStatus = RH_STATUS_NO_CHANGES; + PUSB_HUB_DESCRIPTOR HubDescriptor; + UCHAR NumberOfPorts; + + DPRINT("USBPORT_RootHubSCE: Transfer - %p\n", Transfer); + + Endpoint = Transfer->Endpoint; + + FdoExtension = Endpoint->FdoDevice->DeviceExtension; + PdoExtension = FdoExtension->RootHubPdo->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + HubDescriptor = &PdoExtension->RootHubDescriptors->Descriptor; + NumberOfPorts = HubDescriptor->bNumberOfPorts; + + PortStatus.AsULONG = 0; + HubStatus.AsUshort16 = 0; + + Urb = Transfer->Urb; + TransferLength = Transfer->TransferParameters.TransferBufferLength; + + if (TransferLength) + { + Buffer = Urb->UrbControlTransfer.TransferBufferMDL->MappedSystemVa; + } + else + { + Buffer = NULL; + } + + /* Check parameters */ + + if (!Buffer) + { + /* Not valid parameter */ + DPRINT1("USBPORT_RootHubSCE: Error! Buffer is NULL\n"); + return RH_STATUS_UNSUCCESSFUL; + } + + if ((TransferLength < (NumberOfPorts / 8 + 1))) + { + /* Not valid parameters */ + DPRINT1("USBPORT_RootHubSCE: Error! TransferLength - %x, NumberOfPorts - %x\n", + TransferLength, + NumberOfPorts); + + return RH_STATUS_UNSUCCESSFUL; + } + + RtlZeroMemory(Buffer, TransferLength); + + AddressBitMap = Buffer; + + /* Scan all the ports for changes */ + for (Port = 1; Port <= NumberOfPorts; Port++) + { + DPRINT_CORE("USBPORT_RootHubSCE: Port - %p\n", Port); + + /* Request the port status from miniport */ + if (Packet->RH_GetPortStatus(FdoExtension->MiniPortExt, + Port, + &PortStatus)) + { + /* Miniport returned an error */ + DPRINT1("USBPORT_RootHubSCE: RH_GetPortStatus failed\n"); + return RH_STATUS_UNSUCCESSFUL; + } + + if (PortStatus.UsbPortStatusChange.ConnectStatusChange || + PortStatus.UsbPortStatusChange.PortEnableDisableChange || + PortStatus.UsbPortStatusChange.SuspendChange || + PortStatus.UsbPortStatusChange.OverCurrentIndicatorChange || + PortStatus.UsbPortStatusChange.ResetChange) + { + /* At the port status there is a change */ + AddressBitMap[Port >> 5] |= 1 << (Port & 0x1F); + RHStatus = RH_STATUS_SUCCESS; + } + } + + /* Request the hub status from miniport */ + if (!Packet->RH_GetHubStatus(FdoExtension->MiniPortExt, &HubStatus)) + { + if (HubStatus.AsUshort16 & (HUB_STATUS_CHANGE_LOCAL_POWER | + HUB_STATUS_CHANGE_OVERCURRENT)) + { + /* At the hub status there is a change */ + AddressBitMap[0] |= 1; + RHStatus = RH_STATUS_SUCCESS; + } + + if (RHStatus == RH_STATUS_SUCCESS) + { + /* Done */ + Urb->UrbControlTransfer.TransferBufferLength = TransferLength; + return RH_STATUS_SUCCESS; + } + + if (RHStatus == RH_STATUS_NO_CHANGES) + { + /* No changes. Enable IRQs for miniport root hub */ + Packet->RH_EnableIrq(FdoExtension->MiniPortExt); + } + + return RHStatus; + } + + /* Miniport returned an error */ + DPRINT1("USBPORT_RootHubSCE: RH_GetHubStatus failed\n"); + return RH_STATUS_UNSUCCESSFUL; +} + +VOID +NTAPI +USBPORT_RootHubEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PUSBPORT_TRANSFER Transfer; + RHSTATUS RHStatus; + USBD_STATUS USBDStatus; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_RootHubEndpointWorker: Endpoint - %p\n", Endpoint); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) + { + Packet->CheckController(FdoExtension->MiniPortExt); + } + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + Transfer = CONTAINING_RECORD(Endpoint->TransferList.Flink, + USBPORT_TRANSFER, + TransferLink); + + if (IsListEmpty(&Endpoint->TransferList) || + Endpoint->TransferList.Flink == NULL || + !Transfer) + { + if (Endpoint->StateLast == USBPORT_ENDPOINT_REMOVE) + { + ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList, + &Endpoint->CloseLink, + &FdoExtension->EndpointClosedSpinLock); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + USBPORT_FlushCancelList(Endpoint); + return; + } + + if (Transfer->Flags & (TRANSFER_FLAG_ABORTED | TRANSFER_FLAG_CANCELED)) + { + RemoveEntryList(&Transfer->TransferLink); + InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + USBPORT_FlushCancelList(Endpoint); + return; + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + if (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + RHStatus = USBPORT_RootHubEndpoint0(Transfer); + else + RHStatus = USBPORT_RootHubSCE(Transfer); + + if (RHStatus != RH_STATUS_NO_CHANGES) + { + if (RHStatus == RH_STATUS_SUCCESS) + USBDStatus = USBD_STATUS_SUCCESS; + else + USBDStatus = USBD_STATUS_STALL_PID; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + USBPORT_QueueDoneTransfer(Transfer, USBDStatus); + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + USBPORT_FlushCancelList(Endpoint); + return; + } + + USBPORT_FlushCancelList(Endpoint); +} + +NTSTATUS +NTAPI +USBPORT_RootHubCreateDevice(IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + USBPORT_ROOT_HUB_DATA RootHubData; + ULONG NumMaskByte; + ULONG DescriptorsLength; + PUSBPORT_RH_DESCRIPTORS Descriptors; + PUSB_DEVICE_DESCRIPTOR RH_DeviceDescriptor; + PUSB_CONFIGURATION_DESCRIPTOR RH_ConfigurationDescriptor; + PUSB_INTERFACE_DESCRIPTOR RH_InterfaceDescriptor; + PUSB_ENDPOINT_DESCRIPTOR RH_EndPointDescriptor; + PUSB_HUB_DESCRIPTOR RH_HubDescriptor; + ULONG ix; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + NTSTATUS Status; + + DPRINT("USBPORT_RootHubCreateDevice: FdoDevice - %p, PdoDevice - %p\n", + FdoDevice, + PdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + PdoExtension = PdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + DeviceHandle = &PdoExtension->DeviceHandle; + USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle); + + InitializeListHead(&DeviceHandle->PipeHandleList); + + DeviceHandle->IsRootHub = TRUE; + DeviceHandle->DeviceSpeed = UsbFullSpeed; + DeviceHandle->Flags = DEVICE_HANDLE_FLAG_ROOTHUB; + + RtlZeroMemory(&RootHubData, sizeof(RootHubData)); + + Packet->RH_GetRootHubData(FdoExtension->MiniPortExt, &RootHubData); + + ASSERT(RootHubData.NumberOfPorts != 0); + NumMaskByte = ((RootHubData.NumberOfPorts - 1) >> 3) + 1; + + DescriptorsLength = sizeof(USB_DEVICE_DESCRIPTOR) + + sizeof(USB_CONFIGURATION_DESCRIPTOR) + + sizeof(USB_INTERFACE_DESCRIPTOR) + + sizeof(USB_ENDPOINT_DESCRIPTOR) + + (sizeof(USB_HUB_DESCRIPTOR) + 2 * NumMaskByte); + + Descriptors = ExAllocatePoolWithTag(NonPagedPool, + DescriptorsLength, + USB_PORT_TAG); + + if (Descriptors) + { + RtlZeroMemory(Descriptors, DescriptorsLength); + + PdoExtension->RootHubDescriptors = Descriptors; + + RH_DeviceDescriptor = &PdoExtension->RootHubDescriptors->DeviceDescriptor; + + RH_DeviceDescriptor->bLength = sizeof(USB_DEVICE_DESCRIPTOR); + RH_DeviceDescriptor->bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; + RH_DeviceDescriptor->bcdUSB = 0x100; + RH_DeviceDescriptor->bDeviceClass = USB_DEVICE_CLASS_HUB; + RH_DeviceDescriptor->bDeviceSubClass = 0x01; + RH_DeviceDescriptor->bDeviceProtocol = 0x00; + RH_DeviceDescriptor->bMaxPacketSize0 = 0x08; + RH_DeviceDescriptor->idVendor = FdoExtension->VendorID; + RH_DeviceDescriptor->idProduct = FdoExtension->DeviceID; + RH_DeviceDescriptor->bcdDevice = FdoExtension->RevisionID; + RH_DeviceDescriptor->iManufacturer = 0x00; + RH_DeviceDescriptor->iProduct = 0x00; + RH_DeviceDescriptor->iSerialNumber = 0x00; + RH_DeviceDescriptor->bNumConfigurations = 0x01; + + RH_ConfigurationDescriptor = &PdoExtension->RootHubDescriptors->ConfigDescriptor; + + RH_ConfigurationDescriptor->bLength = sizeof(USB_CONFIGURATION_DESCRIPTOR); + RH_ConfigurationDescriptor->bDescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE; + + RH_ConfigurationDescriptor->wTotalLength = sizeof(USB_CONFIGURATION_DESCRIPTOR) + + sizeof(USB_INTERFACE_DESCRIPTOR) + + sizeof(USB_ENDPOINT_DESCRIPTOR); + + RH_ConfigurationDescriptor->bNumInterfaces = 0x01; + RH_ConfigurationDescriptor->bConfigurationValue = 0x01; + RH_ConfigurationDescriptor->iConfiguration = 0x00; + RH_ConfigurationDescriptor->bmAttributes = USB_CONFIG_SELF_POWERED; + RH_ConfigurationDescriptor->MaxPower = 0x00; + + RH_InterfaceDescriptor = &PdoExtension->RootHubDescriptors->InterfaceDescriptor; + + RH_InterfaceDescriptor->bLength = sizeof(USB_INTERFACE_DESCRIPTOR); + RH_InterfaceDescriptor->bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE; + RH_InterfaceDescriptor->bInterfaceNumber = 0x00; + RH_InterfaceDescriptor->bAlternateSetting = 0x00; + RH_InterfaceDescriptor->bNumEndpoints = 0x01; + RH_InterfaceDescriptor->bInterfaceClass = USB_DEVICE_CLASS_HUB; + RH_InterfaceDescriptor->bInterfaceSubClass = 0x01; + RH_InterfaceDescriptor->bInterfaceProtocol = 0x00; + RH_InterfaceDescriptor->iInterface = 0x00; + + RH_EndPointDescriptor = &PdoExtension->RootHubDescriptors->EndPointDescriptor; + + RH_EndPointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR); + RH_EndPointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE; + RH_EndPointDescriptor->bEndpointAddress = 0x81; + RH_EndPointDescriptor->bmAttributes = USB_ENDPOINT_TYPE_INTERRUPT; // SCE endpoint + RH_EndPointDescriptor->wMaxPacketSize = 0x0008; + RH_EndPointDescriptor->bInterval = 0x0C; // 12 msec + + RH_HubDescriptor = &PdoExtension->RootHubDescriptors->Descriptor; + + RH_HubDescriptor->bDescriptorLength = sizeof(USB_HUB_DESCRIPTOR) + 2 * NumMaskByte; + RH_HubDescriptor->bDescriptorType = 0x29; // USB_20_HUB_DESCRIPTOR_TYPE - need add in .h file + RH_HubDescriptor->bNumberOfPorts = RootHubData.NumberOfPorts; + RH_HubDescriptor->wHubCharacteristics = RootHubData.HubCharacteristics; + RH_HubDescriptor->bPowerOnToPowerGood = RootHubData.PowerOnToPowerGood; + RH_HubDescriptor->bHubControlCurrent = RootHubData.HubControlCurrent; + + for (ix = 0; ix < NumMaskByte; ix += 2) + { + RH_HubDescriptor->bRemoveAndPowerMask[ix] = 0; + RH_HubDescriptor->bRemoveAndPowerMask[ix + 1] = -1; + } + + EndpointDescriptor = &DeviceHandle->PipeHandle.EndpointDescriptor; + + EndpointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR); + EndpointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE; + EndpointDescriptor->bEndpointAddress = 0x00; + EndpointDescriptor->bmAttributes = USB_ENDPOINT_TYPE_CONTROL; + EndpointDescriptor->wMaxPacketSize = 0x0040; + EndpointDescriptor->bInterval = 0x00; + + Status = USBPORT_OpenPipe(FdoDevice, + DeviceHandle, + &DeviceHandle->PipeHandle, + NULL); + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + return Status; +} + +ULONG +NTAPI +USBPORT_InvalidateRootHub(PVOID Context) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_ENDPOINT Endpoint = NULL; + + DPRINT("USBPORT_InvalidateRootHub ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)Context - + sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoDevice = FdoExtension->CommonExtension.SelfDevice; + + if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND && + FdoExtension->Flags & USBPORT_FLAG_HC_WAKE_SUPPORT && + FdoExtension->MiniPortFlags & USBPORT_MPFLAG_SUSPENDED && + FdoExtension->TimerFlags & USBPORT_TMFLAG_WAKE) + { + USBPORT_HcQueueWakeDpc(FdoDevice); + return 0; + } + + FdoExtension->MiniPortInterface->Packet.RH_DisableIrq(FdoExtension->MiniPortExt); + + PdoDevice = FdoExtension->RootHubPdo; + + if (PdoDevice) + { + PdoExtension = PdoDevice->DeviceExtension; + Endpoint = PdoExtension->Endpoint; + + if (Endpoint) + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + PdoExtension->Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + } + } + + return 0; +} + +VOID +NTAPI +USBPORT_RootHubPowerAndChirpAllCcPorts(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + USBPORT_ROOT_HUB_DATA RootHubData; + ULONG Port; + PDEVICE_RELATIONS CompanionControllersList; + PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension; + PUSBPORT_REGISTRATION_PACKET CompanionPacket; + ULONG CompanionPorts; + ULONG NumController; + PDEVICE_OBJECT * Entry; + ULONG NumPorts; + + DPRINT("USBPORT_RootHub_PowerAndChirpAllCcPorts: FdoDevice - %p\n", + FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + + Packet = &FdoExtension->MiniPortInterface->Packet; + + RtlZeroMemory(&RootHubData, sizeof(RootHubData)); + + Packet->RH_GetRootHubData(FdoExtension->MiniPortExt, + &RootHubData); + + NumPorts = RootHubData.NumberOfPorts; + + for (Port = 1; Port <= NumPorts; ++Port) + { + Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port); + } + + USBPORT_Wait(FdoDevice, 10); + + CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice, + FALSE, + TRUE); + + if (CompanionControllersList) + { + Entry = &CompanionControllersList->Objects[0]; + + for (NumController = 0; + NumController < CompanionControllersList->Count; + NumController++) + { + CompanionPacket = &FdoExtension->MiniPortInterface->Packet; + + CompanionFdoExtension = (*Entry)->DeviceExtension; + + CompanionPacket->RH_GetRootHubData(CompanionFdoExtension->MiniPortExt, + &RootHubData); + + CompanionPorts = RootHubData.NumberOfPorts; + + for (Port = 1; Port <= CompanionPorts; ++Port) + { + CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt, + Port); + } + + ++Entry; + } + + ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG); + } + + USBPORT_Wait(FdoDevice, 100); + + for (Port = 1; Port <= NumPorts; ++Port) + { + if (FdoExtension->MiniPortInterface->Version < 200) + { + break; + } + + InterlockedIncrement((PLONG)&FdoExtension->ChirpRootPortLock); + Packet->RH_ChirpRootPort(FdoExtension->MiniPortExt, Port); + InterlockedDecrement((PLONG)&FdoExtension->ChirpRootPortLock); + } +} diff --git a/reactos/drivers/usb/usbport/urb.c b/reactos/drivers/usb/usbport/urb.c new file mode 100644 index 00000000000..5067f96b6c6 --- /dev/null +++ b/reactos/drivers/usb/usbport/urb.c @@ -0,0 +1,1061 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_URB +#include "usbdebug.h" + +NTSTATUS +NTAPI +USBPORT_HandleGetConfiguration(IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + + DPRINT_URB("USBPORT_HandleGetConfiguration: Urb - %p\n", Urb); + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET) + &Urb->UrbControlGetConfigurationRequest.Reserved1; + + SetupPacket->bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bRequest = USB_REQUEST_GET_CONFIGURATION; + SetupPacket->wValue.W = 0; + SetupPacket->wIndex.W = 0; + SetupPacket->wLength = Urb->UrbControlGetConfigurationRequest.TransferBufferLength; + + Urb->UrbControlGetConfigurationRequest.Reserved0 |= USBD_TRANSFER_DIRECTION_IN; // 1; + Urb->UrbControlGetConfigurationRequest.Reserved0 |= USBD_SHORT_TRANSFER_OK; // 2 + + USBPORT_DumpingSetupPacket(SetupPacket); + + USBPORT_QueueTransferUrb(Urb); + + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +USBPORT_HandleGetCurrentFrame(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + ULONG FrameNumber; + KIRQL OldIrql; + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + Urb->UrbGetCurrentFrameNumber.FrameNumber = FrameNumber; + + DPRINT_URB("USBPORT_HandleGetCurrentFrame: FrameNumber - %p\n", + FrameNumber); + + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); +} + +NTSTATUS +NTAPI +USBPORT_AbortPipe(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb) +{ + PUSBPORT_ENDPOINT Endpoint; + PUSBPORT_PIPE_HANDLE PipeHandle; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + NTSTATUS Status; + + DPRINT_URB("USBPORT_AbortPipe: ... \n"); + + PipeHandle = Urb->UrbPipeRequest.PipeHandle; + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + + if (USBPORT_ValidatePipeHandle(DeviceHandle, PipeHandle)) + { + if (!(PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE)) + { + Endpoint = PipeHandle->Endpoint; + + Status = STATUS_PENDING; + + Irp->IoStatus.Status = Status; + IoMarkIrpPending(Irp); + + USBPORT_AbortEndpoint(FdoDevice, Endpoint, Irp); + + return Status; + } + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PIPE_HANDLE); + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_ResetPipe(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PUSBPORT_PIPE_HANDLE PipeHandle; + PUSBPORT_ENDPOINT Endpoint; + NTSTATUS Status; + + DPRINT_URB("USBPORT_ResetPipe: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + PipeHandle = Urb->UrbPipeRequest.PipeHandle; + + if (!USBPORT_ValidatePipeHandle((PUSBPORT_DEVICE_HANDLE)Urb->UrbHeader.UsbdDeviceHandle, + PipeHandle)) + { + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_INVALID_PIPE_HANDLE); + } + + Endpoint = PipeHandle->Endpoint; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (IsListEmpty(&Endpoint->TransferList)) + { + if (Urb->UrbHeader.UsbdFlags & USBD_FLAG_NOT_ISO_TRANSFER) + { + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); + + Packet->SetEndpointDataToggle(FdoExtension->MiniPortExt, + Endpoint + 1, + 0); + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); + } + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_ERROR_BUSY); + } + + Endpoint->Flags |= ENDPOINT_FLAG_QUEUENE_EMPTY; + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); + + Packet->SetEndpointStatus(FdoExtension->MiniPortExt, + Endpoint + 1, + USBPORT_ENDPOINT_RUN); + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_ClearStall(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb) +{ + PUSBPORT_DEVICE_HANDLE DeviceHandle; + PUSBPORT_PIPE_HANDLE PipeHandle; + USBD_STATUS USBDStatus; + PUSBPORT_ENDPOINT Endpoint; + NTSTATUS Status; + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + + DPRINT_URB("USBPORT_ClearStall: ... \n"); + + PipeHandle = Urb->UrbPipeRequest.PipeHandle; + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + + if (!USBPORT_ValidatePipeHandle(DeviceHandle, PipeHandle)) + { + return USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PIPE_HANDLE); + } + + Endpoint = PipeHandle->Endpoint; + + RtlZeroMemory(&SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + SetupPacket.bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + SetupPacket.bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket.wValue.W = 0; + SetupPacket.wIndex.W = Endpoint->EndpointProperties.EndpointAddress; + SetupPacket.wLength = 0; + + USBPORT_SendSetupPacket(DeviceHandle, + FdoDevice, + &SetupPacket, + NULL, + 0, + NULL, + &USBDStatus); + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_SyncResetPipeAndClearStall(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb) +{ + PUSBPORT_DEVICE_HANDLE DeviceHandle; + PUSBPORT_PIPE_HANDLE PipeHandle; + PUSBPORT_ENDPOINT Endpoint; + ULONG EndpointState; + NTSTATUS Status; + + DPRINT_URB("USBPORT_SyncResetPipeAndClearStall: ... \n"); + + ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + ASSERT(Urb->UrbPipeRequest.PipeHandle); + + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + PipeHandle = Urb->UrbPipeRequest.PipeHandle; + + if (!USBPORT_ValidatePipeHandle(DeviceHandle, PipeHandle)) + { + return USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PIPE_HANDLE); + } + + if (PipeHandle->Flags & PIPE_HANDLE_FLAG_NULL_PACKET_SIZE) + { + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); + } + + Endpoint = PipeHandle->Endpoint; + InterlockedIncrement(&DeviceHandle->DeviceHandleLock); + + if (Endpoint->EndpointProperties.TransferType != USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + Urb->UrbHeader.UsbdFlags |= USBD_FLAG_NOT_ISO_TRANSFER; + Status = USBPORT_ClearStall(FdoDevice, Irp, Urb); + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); + } + + if (NT_SUCCESS(Status)) + { + Status = USBPORT_ResetPipe(FdoDevice, Irp, Urb); + + if (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + while (TRUE) + { + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, + &Endpoint->EndpointOldIrql); + + EndpointState = USBPORT_GetEndpointState(Endpoint); + + if (EndpointState == USBPORT_ENDPOINT_PAUSED && + IsListEmpty(&Endpoint->TransferList)) + { + USBPORT_SetEndpointState(Endpoint, + USBPORT_ENDPOINT_ACTIVE); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, + Endpoint->EndpointOldIrql); + + if (EndpointState == USBPORT_ENDPOINT_ACTIVE) + { + break; + } + + USBPORT_Wait(FdoDevice, 1); + } + } + } + + InterlockedDecrement(&DeviceHandle->DeviceHandleLock); + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_HandleSetOrClearFeature(IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + + DPRINT_URB("USBPORT_HandleSetOrClearFeature: Urb - %p\n", Urb); + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET) + &Urb->UrbControlFeatureRequest.Reserved0; + + SetupPacket->wLength = 0; + Urb->UrbControlFeatureRequest.Reserved3 = 0; // TransferBufferLength + + SetupPacket->bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_OTHER; + break; + + case URB_FUNCTION_SET_FEATURE_TO_OTHER: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_OTHER; + break; + } + + Urb->UrbControlFeatureRequest.Reserved2 &= ~USBD_TRANSFER_DIRECTION_IN; + Urb->UrbControlFeatureRequest.Reserved2 |= USBD_SHORT_TRANSFER_OK; + + USBPORT_DumpingSetupPacket(SetupPacket); + + USBPORT_QueueTransferUrb(Urb); + + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +USBPORT_HandleDataTransfers(IN PURB Urb) +{ + PUSBPORT_ENDPOINT Endpoint; + + DPRINT_URB("USBPORT_HandleDataTransfers: Urb - %p\n", Urb); + + Endpoint = ((PUSBPORT_PIPE_HANDLE) + (Urb->UrbBulkOrInterruptTransfer.PipeHandle))->Endpoint; + + if (Endpoint->EndpointProperties.TransferType != USBPORT_TRANSFER_TYPE_CONTROL) + { + if (Endpoint->EndpointProperties.Direction) + { + Urb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; + } + else + { + Urb->UrbBulkOrInterruptTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN; + } + } + + USBPORT_QueueTransferUrb(Urb); + + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +USBPORT_HandleGetStatus(IN PIRP Irp, + IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + NTSTATUS Status; + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET) + &Urb->UrbControlDescriptorRequest.Reserved1; + + SetupPacket->bmRequestType.B = 0; + SetupPacket->bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bRequest = USB_REQUEST_GET_STATUS; + SetupPacket->wLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; + SetupPacket->wValue.W = 0; + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_DEVICE\n"); + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_INTERFACE\n"); + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_ENDPOINT\n"); + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_GET_STATUS_FROM_OTHER: + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_OTHER\n"); + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_OTHER; + break; + } + + if (SetupPacket->wLength == 2) + { + Urb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; + + if (SetupPacket->bmRequestType.Dir) + Urb->UrbControlTransfer.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; + else + Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN; + + //USBPORT_DumpingSetupPacket(SetupPacket); + + USBPORT_QueueTransferUrb(Urb); + + Status = STATUS_PENDING; + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PARAMETER); + + DPRINT1("USBPORT_HandleGetStatus: Bad wLength\n"); + USBPORT_DumpingSetupPacket(SetupPacket); + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_HandleVendorOrClass(IN PIRP Irp, + IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + + /* + Specifies a value, from 4 to 31 inclusive, + that becomes part of the request type code in the USB-defined setup packet. + This value is defined by USB for a class request or the vendor for a vendor request. + */ + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET) + &Urb->UrbControlDescriptorRequest.Reserved1; + + SetupPacket->bmRequestType.Dir = USBD_TRANSFER_DIRECTION_FLAG + (Urb->UrbControlTransfer.TransferFlags); + + SetupPacket->wLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; + + Urb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_VENDOR_DEVICE: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_DEVICE\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_VENDOR_INTERFACE: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_INTERFACE\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_VENDOR_ENDPOINT: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_ENDPOINT\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLASS_DEVICE: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_DEVICE\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_CLASS_INTERFACE: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_INTERFACE\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_CLASS_ENDPOINT: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_ENDPOINT\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLASS_OTHER: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_OTHER\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_OTHER; + break; + + case URB_FUNCTION_VENDOR_OTHER: + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_OTHER\n"); + SetupPacket->bmRequestType.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_OTHER; + break; + } + + USBPORT_DumpingSetupPacket(SetupPacket); + + USBPORT_QueueTransferUrb(Urb); + + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +USBPORT_HandleGetSetDescriptor(IN PIRP Irp, + IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + + SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET) + &Urb->UrbControlDescriptorRequest.Reserved1; + + SetupPacket->wLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; + SetupPacket->bmRequestType.B = 0; // Clear bmRequestType + SetupPacket->bmRequestType.Type = BMREQUEST_STANDARD; + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR; + SetupPacket->bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_DESCRIPTOR; + SetupPacket->bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR; + SetupPacket->bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_SET_DESCRIPTOR; + SetupPacket->bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR; + SetupPacket->bmRequestType.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_DESCRIPTOR; + SetupPacket->bmRequestType.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket->bmRequestType.Recipient = BMREQUEST_TO_INTERFACE; + break; + } + + Urb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; + + if (SetupPacket->bmRequestType.Dir) + Urb->UrbControlTransfer.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; + else + Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN; + + USBPORT_DumpingSetupPacket(SetupPacket); + + USBPORT_QueueTransferUrb(Urb); + + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +USBPORT_ValidateTransferParametersURB(IN PURB Urb) +{ + struct _URB_CONTROL_TRANSFER *UrbRequest; + PMDL Mdl; + + DPRINT_URB("USBPORT_ValidateTransferParametersURB: Urb - %p\n", Urb); + + UrbRequest = &Urb->UrbControlTransfer; + + if (UrbRequest->TransferBuffer == NULL && + UrbRequest->TransferBufferMDL == NULL && + UrbRequest->TransferBufferLength > 0) + { + DPRINT1("USBPORT_ValidateTransferParametersURB: Not valid parameter\n"); + USBPORT_DumpingURB(Urb); + return STATUS_INVALID_PARAMETER; + } + + if ((UrbRequest->TransferBuffer != NULL) && + (UrbRequest->TransferBufferMDL != NULL) && + UrbRequest->TransferBufferLength == 0) + { + DPRINT1("USBPORT_ValidateTransferParametersURB: Not valid parameter\n"); + USBPORT_DumpingURB(Urb); + return STATUS_INVALID_PARAMETER; + } + + if (UrbRequest->TransferBuffer != NULL && + UrbRequest->TransferBufferMDL == NULL && + UrbRequest->TransferBufferLength != 0) + { + DPRINT_URB("USBPORT_ValidateTransferParametersURB: TransferBuffer - %p, TransferBufferLength - %x\n", + UrbRequest->TransferBuffer, + UrbRequest->TransferBufferLength); + + Mdl = IoAllocateMdl(UrbRequest->TransferBuffer, + UrbRequest->TransferBufferLength, + FALSE, + FALSE, + NULL); + + if (!Mdl) + { + DPRINT1("USBPORT_ValidateTransferParametersURB: Not allocated Mdl\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + MmBuildMdlForNonPagedPool(Mdl); + + UrbRequest->TransferBufferMDL = Mdl; + Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_MDL; + + DPRINT_URB("USBPORT_ValidateTransferParametersURB: Mdl - %p\n", Mdl); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +USBPORT_ValidateURB(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb, + IN BOOLEAN IsControlTransfer, + IN BOOLEAN IsNullTransfer) +{ + struct _URB_CONTROL_TRANSFER *UrbRequest; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + NTSTATUS Status; + USBD_STATUS USBDStatus; + + UrbRequest = &Urb->UrbControlTransfer; + + if (UrbRequest->UrbLink) + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PARAMETER); + + DPRINT1("USBPORT_ValidateURB: Not valid parameter\n"); + + USBPORT_DumpingURB(Urb); + return Status; + } + + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + + if (IsControlTransfer) + { + UrbRequest->TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER; + UrbRequest->PipeHandle = &DeviceHandle->PipeHandle; + } + + if (UrbRequest->TransferFlags & USBD_DEFAULT_PIPE_TRANSFER) + { + if (UrbRequest->TransferBufferLength > 0x1000) + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PARAMETER); + + DPRINT1("USBPORT_ValidateURB: Not valid parameter\n"); + + USBPORT_DumpingURB(Urb); + return Status; + } + + if (Urb->UrbHeader.Function == URB_FUNCTION_CONTROL_TRANSFER) + { + UrbRequest->PipeHandle = &DeviceHandle->PipeHandle; + } + } + + if (!USBPORT_ValidatePipeHandle(DeviceHandle, UrbRequest->PipeHandle)) + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_PIPE_HANDLE); + + DPRINT1("USBPORT_ValidateURB: Not valid pipe handle\n"); + + USBPORT_DumpingURB(Urb); + return Status; + } + + UrbRequest->hca.Reserved8[0] = NULL; // Transfer + + if (IsNullTransfer) + { + UrbRequest->TransferBuffer = 0; + UrbRequest->TransferBufferMDL = NULL; + UrbRequest->TransferBufferLength = 0; + } + else + { + Status = USBPORT_ValidateTransferParametersURB(Urb); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + + USBDStatus = USBPORT_AllocateTransfer(FdoDevice, + Urb, + DeviceHandle, + Irp, + NULL); + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_ValidateURB: Not allocated transfer\n"); + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_HandleSubmitURB(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp, + IN PURB Urb) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + USHORT Function; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + NTSTATUS Status = STATUS_NOT_IMPLEMENTED; + + ASSERT(Urb); + + PdoExtension = PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + Urb->UrbHeader.Status = USBD_STATUS_SUCCESS; + Urb->UrbHeader.UsbdFlags = 0; + + Function = Urb->UrbHeader.Function; + + if (Function > URB_FUNCTION_MAX) + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_URB_FUNCTION); + + DPRINT1("USBPORT_HandleSubmitURB: Unknown URB function - %x !!!\n", + Function); + + return Status; + } + + if (FdoExtension->TimerFlags & USBPORT_TMFLAG_RH_SUSPENDED) + { + DPRINT1("USBPORT_HandleSubmitURB: Bad Request\n"); + + USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_DEVICE_GONE); + + Irp->IoStatus.Status = STATUS_PENDING; + IoMarkIrpPending(Irp); + IoCsqInsertIrp(&FdoExtension->BadRequestIoCsq, Irp, NULL); + + return STATUS_PENDING; + } + + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + + if (!DeviceHandle) + { + DeviceHandle = &PdoExtension->DeviceHandle; + Urb->UrbHeader.UsbdDeviceHandle = DeviceHandle; + } + + if (!USBPORT_ValidateDeviceHandle(PdoExtension->FdoDevice, + DeviceHandle)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid device handle\n"); + + Irp->IoStatus.Status = STATUS_PENDING; + IoMarkIrpPending(Irp); + IoCsqInsertIrp(&FdoExtension->BadRequestIoCsq, Irp, NULL); + + return STATUS_PENDING; + } + + InterlockedIncrement(&DeviceHandle->DeviceHandleLock); + + DPRINT_URB("USBPORT_HandleSubmitURB: Function - 0x%02X, DeviceHandle - %p\n", + Function, + Urb->UrbHeader.UsbdDeviceHandle); + + switch (Function) + { + case URB_FUNCTION_ISOCH_TRANSFER: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_ISOCH_TRANSFER UNIMPLEMENTED. FIXME. \n"); + break; + + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: + case URB_FUNCTION_CONTROL_TRANSFER: + Status = USBPORT_ValidateURB(FdoDevice, Irp, Urb, FALSE, FALSE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid URB\n"); + break; + } + + Status = USBPORT_HandleDataTransfers(Urb); + break; + + case URB_FUNCTION_VENDOR_DEVICE: + case URB_FUNCTION_VENDOR_INTERFACE: + case URB_FUNCTION_VENDOR_ENDPOINT: + case URB_FUNCTION_CLASS_DEVICE: + case URB_FUNCTION_CLASS_INTERFACE: + case URB_FUNCTION_CLASS_ENDPOINT: + case URB_FUNCTION_CLASS_OTHER: + case URB_FUNCTION_VENDOR_OTHER: + Status = USBPORT_ValidateURB(FdoDevice, Irp, Urb, TRUE, FALSE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid URB\n"); + break; + } + + Status = USBPORT_HandleVendorOrClass(Irp, Urb); + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: + case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: + Status = USBPORT_ValidateURB(FdoDevice, Irp, Urb, TRUE, FALSE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid URB\n"); + break; + } + + Status = USBPORT_HandleGetSetDescriptor(Irp, Urb); + break; + + case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR (0x2A) NOT_SUPPORTED\n"); + return USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_URB_FUNCTION); + + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + case URB_FUNCTION_GET_STATUS_FROM_OTHER: + Status = USBPORT_ValidateURB(FdoDevice, Irp, Urb, TRUE, FALSE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid URB\n"); + break; + } + + Status = USBPORT_HandleGetStatus(Irp, Urb); + break; + + case URB_FUNCTION_SELECT_CONFIGURATION: + Status = USBPORT_HandleSelectConfiguration(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SELECT_INTERFACE: + Status = USBPORT_HandleSelectInterface(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_GET_CONFIGURATION: + Status = USBPORT_ValidateURB(FdoDevice, Irp, Urb, TRUE, FALSE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid URB\n"); + break; + } + + Status = USBPORT_HandleGetConfiguration(Urb); + break; + + case URB_FUNCTION_GET_INTERFACE: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_GET_INTERFACE (0x27) NOT_SUPPORTED\n"); + return USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_URB_FUNCTION); + + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + Status = USBPORT_SyncResetPipeAndClearStall(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SYNC_RESET_PIPE: + Status = USBPORT_ResetPipe(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SYNC_CLEAR_STALL: + Status = USBPORT_ClearStall(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_ABORT_PIPE: + Status = USBPORT_AbortPipe(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: + case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: + case URB_FUNCTION_SET_FEATURE_TO_OTHER: + Status = USBPORT_ValidateURB(FdoDevice, Irp, Urb, TRUE, TRUE); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_HandleSubmitURB: Not valid URB\n"); + break; + } + + Status = USBPORT_HandleSetOrClearFeature(Urb); + break; + + case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER: + Status = USBPORT_HandleGetCurrentFrame(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL (0x03) NOT_SUPPORTED\n"); + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_NOT_SUPPORTED); + + case URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL (0x04) NOT_SUPPORTED\n"); + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_NOT_SUPPORTED); + + case URB_FUNCTION_GET_FRAME_LENGTH: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_GET_FRAME_LENGTH (0x05) NOT_SUPPORTED\n"); + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_NOT_SUPPORTED); + + case URB_FUNCTION_SET_FRAME_LENGTH: + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_SET_FRAME_LENGTH (0x06) NOT_SUPPORTED\n"); + return USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_NOT_SUPPORTED); + + default: + DPRINT1("USBPORT_HandleSubmitURB: Unknown URB Function - %x\n", + Function); + //URB_FUNCTION_RESERVED_0X0016 + //URB_FUNCTION_RESERVE_0X001D + //URB_FUNCTION_RESERVE_0X002B + //URB_FUNCTION_RESERVE_0X002C + //URB_FUNCTION_RESERVE_0X002D + //URB_FUNCTION_RESERVE_0X002E + //URB_FUNCTION_RESERVE_0X002F + break; + } + + if (Status == STATUS_PENDING) + { + return Status; + } + + if (Urb->UrbHeader.UsbdFlags & USBD_FLAG_ALLOCATED_TRANSFER) + { + PUSBPORT_TRANSFER Transfer; + + Transfer = Urb->UrbControlTransfer.hca.Reserved8[0]; + Urb->UrbControlTransfer.hca.Reserved8[0] = NULL; + Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_TRANSFER; + ExFreePoolWithTag(Transfer, USB_PORT_TAG); + } + + if (DeviceHandle) + { + InterlockedDecrement(&DeviceHandle->DeviceHandleLock); + } + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; +} diff --git a/reactos/drivers/usb/usbport/usb2.c b/reactos/drivers/usb/usbport/usb2.c new file mode 100644 index 00000000000..4bcff0a1c38 --- /dev/null +++ b/reactos/drivers/usb/usbport/usb2.c @@ -0,0 +1,21 @@ +#include "usbport.h" + +//#define NDEBUG +#include + +BOOLEAN +NTAPI +USBPORT_AllocateBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + DPRINT1("USBPORT_AllocateBandwidthUSB2: UNIMPLEMENTED. FIXME. \n"); + return TRUE; +} + +VOID +NTAPI +USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint) +{ + DPRINT1("USBPORT_FreeBandwidthUSB2: UNIMPLEMENTED. FIXME. \n"); +} diff --git a/reactos/drivers/usb/usbport/usbdebug.h b/reactos/drivers/usb/usbport/usbdebug.h new file mode 100644 index 00000000000..ebeb2e27fc6 --- /dev/null +++ b/reactos/drivers/usb/usbport/usbdebug.h @@ -0,0 +1,128 @@ +#ifndef USBDEBUG_H__ +#define USBDEBUG_H__ + +#if DBG + + #ifndef NDEBUG_USBPORT_MINIPORT + + #define DPRINT_MINIPORT(fmt, ...) do { \ + if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + + #else + +#if defined(_MSC_VER) + #define DPRINT_MINIPORT __noop +#else + #define DPRINT_MINIPORT(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif + + #endif + + #ifndef NDEBUG_USBPORT_CORE + + #define DPRINT_CORE(fmt, ...) do { \ + if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + + #else + +#if defined(_MSC_VER) + #define DPRINT_CORE __noop +#else + #define DPRINT_CORE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif + + #endif + + #ifndef NDEBUG_USBPORT_URB + + #define DPRINT_URB(fmt, ...) do { \ + if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + + #else + +#if defined(_MSC_VER) + #define DPRINT_URB __noop +#else + #define DPRINT_URB(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif + + #endif + + #ifndef NDEBUG_USBPORT_INTERRUPT + + #define DPRINT_INT(fmt, ...) do { \ + if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + + #else + +#if defined(_MSC_VER) + #define DPRINT_INT __noop +#else + #define DPRINT_INT(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif + + #endif + + #ifndef NDEBUG_USBPORT_TIMER + + #define DPRINT_TIMER(fmt, ...) do { \ + if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + + #else + +#if defined(_MSC_VER) + #define DPRINT_TIMER __noop +#else + #define DPRINT_TIMER(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif + + #endif + + #ifndef NDEBUG_USBPORT_QUEUE + + #define DPRINT_QUEUE(fmt, ...) do { \ + if (DbgPrint("(%s:%d) " fmt, __RELFILE__, __LINE__, ##__VA_ARGS__)) \ + DbgPrint("(%s:%d) DbgPrint() failed!\n", __RELFILE__, __LINE__); \ + } while (0) + + #else + +#if defined(_MSC_VER) + #define DPRINT_QUEUE __noop +#else + #define DPRINT_QUEUE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif + + #endif + +#else /* not DBG */ + +#if defined(_MSC_VER) + #define DPRINT_MINIPORT __noop + #define DPRINT_CORE __noop + #define DPRINT_URB __noop + #define DPRINT_INT __noop + #define DPRINT_TIMER __noop + #define DPRINT_QUEUE __noop +#else + #define DPRINT_MINIPORT(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #define DPRINT_CORE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #define DPRINT_URB(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #define DPRINT_INT(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #define DPRINT_TIMER(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #define DPRINT_QUEUE(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) +#endif /* _MSC_VER */ + +#endif /* not DBG */ + +#endif /* USBDEBUG_H__ */ diff --git a/reactos/drivers/usb/usbport/usbport.c b/reactos/drivers/usb/usbport/usbport.c new file mode 100644 index 00000000000..9a099828e2d --- /dev/null +++ b/reactos/drivers/usb/usbport/usbport.c @@ -0,0 +1,2775 @@ +#include "usbport.h" + +#define NDEBUG +#include + +#define NDEBUG_USBPORT_CORE +#define NDEBUG_USBPORT_INTERRUPT +#define NDEBUG_USBPORT_TIMER +#include "usbdebug.h" + +LIST_ENTRY USBPORT_MiniPortDrivers = {NULL, NULL}; +LIST_ENTRY USBPORT_USB1FdoList = {NULL, NULL}; +LIST_ENTRY USBPORT_USB2FdoList = {NULL, NULL}; + +KSPIN_LOCK USBPORT_SpinLock; +BOOLEAN USBPORT_Initialized = FALSE; + +PDEVICE_OBJECT +NTAPI +USBPORT_FindUSB2Controller(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_DEVICE_EXTENSION USB2FdoExtension; + KIRQL OldIrql; + PLIST_ENTRY USB2FdoEntry; + PDEVICE_OBJECT USB2FdoDevice = NULL; + + DPRINT("USBPORT_FindUSB2Controller: FdoDevice - %p\n", FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); + + USB2FdoEntry = USBPORT_USB2FdoList.Flink; + + while (USB2FdoEntry && USB2FdoEntry != &USBPORT_USB2FdoList) + { + USB2FdoExtension = CONTAINING_RECORD(USB2FdoEntry, + USBPORT_DEVICE_EXTENSION, + ControllerLink); + + if (USB2FdoExtension->BusNumber == FdoExtension->BusNumber && + USB2FdoExtension->PciDeviceNumber == FdoExtension->PciDeviceNumber) + { + USB2FdoDevice = USB2FdoExtension->CommonExtension.SelfDevice; + break; + } + + USB2FdoEntry = USB2FdoEntry->Flink; + } + + KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); + + return USB2FdoDevice; +} + +VOID +NTAPI +USBPORT_AddUSB1Fdo(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_AddUSB1Fdo: FdoDevice - %p\n", FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + FdoExtension->Flags |= USBPORT_FLAG_REGISTERED_FDO; + + ExInterlockedInsertTailList(&USBPORT_USB1FdoList, + &FdoExtension->ControllerLink, + &USBPORT_SpinLock); +} + +VOID +NTAPI +USBPORT_AddUSB2Fdo(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_AddUSB2Fdo: FdoDevice - %p\n", FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + FdoExtension->Flags |= USBPORT_FLAG_REGISTERED_FDO; + + ExInterlockedInsertTailList(&USBPORT_USB2FdoList, + &FdoExtension->ControllerLink, + &USBPORT_SpinLock); +} + +VOID +NTAPI +USBPORT_RemoveUSBxFdo(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + + DPRINT("USBPORT_RemoveUSBxFdo: FdoDevice - %p\n", FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); + RemoveEntryList(&FdoExtension->ControllerLink); + KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); + + FdoExtension->Flags &= ~USBPORT_FLAG_REGISTERED_FDO; + + FdoExtension->ControllerLink.Flink = NULL; + FdoExtension->ControllerLink.Blink = NULL; +} + +BOOLEAN +NTAPI +USBPORT_IsCompanionFdoExtension(IN PDEVICE_OBJECT USB2FdoDevice, + IN PUSBPORT_DEVICE_EXTENSION USB1FdoExtension) +{ + PUSBPORT_DEVICE_EXTENSION USB2FdoExtension; + + DPRINT("USBPORT_IsCompanionFdoExtension: USB2Fdo - %p, USB1FdoExtension - %p\n", + USB2FdoDevice, + USB1FdoExtension); + + USB2FdoExtension = USB2FdoDevice->DeviceExtension; + + return USB2FdoExtension->BusNumber == USB1FdoExtension->BusNumber && + USB2FdoExtension->PciDeviceNumber == USB1FdoExtension->PciDeviceNumber; +} + +PDEVICE_RELATIONS +NTAPI +USBPORT_FindCompanionControllers(IN PDEVICE_OBJECT USB2FdoDevice, + IN BOOLEAN IsObRefer, + IN BOOLEAN IsFDOsReturned) +{ + PLIST_ENTRY USB1FdoList; + PUSBPORT_DEVICE_EXTENSION USB1FdoExtension; + ULONG NumControllers = 0; + PDEVICE_OBJECT * Entry; + PDEVICE_RELATIONS ControllersList = NULL; + KIRQL OldIrql; + + DPRINT("USBPORT_FindCompanionControllers: USB2Fdo - %p, IsObRefer - %x, IsFDOs - %x\n", + USB2FdoDevice, + IsObRefer, + IsFDOsReturned); + + KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); + + USB1FdoList = USBPORT_USB1FdoList.Flink; + + while (USB1FdoList && USB1FdoList != &USBPORT_USB1FdoList) + { + USB1FdoExtension = CONTAINING_RECORD(USB1FdoList, + USBPORT_DEVICE_EXTENSION, + ControllerLink); + + if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC && + USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension)) + { + ++NumControllers; + } + + USB1FdoList = USB1FdoExtension->ControllerLink.Flink; + } + + DPRINT("USBPORT_FindCompanionControllers: NumControllers - %x\n", + NumControllers); + + if (!NumControllers) + { + goto Exit; + } + + ControllersList = ExAllocatePoolWithTag(NonPagedPool, + NumControllers * sizeof(DEVICE_RELATIONS), + USB_PORT_TAG); + + if (!ControllersList) + { + goto Exit; + } + + RtlZeroMemory(ControllersList, NumControllers * sizeof(DEVICE_RELATIONS)); + + ControllersList->Count = NumControllers; + + USB1FdoList = USBPORT_USB1FdoList.Flink; + + Entry = &ControllersList->Objects[0]; + + while (USB1FdoList && USB1FdoList != &USBPORT_USB1FdoList) + { + USB1FdoExtension = CONTAINING_RECORD(USB1FdoList, + USBPORT_DEVICE_EXTENSION, + ControllerLink); + + if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC && + USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension)) + { + *Entry = USB1FdoExtension->CommonExtension.LowerPdoDevice; + + if (IsObRefer) + { + ObReferenceObject(USB1FdoExtension->CommonExtension.LowerPdoDevice); + } + + if (IsFDOsReturned) + { + *Entry = USB1FdoExtension->CommonExtension.SelfDevice; + } + + ++Entry; + } + + USB1FdoList = USB1FdoExtension->ControllerLink.Flink; + } + +Exit: + + KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); + + return ControllersList; +} + +MPSTATUS +NTAPI +USBPORT_NtStatusToMpStatus(NTSTATUS NtStatus) +{ + DPRINT("USBPORT_NtStatusToMpStatus: NtStatus - %x\n", NtStatus); + + if (NtStatus == STATUS_SUCCESS) + { + return MP_STATUS_SUCCESS; + } + else + { + return MP_STATUS_UNSUCCESSFUL; + } +} + +NTSTATUS +NTAPI +USBPORT_SetRegistryKeyValue(IN PDEVICE_OBJECT DeviceObject, + IN BOOL UseDriverKey, + IN ULONG Type, + IN PCWSTR ValueNameString, + IN PVOID Data, + IN ULONG DataSize) +{ + UNICODE_STRING ValueName; + HANDLE KeyHandle; + NTSTATUS Status; + + DPRINT("USBPORT_SetRegistryKeyValue: ValueNameString - %S \n", + ValueNameString); + + if (UseDriverKey) + { + Status = IoOpenDeviceRegistryKey(DeviceObject, + PLUGPLAY_REGKEY_DRIVER, + STANDARD_RIGHTS_ALL, + &KeyHandle); + } + else + { + Status = IoOpenDeviceRegistryKey(DeviceObject, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + &KeyHandle); + } + + if (NT_SUCCESS(Status)) + { + RtlInitUnicodeString(&ValueName, ValueNameString); + + Status = ZwSetValueKey(KeyHandle, + &ValueName, + 0, + Type, + Data, + DataSize); + + ZwClose(KeyHandle); + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_GetRegistryKeyValueFullInfo(IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice, + IN BOOL UseDriverKey, + IN PCWSTR SourceString, + IN ULONG LengthStr, + IN PVOID Buffer, + IN ULONG BufferLength) +{ + NTSTATUS Status; + PKEY_VALUE_FULL_INFORMATION KeyValue; + UNICODE_STRING ValueName; + HANDLE KeyHandle; + ULONG LengthKey; + + DPRINT("USBPORT_GetRegistryKeyValue: UseDriverKey - %x, SourceString - %S, LengthStr - %x, Buffer - %p, BufferLength - %x\n", + UseDriverKey, + SourceString, + LengthStr, + Buffer, + BufferLength); + + if (UseDriverKey) + { + Status = IoOpenDeviceRegistryKey(PdoDevice, + PLUGPLAY_REGKEY_DRIVER, + STANDARD_RIGHTS_ALL, + &KeyHandle); + } + else + { + Status = IoOpenDeviceRegistryKey(PdoDevice, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + &KeyHandle); + } + + if (NT_SUCCESS(Status)) + { + RtlInitUnicodeString(&ValueName, SourceString); + + LengthKey = sizeof(KEY_VALUE_FULL_INFORMATION) + + LengthStr + + BufferLength; + + KeyValue = ExAllocatePoolWithTag(PagedPool, + LengthKey, + USB_PORT_TAG); + + if (KeyValue) + { + RtlZeroMemory(KeyValue, LengthKey); + + Status = ZwQueryValueKey(KeyHandle, + &ValueName, + KeyValueFullInformation, + KeyValue, + LengthKey, + &LengthKey); + + if (NT_SUCCESS(Status)) + { + RtlCopyMemory(Buffer, + (PUCHAR)KeyValue + KeyValue->DataOffset, + BufferLength); + } + + ExFreePoolWithTag(KeyValue, USB_PORT_TAG); + } + + ZwClose(KeyHandle); + } + + return Status; +} + +MPSTATUS +NTAPI +USBPORT_GetMiniportRegistryKeyValue(IN PVOID Context, + IN BOOL UseDriverKey, + IN PCWSTR SourceString, + IN SIZE_T LengthStr, + IN PVOID Buffer, + IN SIZE_T BufferLength) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + NTSTATUS Status; + + DPRINT("USBPORT_GetMiniportRegistryKeyValue: Context - %p, UseDriverKey - %x, SourceString - %S, LengthStr - %x, Buffer - %p, BufferLength - %x\n", + Context, + UseDriverKey, + SourceString, + LengthStr, + Buffer, + BufferLength); + + //DbgBreakPoint(); + + //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION)); + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)Context - + sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoDevice = FdoExtension->CommonExtension.SelfDevice; + + Status = USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + UseDriverKey, + SourceString, + LengthStr, + Buffer, + BufferLength); + + return USBPORT_NtStatusToMpStatus(Status); +} + +NTSTATUS +NTAPI +USBPORT_GetSetConfigSpaceData(IN PDEVICE_OBJECT FdoDevice, + IN BOOLEAN IsReadData, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + ULONG BytesReadWrite; + + DPRINT("USBPORT_GetSetConfigSpaceData ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + BytesReadWrite = Length; + + if (IsReadData) + { + RtlZeroMemory(Buffer, Length); + + BytesReadWrite = (*FdoExtension->BusInterface.GetBusData) + (FdoExtension->BusInterface.Context, + PCI_WHICHSPACE_CONFIG, + Buffer, + Offset, + Length); + } + else + { + BytesReadWrite = (*FdoExtension->BusInterface.SetBusData) + (FdoExtension->BusInterface.Context, + PCI_WHICHSPACE_CONFIG, + Buffer, + Offset, + Length); + } + + if (BytesReadWrite == Length) + { + return STATUS_SUCCESS; + } + + return STATUS_UNSUCCESSFUL; +} + +MPSTATUS +NTAPI +USBPORT_ReadWriteConfigSpace(IN PVOID Context, + IN BOOLEAN IsReadData, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + NTSTATUS Status; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + + DPRINT("USBPORT_ReadWriteConfigSpace: ... \n"); + + //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION)); + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)Context - + sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoDevice = FdoExtension->CommonExtension.SelfDevice; + + Status = USBPORT_GetSetConfigSpaceData(FdoDevice, + IsReadData, + Buffer, + Offset, + Length); + + return USBPORT_NtStatusToMpStatus(Status); +} + +NTSTATUS +NTAPI +USBPORT_USBDStatusToNtStatus(IN PURB Urb, + IN USBD_STATUS USBDStatus) +{ + NTSTATUS Status; + + if (USBD_ERROR(USBDStatus)) + { + DPRINT1("USBPORT_USBDStatusToNtStatus: Urb - %p, USBDStatus - %x\n", + Urb, + USBDStatus); + } + + if (Urb) + Urb->UrbHeader.Status = USBDStatus; + + switch (USBDStatus) + { + case USBD_STATUS_SUCCESS: + Status = STATUS_SUCCESS; + break; + + case USBD_STATUS_INSUFFICIENT_RESOURCES: + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + + case USBD_STATUS_DEVICE_GONE: + Status = STATUS_DEVICE_NOT_CONNECTED; + break; + + case USBD_STATUS_CANCELED: + Status = STATUS_CANCELLED; + break; + + case USBD_STATUS_NOT_SUPPORTED: + Status = STATUS_NOT_SUPPORTED; + break; + + case USBD_STATUS_INVALID_URB_FUNCTION: + case USBD_STATUS_INVALID_PARAMETER: + case USBD_STATUS_INVALID_PIPE_HANDLE: + case USBD_STATUS_BAD_START_FRAME: + Status = STATUS_INVALID_PARAMETER; + break; + + default: + if (USBD_ERROR(USBDStatus)) + Status = STATUS_UNSUCCESSFUL; + else + Status = STATUS_SUCCESS; + + break; + } + + return Status; +} + +NTSTATUS +NTAPI +USBPORT_Wait(IN PVOID Context, + IN ULONG Milliseconds) +{ + LARGE_INTEGER Interval = {{0, 0}}; + + DPRINT("USBPORT_Wait: Milliseconds - %x\n", Milliseconds); + Interval.QuadPart -= 10000 * Milliseconds + (KeQueryTimeIncrement() - 1); + return KeDelayExecutionThread(KernelMode, FALSE, &Interval); +} + +VOID +NTAPI +USBPORT_MiniportInterrupts(IN PDEVICE_OBJECT FdoDevice, + IN BOOLEAN IsEnable) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + BOOLEAN IsLock; + KIRQL OldIrql; + + DPRINT_INT("USBPORT_MiniportInterrupts: IsEnable - %p\n", IsEnable); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + IsLock = (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_NOT_LOCK_INT) == 0; + + if (IsLock) + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + if (IsEnable) + { + FdoExtension->Flags |= USBPORT_FLAG_INTERRUPT_ENABLED; + Packet->EnableInterrupts(FdoExtension->MiniPortExt); + } + else + { + Packet->DisableInterrupts(FdoExtension->MiniPortExt); + FdoExtension->Flags &= ~USBPORT_FLAG_INTERRUPT_ENABLED; + } + + if (IsLock) + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); +} + +VOID +NTAPI +USBPORT_SoftInterruptDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_SoftInterruptDpc: ... \n"); + + FdoDevice = DeferredContext; + FdoExtension = FdoDevice->DeviceExtension; + + if (!KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, (PVOID)1)) + { + InterlockedDecrement(&FdoExtension->IsrDpcCounter); + } +} + +VOID +NTAPI +USBPORT_SoftInterrupt(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + LARGE_INTEGER DueTime = {{0, 0}}; + + DPRINT("USBPORT_SoftInterrupt: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + KeInitializeTimer(&FdoExtension->TimerSoftInterrupt); + + KeInitializeDpc(&FdoExtension->SoftInterruptDpc, + USBPORT_SoftInterruptDpc, + FdoDevice); + + DueTime.QuadPart -= 10000 + (KeQueryTimeIncrement() - 1); + + KeSetTimer(&FdoExtension->TimerSoftInterrupt, + DueTime, + &FdoExtension->SoftInterruptDpc); +} + +VOID +NTAPI +USBPORT_InvalidateControllerHandler(IN PDEVICE_OBJECT FdoDevice, + IN ULONG Type) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_InvalidateControllerHandler: Invalidate Type - %x\n", + Type); + + FdoExtension = FdoDevice->DeviceExtension; + + switch (Type) + { + case INVALIDATE_CONTROLLER_RESET: + DPRINT1("USBPORT_InvalidateControllerHandler: INVALIDATE_CONTROLLER_RESET UNIMPLEMENTED. FIXME. \n"); + break; + + case INVALIDATE_CONTROLLER_SURPRISE_REMOVE: + DPRINT1("USBPORT_InvalidateControllerHandler: INVALIDATE_CONTROLLER_SURPRISE_REMOVE UNIMPLEMENTED. FIXME. \n"); + break; + + case INVALIDATE_CONTROLLER_SOFT_INTERRUPT: + if (InterlockedIncrement(&FdoExtension->IsrDpcCounter)) + { + InterlockedDecrement(&FdoExtension->IsrDpcCounter); + } + else + { + USBPORT_SoftInterrupt(FdoDevice); + } + break; + } +} + +ULONG +NTAPI +USBPORT_InvalidateController(IN PVOID Context, + IN ULONG Type) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + + DPRINT("USBPORT_InvalidateController: Invalidate Type - %x\n", Type); + + //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION)); + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)Context - + sizeof(USBPORT_DEVICE_EXTENSION)); + FdoDevice = FdoExtension->CommonExtension.SelfDevice; + + USBPORT_InvalidateControllerHandler(FdoDevice, Type); + + return 0; +} + +ULONG +NTAPI +USBPORT_NotifyDoubleBuffer(IN PVOID Context1, + IN PVOID Context2, + IN PVOID Buffer, + IN SIZE_T Length) +{ + DPRINT1("USBPORT_NotifyDoubleBuffer: UNIMPLEMENTED. FIXME. \n"); + return 0; +} + +VOID +NTAPI +USBPORT_WorkerRequestDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_WorkerRequestDpc: ... \n"); + + FdoDevice = DeferredContext; + FdoExtension = FdoDevice->DeviceExtension; + + if (!InterlockedIncrement(&FdoExtension->IsrDpcHandlerCounter)) + { + USBPORT_DpcHandler(FdoDevice); + } + + InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter); +} + +VOID +NTAPI +USBPORT_DoneTransfer(IN PUSBPORT_TRANSFER Transfer) +{ + PUSBPORT_ENDPOINT Endpoint; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PURB Urb; + PIRP Irp; + KIRQL CancelIrql; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_DoneTransfer: Transfer - %p\n", Transfer); + + Endpoint = Transfer->Endpoint; + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + Urb = Transfer->Urb; + Irp = Transfer->Irp; + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + + if (Irp) + { + IoAcquireCancelSpinLock(&CancelIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(CancelIrql); + + USBPORT_RemoveActiveTransferIrp(FdoDevice, Irp); + } + + KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); + + USBPORT_USBDStatusToNtStatus(Transfer->Urb, Transfer->USBDStatus); + USBPORT_CompleteTransfer(Urb, Urb->UrbHeader.Status); + + DPRINT_CORE("USBPORT_DoneTransfer: exit\n"); +} + +VOID +NTAPI +USBPORT_FlushDoneTransfers(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY DoneTransferList; + PUSBPORT_TRANSFER Transfer; + PUSBPORT_ENDPOINT Endpoint; + ULONG TransferCount; + KIRQL OldIrql; + BOOLEAN IsHasTransfers; + + DPRINT_CORE("USBPORT_FlushDoneTransfers: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + DoneTransferList = &FdoExtension->DoneTransferList; + + while (TRUE) + { + KeAcquireSpinLock(&FdoExtension->DoneTransferSpinLock, &OldIrql); + + if (IsListEmpty(DoneTransferList)) + break; + + Transfer = CONTAINING_RECORD(DoneTransferList->Flink, + USBPORT_TRANSFER, + TransferLink); + + RemoveHeadList(DoneTransferList); + KeReleaseSpinLock(&FdoExtension->DoneTransferSpinLock, OldIrql); + + if (Transfer) + { + Endpoint = Transfer->Endpoint; + + if ((Transfer->Flags & TRANSFER_FLAG_SPLITED)) + { + ASSERT(FALSE);// USBPORT_DoneSplitTransfer(Transfer); + } + else + { + USBPORT_DoneTransfer(Transfer); + } + + IsHasTransfers = USBPORT_EndpointHasQueuedTransfers(FdoDevice, + Endpoint, + &TransferCount); + + if (IsHasTransfers && !TransferCount) + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_DPC); + } + } + } + + KeReleaseSpinLock(&FdoExtension->DoneTransferSpinLock, OldIrql); +} + + +VOID +NTAPI +USBPORT_TransferFlushDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PDEVICE_OBJECT FdoDevice; + + DPRINT_CORE("USBPORT_TransferFlushDpc: ... \n"); + FdoDevice = DeferredContext; + USBPORT_FlushDoneTransfers(FdoDevice); +} + +BOOLEAN +NTAPI +USBPORT_QueueDoneTransfer(IN PUSBPORT_TRANSFER Transfer, + IN USBD_STATUS USBDStatus) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_QueueDoneTransfer: Transfer - %p, USBDStatus - %p\n", + Transfer, + USBDStatus); + + FdoDevice = Transfer->Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + RemoveEntryList(&Transfer->TransferLink); + Transfer->USBDStatus = USBDStatus; + + ExInterlockedInsertTailList(&FdoExtension->DoneTransferList, + &Transfer->TransferLink, + &FdoExtension->DoneTransferSpinLock); + + return KeInsertQueueDpc(&FdoExtension->TransferFlushDpc, NULL, NULL); +} + +VOID +NTAPI +USBPORT_DpcHandler(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_ENDPOINT Endpoint; + PLIST_ENTRY Entry; + LIST_ENTRY List; + LONG LockCounter; + + DPRINT("USBPORT_DpcHandler: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + InitializeListHead(&List); + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + Entry = FdoExtension->EndpointList.Flink; + + while (Entry && Entry != &FdoExtension->EndpointList) + { + Endpoint = CONTAINING_RECORD(Entry, + USBPORT_ENDPOINT, + EndpointLink); + + LockCounter = InterlockedIncrement(&Endpoint->LockCounter); + + if (USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_ACTIVE || + LockCounter || + Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) + { + InterlockedDecrement(&Endpoint->LockCounter); + } + else + { + InsertTailList(&List, &Endpoint->DispatchLink); + + if (Endpoint->WorkerLink.Flink && Endpoint->WorkerLink.Blink) + { + RemoveEntryList(&Endpoint->WorkerLink); + + Endpoint->WorkerLink.Flink = NULL; + Endpoint->WorkerLink.Blink = NULL; + } + } + + Entry = Endpoint->EndpointLink.Flink; + } + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + + while (!IsListEmpty(&List)) + { + Endpoint = CONTAINING_RECORD(List.Flink, + USBPORT_ENDPOINT, + DispatchLink); + + RemoveEntryList(List.Flink); + Endpoint->DispatchLink.Flink = NULL; + Endpoint->DispatchLink.Blink = NULL; + + USBPORT_EndpointWorker(Endpoint, TRUE); + USBPORT_FlushPendingTransfers(Endpoint); + } + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + + if (!IsListEmpty(&FdoExtension->WorkerList)) + { + USBPORT_SignalWorkerThread(FdoDevice); + } + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + + USBPORT_FlushDoneTransfers(FdoDevice); +} + +VOID +NTAPI +USBPORT_IsrDpcHandler(IN PDEVICE_OBJECT FdoDevice, + IN BOOLEAN IsDpcHandler) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PUSBPORT_ENDPOINT Endpoint; + PLIST_ENTRY List; + ULONG FrameNumber; + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + DPRINT_CORE("USBPORT_IsrDpcHandler: IsDpcHandler - %x\n", IsDpcHandler); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (InterlockedIncrement(&FdoExtension->IsrDpcHandlerCounter)) + { + KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL); + InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter); + return; + } + + for (List = ExInterlockedRemoveHeadList(&FdoExtension->EpStateChangeList, + &FdoExtension->EpStateChangeSpinLock); + List != NULL; + List = ExInterlockedRemoveHeadList(&FdoExtension->EpStateChangeList, + &FdoExtension->EpStateChangeSpinLock)) + { + Endpoint = CONTAINING_RECORD(List, + USBPORT_ENDPOINT, + StateChangeLink); + + DPRINT_CORE("USBPORT_IsrDpcHandler: Endpoint - %p\n", Endpoint); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); + FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt); + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); + + if (FrameNumber <= Endpoint->FrameNumber && + !(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) + { + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + + ExInterlockedInsertHeadList(&FdoExtension->EpStateChangeList, + &Endpoint->StateChangeLink, + &FdoExtension->EpStateChangeSpinLock); + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); + Packet->InterruptNextSOF(FdoExtension->MiniPortExt); + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); + + break; + } + + KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); + + KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); + Endpoint->StateLast = Endpoint->StateNext; + KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); + + DPRINT_CORE("USBPORT_IsrDpcHandler: Endpoint->StateLast - %x\n", + Endpoint->StateLast); + + if (IsDpcHandler) + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_ONLY); + } + else + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + } + } + + if (IsDpcHandler) + { + USBPORT_DpcHandler(FdoDevice); + } + + InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter); +} + +VOID +NTAPI +USBPORT_IsrDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + BOOLEAN InterruptEnable; + + DPRINT_INT("USBPORT_IsrDpc: DeferredContext - %p, SystemArgument2 - %p\n", + DeferredContext, + SystemArgument2); + + FdoDevice = DeferredContext; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (SystemArgument2) + { + InterlockedDecrement(&FdoExtension->IsrDpcCounter); + } + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportInterruptsSpinLock); + InterruptEnable = (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED) == + USBPORT_FLAG_INTERRUPT_ENABLED; + + Packet->InterruptDpc(FdoExtension->MiniPortExt, InterruptEnable); + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportInterruptsSpinLock); + + if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND && + FdoExtension->TimerFlags & USBPORT_TMFLAG_WAKE) + { + USBPORT_CompletePdoWaitWake(FdoDevice); + } + else + { + USBPORT_IsrDpcHandler(FdoDevice, TRUE); + } + + DPRINT_INT("USBPORT_IsrDpc: exit\n"); +} + +BOOLEAN +NTAPI +USBPORT_InterruptService(IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + BOOLEAN Result = FALSE; + + FdoDevice = ServiceContext; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + DPRINT_INT("USBPORT_InterruptService: FdoExtension->Flags - %lx\n", + FdoExtension->Flags); + + if (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED && + FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) + { + Result = Packet->InterruptService(FdoExtension->MiniPortExt); + + if (Result) + { + KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL); + } + } + + DPRINT_INT("USBPORT_InterruptService: return - %x\n", Result); + + return Result; +} + +VOID +NTAPI +USBPORT_SignalWorkerThread(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_SignalWorkerThread ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->WorkerThreadEventSpinLock, &OldIrql); + KeSetEvent(&FdoExtension->WorkerThreadEvent, EVENT_INCREMENT, FALSE); + KeReleaseSpinLock(&FdoExtension->WorkerThreadEventSpinLock, OldIrql); +} + +VOID +NTAPI +USBPORT_WorkerThreadHandler(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PLIST_ENTRY workerList; + KIRQL OldIrql; + PUSBPORT_ENDPOINT Endpoint; + LIST_ENTRY list; + BOOLEAN Result; + + DPRINT_CORE("USBPORT_WorkerThreadHandler: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) + { + Packet->CheckController(FdoExtension->MiniPortExt); + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + InitializeListHead(&list); + + USBPORT_FlushAllEndpoints(FdoDevice); + + while (TRUE) + { + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + + workerList = &FdoExtension->WorkerList; + + if (IsListEmpty(workerList)) + break; + + Endpoint = CONTAINING_RECORD(workerList->Flink, + USBPORT_ENDPOINT, + WorkerLink); + + DPRINT_CORE("USBPORT_WorkerThreadHandler: Endpoint - %p\n", Endpoint); + + RemoveHeadList(workerList); + Endpoint->WorkerLink.Blink = NULL; + Endpoint->WorkerLink.Flink = NULL; + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + + Result = USBPORT_EndpointWorker(Endpoint, FALSE); + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + + if (Result) + { + if (Endpoint->FlushAbortLink.Flink == NULL || + Endpoint->FlushAbortLink.Blink == NULL) + { + InsertTailList(&list, &Endpoint->FlushAbortLink); + } + } + + while (!IsListEmpty(&list)) + { + Endpoint = CONTAINING_RECORD(list.Flink, + USBPORT_ENDPOINT, + FlushAbortLink); + + RemoveHeadList(&list); + + Endpoint->FlushAbortLink.Flink = NULL; + Endpoint->FlushAbortLink.Blink = NULL; + + if (Endpoint->WorkerLink.Flink == NULL || + Endpoint->WorkerLink.Blink == NULL) + { + InsertTailList(&FdoExtension->WorkerList, + &Endpoint->WorkerLink); + + USBPORT_SignalWorkerThread(FdoDevice); + } + } + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + KeLowerIrql(OldIrql); + } + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + KeLowerIrql(OldIrql); + + USBPORT_FlushClosedEndpointList(FdoDevice); +} + +VOID +NTAPI +USBPORT_DoRootHubCallback(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PRH_INIT_CALLBACK RootHubInitCallback; + PVOID RootHubInitContext; + + FdoExtension = FdoDevice->DeviceExtension; + + DPRINT("USBPORT_DoRootHubCallback: FdoDevice - %p\n", FdoDevice); + + PdoDevice = FdoExtension->RootHubPdo; + + if (PdoDevice) + { + PdoExtension = PdoDevice->DeviceExtension; + + RootHubInitContext = PdoExtension->RootHubInitContext; + RootHubInitCallback = PdoExtension->RootHubInitCallback; + + PdoExtension->RootHubInitCallback = NULL; + PdoExtension->RootHubInitContext = NULL; + + if (RootHubInitCallback) + { + RootHubInitCallback(RootHubInitContext); + } + } + + DPRINT("USBPORT_DoRootHubCallback: exit\n"); +} + +VOID +NTAPI +USBPORT_SynchronizeRootHubCallback(IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT Usb2FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + PUSBPORT_DEVICE_EXTENSION Usb2FdoExtension; + PDEVICE_RELATIONS CompanionControllersList; + PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension; + PDEVICE_OBJECT * Entry; + ULONG ix; + + DPRINT("USBPORT_SynchronizeRootHubCallback: FdoDevice - %p, Usb2FdoDevice - %p\n", + FdoDevice, + Usb2FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (Usb2FdoDevice == NULL && + !(Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)) + { + /* Not Companion USB11 Controller */ + USBPORT_DoRootHubCallback(FdoDevice); + + FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; + InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1); + + DPRINT("USBPORT_SynchronizeRootHubCallback: exit \n"); + return; + } + + /* USB2 or Companion USB11 */ + + DPRINT("USBPORT_SynchronizeRootHubCallback: FdoExtension->Flags - %p\n", + FdoExtension->Flags); + + if (!(FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC)) + { + KeWaitForSingleObject(&FdoExtension->ControllerSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + FdoExtension->Flags |= USBPORT_FLAG_PWR_AND_CHIRP_LOCK; + + if (!(FdoExtension->Flags & (USBPORT_FLAG_HC_SUSPEND | + USBPORT_FLAG_POWER_AND_CHIRP_OK))) + { + USBPORT_RootHubPowerAndChirpAllCcPorts(FdoDevice); + FdoExtension->Flags |= USBPORT_FLAG_POWER_AND_CHIRP_OK; + } + + FdoExtension->Flags &= ~USBPORT_FLAG_PWR_AND_CHIRP_LOCK; + + KeReleaseSemaphore(&FdoExtension->ControllerSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice, + FALSE, + TRUE); + + if (CompanionControllersList) + { + Entry = &CompanionControllersList->Objects[0]; + + for (ix = 0; ix < CompanionControllersList->Count; ++ix) + { + CompanionFdoExtension = ((*Entry)->DeviceExtension); + + InterlockedCompareExchange(&CompanionFdoExtension->RHInitCallBackLock, + 0, + 1); + + ++Entry; + } + + ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG); + } + + USBPORT_DoRootHubCallback(FdoDevice); + + FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; + InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1); + } + else + { + Usb2FdoExtension = Usb2FdoDevice->DeviceExtension; + + USBPORT_Wait(FdoDevice, 50); + + while (FdoExtension->RHInitCallBackLock) + { + USBPORT_Wait(FdoDevice, 10); + + Usb2FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK; + USBPORT_SignalWorkerThread(Usb2FdoDevice); + } + + USBPORT_DoRootHubCallback(FdoDevice); + + FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; + } + + DPRINT("USBPORT_SynchronizeRootHubCallback: exit \n"); +} + +VOID +NTAPI +USBPORT_WorkerThread(IN PVOID StartContext) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + LARGE_INTEGER OldTime; + LARGE_INTEGER NewTime; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_WorkerThread ... \n"); + + FdoDevice = StartContext; + FdoExtension = FdoDevice->DeviceExtension; + + FdoExtension->WorkerThread = KeGetCurrentThread(); + + do + { + KeQuerySystemTime(&OldTime); + + KeWaitForSingleObject(&FdoExtension->WorkerThreadEvent, + Suspended, + KernelMode, + FALSE, + NULL); + + KeQuerySystemTime(&NewTime); + + KeAcquireSpinLock(&FdoExtension->WorkerThreadEventSpinLock, &OldIrql); + KeResetEvent(&FdoExtension->WorkerThreadEvent); + KeReleaseSpinLock(&FdoExtension->WorkerThreadEventSpinLock, OldIrql); + DPRINT_CORE("USBPORT_WorkerThread: run \n"); + + if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) + { + USBPORT_DoSetPowerD0(FdoDevice); + + if (FdoExtension->Flags & USBPORT_FLAG_RH_INIT_CALLBACK) + { + PDEVICE_OBJECT USB2FdoDevice = NULL; + + USB2FdoDevice = USBPORT_FindUSB2Controller(FdoDevice); + USBPORT_SynchronizeRootHubCallback(FdoDevice, USB2FdoDevice); + } + } + + USBPORT_WorkerThreadHandler(FdoDevice); + } + while (!(FdoExtension->Flags & USBPORT_FLAG_WORKER_THREAD_ON)); + + PsTerminateSystemThread(0); +} + +NTSTATUS +NTAPI +USBPORT_CreateWorkerThread(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + NTSTATUS Status; + + DPRINT("USBPORT_CreateWorkerThread ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + FdoExtension->Flags &= ~USBPORT_FLAG_WORKER_THREAD_ON; + + KeInitializeEvent(&FdoExtension->WorkerThreadEvent, + NotificationEvent, + FALSE); + + Status = PsCreateSystemThread(&FdoExtension->WorkerThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + NULL, + USBPORT_WorkerThread, + (PVOID)FdoDevice); + + return Status; +} + +VOID +NTAPI +USBPORT_SynchronizeControllersStart(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT PdoDevice; + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT USB2FdoDevice = NULL; + PUSBPORT_DEVICE_EXTENSION USB2FdoExtension; + BOOLEAN IsOn; + + DPRINT_TIMER("USBPORT_SynchronizeControllersStart: FdoDevice - %p\n", + FdoDevice); + + FdoExtension = FdoDevice->DeviceExtension; + + PdoDevice = FdoExtension->RootHubPdo; + + if (!PdoDevice) + { + return; + } + + PdoExtension = PdoDevice->DeviceExtension; + + if (PdoExtension->RootHubInitCallback == NULL || + FdoExtension->Flags & USBPORT_FLAG_RH_INIT_CALLBACK) + { + return; + } + + DPRINT_TIMER("USBPORT_SynchronizeControllersStart: Flags - %p\n", + FdoExtension->Flags); + + if (FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC) + { + IsOn = FALSE; + + USB2FdoDevice = USBPORT_FindUSB2Controller(FdoDevice); + + DPRINT_TIMER("USBPORT_SynchronizeControllersStart: USB2FdoDevice - %p\n", + USB2FdoDevice); + + if (USB2FdoDevice) + { + USB2FdoExtension = USB2FdoDevice->DeviceExtension; + + if (USB2FdoExtension->CommonExtension.PnpStateFlags & + USBPORT_PNP_STATE_STARTED) + { + IsOn = TRUE; + } + } + + if (!(FdoExtension->Flags & USBPORT_FLAG_NO_HACTION)) + { + goto Start; + } + + USB2FdoDevice = NULL; + } + + IsOn = TRUE; + + Start: + + if (IsOn && + !InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 1, 0)) + { + FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK; + USBPORT_SignalWorkerThread(FdoDevice); + + if (USB2FdoDevice) + { + USB2FdoExtension = USB2FdoDevice->DeviceExtension; + + USB2FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK; + USBPORT_SignalWorkerThread(USB2FdoDevice); + } + } + + DPRINT_TIMER("USBPORT_SynchronizeControllersStart: exit\n"); +} + +VOID +NTAPI +USBPORT_TimerDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + LARGE_INTEGER DueTime = {{0, 0}}; + ULONG TimerFlags; + PTIMER_WORK_QUEUE_ITEM IdleQueueItem; + KIRQL OldIrql; + KIRQL TimerOldIrql; + + DPRINT_TIMER("USBPORT_TimerDpc: Dpc - %p, DeferredContext - %p\n", + Dpc, + DeferredContext); + + FdoDevice = DeferredContext; + FdoExtension = FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &TimerOldIrql); + + TimerFlags = FdoExtension->TimerFlags; + + DPRINT_TIMER("USBPORT_TimerDpc: Flags - %p, TimerFlags - %p\n", + FdoExtension->Flags, + TimerFlags); + + if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND && + FdoExtension->Flags & USBPORT_FLAG_HC_WAKE_SUPPORT && + !(TimerFlags & USBPORT_TMFLAG_HC_RESUME)) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Packet->PollController(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + + USBPORT_SynchronizeControllersStart(FdoDevice); + + if (TimerFlags & USBPORT_TMFLAG_HC_SUSPENDED) + { + USBPORT_BadRequestFlush(FdoDevice); + goto Exit; + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) + { + Packet->CheckController(FdoExtension->MiniPortExt); + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (FdoExtension->Flags & USBPORT_FLAG_HC_POLLING) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Packet->PollController(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + + USBPORT_IsrDpcHandler(FdoDevice, FALSE); + + DPRINT_TIMER("USBPORT_TimerDpc: USBPORT_TimeoutAllEndpoints UNIMPLEMENTED.\n"); + //USBPORT_TimeoutAllEndpoints(FdoDevice); + DPRINT_TIMER("USBPORT_TimerDpc: USBPORT_CheckIdleEndpoints UNIMPLEMENTED.\n"); + //USBPORT_CheckIdleEndpoints(FdoDevice); + + USBPORT_BadRequestFlush(FdoDevice); + + if (FdoExtension->IdleLockCounter > -1 && + !(TimerFlags & USBPORT_TMFLAG_IDLE_QUEUEITEM_ON)) + { + IdleQueueItem = ExAllocatePoolWithTag(NonPagedPool, + sizeof(TIMER_WORK_QUEUE_ITEM), + USB_PORT_TAG); + + DPRINT("USBPORT_TimerDpc: IdleLockCounter - %x, IdleQueueItem - %p\n", + FdoExtension->IdleLockCounter, + IdleQueueItem); + + if (IdleQueueItem) + { + RtlZeroMemory(IdleQueueItem, sizeof(TIMER_WORK_QUEUE_ITEM)); + + IdleQueueItem->WqItem.List.Flink = NULL; + IdleQueueItem->WqItem.WorkerRoutine = USBPORT_DoIdleNotificationCallback; + IdleQueueItem->WqItem.Parameter = IdleQueueItem; + + IdleQueueItem->FdoDevice = FdoDevice; + IdleQueueItem->Context = 0; + + FdoExtension->TimerFlags |= USBPORT_TMFLAG_IDLE_QUEUEITEM_ON; + + ExQueueWorkItem(&IdleQueueItem->WqItem, CriticalWorkQueue); + } + } + +Exit: + + KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, TimerOldIrql); + + if (TimerFlags & USBPORT_TMFLAG_TIMER_QUEUED) + { + DueTime.QuadPart -= FdoExtension->TimerValue * 10000 + + (KeQueryTimeIncrement() - 1); + + KeSetTimer(&FdoExtension->TimerObject, + DueTime, + &FdoExtension->TimerDpc); + } + + DPRINT_TIMER("USBPORT_TimerDpc: exit\n"); +} + +BOOLEAN +NTAPI +USBPORT_StartTimer(IN PDEVICE_OBJECT FdoDevice, + IN ULONG Time) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + LARGE_INTEGER DueTime = {{0, 0}}; + ULONG TimeIncrement; + BOOLEAN Result; + + DPRINT_TIMER("USBPORT_StartTimer: FdoDevice - %p, Time - %x\n", + FdoDevice, + Time); + + FdoExtension = FdoDevice->DeviceExtension; + + TimeIncrement = KeQueryTimeIncrement(); + + FdoExtension->TimerFlags |= USBPORT_TMFLAG_TIMER_QUEUED; + FdoExtension->TimerValue = Time; + + KeInitializeTimer(&FdoExtension->TimerObject); + KeInitializeDpc(&FdoExtension->TimerDpc, USBPORT_TimerDpc, FdoDevice); + + DueTime.QuadPart -= 10000 * Time + (TimeIncrement - 1); + + Result = KeSetTimer(&FdoExtension->TimerObject, + DueTime, + &FdoExtension->TimerDpc); + + return Result; +} + +PUSBPORT_COMMON_BUFFER_HEADER +NTAPI +USBPORT_AllocateCommonBuffer(IN PDEVICE_OBJECT FdoDevice, + IN SIZE_T BufferLength) +{ + PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer = NULL; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDMA_ADAPTER DmaAdapter; + PDMA_OPERATIONS DmaOperations; + SIZE_T HeaderSize; + ULONG Length = 0; + ULONG LengthPadded; + PHYSICAL_ADDRESS LogicalAddress; + ULONG_PTR BaseVA; + ULONG_PTR StartBufferVA; + ULONG_PTR StartBufferPA; + + DPRINT("USBPORT_AllocateCommonBuffer: FdoDevice - %p, BufferLength - %p\n", + FdoDevice, + BufferLength); + + if (BufferLength == 0) + goto Exit; + + FdoExtension = FdoDevice->DeviceExtension; + + DmaAdapter = FdoExtension->DmaAdapter; + DmaOperations = DmaAdapter->DmaOperations; + + HeaderSize = sizeof(USBPORT_COMMON_BUFFER_HEADER); + Length = ROUND_TO_PAGES(BufferLength + HeaderSize); + LengthPadded = Length - (BufferLength + HeaderSize); + + BaseVA = (ULONG_PTR)DmaOperations->AllocateCommonBuffer(DmaAdapter, + Length, + &LogicalAddress, + TRUE); + + if (!BaseVA) + goto Exit; + + StartBufferVA = BaseVA & ~(PAGE_SIZE - 1); + StartBufferPA = LogicalAddress.LowPart & ~(PAGE_SIZE - 1); + + HeaderBuffer = (PUSBPORT_COMMON_BUFFER_HEADER)(StartBufferVA + + BufferLength + + LengthPadded); + + HeaderBuffer->Length = Length; + HeaderBuffer->BaseVA = BaseVA; + HeaderBuffer->LogicalAddress = LogicalAddress; + + HeaderBuffer->BufferLength = BufferLength + LengthPadded; + HeaderBuffer->VirtualAddress = StartBufferVA; + HeaderBuffer->PhysicalAddress = StartBufferPA; + + RtlZeroMemory((PVOID)StartBufferVA, BufferLength + LengthPadded); + +Exit: + return HeaderBuffer; +} + +VOID +NTAPI +USBPORT_FreeCommonBuffer(IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDMA_ADAPTER DmaAdapter; + PDMA_OPERATIONS DmaOperations; + + DPRINT("USBPORT_FreeCommonBuffer: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + + DmaAdapter = FdoExtension->DmaAdapter; + DmaOperations = DmaAdapter->DmaOperations; + + DmaOperations->FreeCommonBuffer(FdoExtension->DmaAdapter, + HeaderBuffer->Length, + HeaderBuffer->LogicalAddress, + (PVOID)HeaderBuffer->VirtualAddress, + TRUE); +} + +PUSBPORT_MINIPORT_INTERFACE +NTAPI +USBPORT_FindMiniPort(IN PDRIVER_OBJECT DriverObject) +{ + KIRQL OldIrql; + PLIST_ENTRY List; + PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; + BOOLEAN IsFound = FALSE; + + DPRINT("USBPORT_FindMiniPort: ... \n"); + + KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); + + for (List = USBPORT_MiniPortDrivers.Flink; + List != &USBPORT_MiniPortDrivers; + List = List->Flink) + { + MiniPortInterface = CONTAINING_RECORD(List, + USBPORT_MINIPORT_INTERFACE, + DriverLink); + + if (MiniPortInterface->DriverObject == DriverObject) + { + DPRINT("USBPORT_FindMiniPort: find MiniPortInterface - %p\n", + MiniPortInterface); + + IsFound = TRUE; + break; + } + } + + KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); + + if (IsFound) + return MiniPortInterface; + else + return NULL; + +} + +NTSTATUS +NTAPI +USBPORT_AddDevice(IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + NTSTATUS Status; + PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; + ULONG DeviceNumber = 0; + WCHAR CharDeviceName[64]; + UNICODE_STRING DeviceName; + PDEVICE_OBJECT DeviceObject; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_COMMON_DEVICE_EXTENSION FdoCommonExtension; + PDEVICE_OBJECT LowerDevice; + ULONG Length; + + DPRINT("USBPORT_AddDevice: DriverObject - %p, PhysicalDeviceObject - %p\n", + DriverObject, + PhysicalDeviceObject); + + MiniPortInterface = USBPORT_FindMiniPort(DriverObject); + + if (!MiniPortInterface) + { + DPRINT("USBPORT_AddDevice: USBPORT_FindMiniPort not found MiniPortInterface\n"); + return STATUS_UNSUCCESSFUL; + } + + while (TRUE) + { + /* Construct device name */ + RtlStringCbPrintfW(CharDeviceName, + sizeof(CharDeviceName), + L"\\Device\\USBFDO-%d", + DeviceNumber); + + RtlInitUnicodeString(&DeviceName, CharDeviceName); + + Length = sizeof(USBPORT_DEVICE_EXTENSION) + + MiniPortInterface->Packet.MiniPortExtensionSize; + + /* Create device */ + Status = IoCreateDevice(DriverObject, + Length, + &DeviceName, + FILE_DEVICE_CONTROLLER, + 0, + FALSE, + &DeviceObject); + + /* Check for success */ + if (NT_SUCCESS(Status)) break; + + /* Is there a device object with that same name */ + if ((Status == STATUS_OBJECT_NAME_EXISTS) || + (Status == STATUS_OBJECT_NAME_COLLISION)) + { + /* Try the next name */ + DeviceNumber++; + continue; + } + + /* Bail out on other errors */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBPORT_AddDevice: failed to create %wZ, Status %x\n", + &DeviceName, + Status); + + return Status; + } + } + + DPRINT("USBPORT_AddDevice: created device %p <%wZ>, Status %x\n", + DeviceObject, + &DeviceName, + Status); + + FdoExtension = DeviceObject->DeviceExtension; + FdoCommonExtension = &FdoExtension->CommonExtension; + + RtlZeroMemory(FdoExtension, sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoCommonExtension->SelfDevice = DeviceObject; + FdoCommonExtension->LowerPdoDevice = PhysicalDeviceObject; + FdoCommonExtension->IsPDO = FALSE; + + LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, + PhysicalDeviceObject); + + FdoCommonExtension->LowerDevice = LowerDevice; + + FdoCommonExtension->DevicePowerState = PowerDeviceD3; + + FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + + sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoExtension->MiniPortInterface = MiniPortInterface; + FdoExtension->FdoNameNumber = DeviceNumber; + + KeInitializeSemaphore(&FdoExtension->DeviceSemaphore, 1, 1); + KeInitializeSemaphore(&FdoExtension->ControllerSemaphore, 1, 1); + + InitializeListHead(&FdoExtension->EndpointList); + InitializeListHead(&FdoExtension->DoneTransferList); + InitializeListHead(&FdoExtension->WorkerList); + InitializeListHead(&FdoExtension->EpStateChangeList); + InitializeListHead(&FdoExtension->MapTransferList); + InitializeListHead(&FdoExtension->DeviceHandleList); + InitializeListHead(&FdoExtension->IdleIrpList); + InitializeListHead(&FdoExtension->BadRequestList); + InitializeListHead(&FdoExtension->EndpointClosedList); + + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + return Status; +} + +VOID +NTAPI +USBPORT_Unload(IN PDRIVER_OBJECT DriverObject) +{ + PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; + + DPRINT1("USBPORT_Unload: FIXME!\n"); + + MiniPortInterface = USBPORT_FindMiniPort(DriverObject); + + if (!MiniPortInterface) + { + DPRINT("USBPORT_Unload: CRITICAL ERROR!!! USBPORT_FindMiniPort not found MiniPortInterface\n"); + KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0); + } + + DPRINT1("USBPORT_Unload: UNIMPLEMENTED. FIXME. \n"); + //MiniPortInterface->DriverUnload(DriverObject); // Call MiniPort _HCI_Unload +} + +ULONG +NTAPI +USBPORT_MiniportCompleteTransfer(IN PVOID MiniPortExtension, + IN PVOID MiniPortEndpoint, + IN PVOID TransferParameters, + IN USBD_STATUS USBDStatus, + IN ULONG TransferLength) +{ + PUSBPORT_TRANSFER Transfer; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_MiniportCompleteTransfer: USBDStatus - %x, TransferLength - %x\n", + USBDStatus, + TransferLength); + + Transfer = CONTAINING_RECORD(TransferParameters, + USBPORT_TRANSFER, + TransferParameters); + + FdoDevice = Transfer->Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + Transfer->CompletedTransferLen = TransferLength; + + RemoveEntryList(&Transfer->TransferLink); + + Transfer->USBDStatus = USBDStatus; + + ExInterlockedInsertTailList(&FdoExtension->DoneTransferList, + &Transfer->TransferLink, + &FdoExtension->DoneTransferSpinLock); + + return KeInsertQueueDpc(&FdoExtension->TransferFlushDpc, NULL, NULL); +} + +ULONG +NTAPI +USBPORT_CompleteIsoTransfer(IN PVOID MiniPortExtension, + IN PVOID MiniPortEndpoint, + IN PVOID TransferParameters, + IN ULONG TransferLength) +{ + DPRINT1("USBPORT_CompleteIsoTransfer: UNIMPLEMENTED. FIXME.\n"); + return 0; +} + +VOID +NTAPI +USBPORT_AsyncTimerDpc(IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_ASYNC_CALLBACK_DATA AsyncCallbackData; + + DPRINT("USBPORT_AsyncTimerDpc: ... \n"); + + AsyncCallbackData = DeferredContext; + FdoDevice = AsyncCallbackData->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + + (*AsyncCallbackData->CallbackFunction)(FdoExtension->MiniPortExt, + &AsyncCallbackData->CallbackContext); + + ExFreePoolWithTag(AsyncCallbackData, USB_PORT_TAG); +} + +ULONG +NTAPI +USBPORT_RequestAsyncCallback(IN PVOID Context, + IN ULONG TimerValue, + IN PVOID Buffer, + IN SIZE_T Length, + IN ASYNC_TIMER_CALLBACK * Callback) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_ASYNC_CALLBACK_DATA AsyncCallbackData; + LARGE_INTEGER DueTime = {{0, 0}}; + + DPRINT("USBPORT_RequestAsyncCallback: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)Context - + sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoDevice = FdoExtension->CommonExtension.SelfDevice; + + AsyncCallbackData = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBPORT_ASYNC_CALLBACK_DATA) + Length, + USB_PORT_TAG); + + if (!AsyncCallbackData) + { + DPRINT1("USBPORT_RequestAsyncCallback: Not allocated AsyncCallbackData!\n"); + return 0; + } + + RtlZeroMemory(AsyncCallbackData, + sizeof(USBPORT_ASYNC_CALLBACK_DATA) + Length); + + if (Length) + { + RtlCopyMemory(&AsyncCallbackData->CallbackContext, Buffer, Length); + } + + AsyncCallbackData->FdoDevice = FdoDevice; + AsyncCallbackData->CallbackFunction = Callback; + + KeInitializeTimer(&AsyncCallbackData->AsyncTimer); + + KeInitializeDpc(&AsyncCallbackData->AsyncTimerDpc, + USBPORT_AsyncTimerDpc, + AsyncCallbackData); + + DueTime.QuadPart -= (KeQueryTimeIncrement() - 1) + 10000 * TimerValue; + + KeSetTimer(&AsyncCallbackData->AsyncTimer, + DueTime, + &AsyncCallbackData->AsyncTimerDpc); + + return 0; +} + +PVOID +NTAPI +USBPORT_GetMappedVirtualAddress(IN PVOID PhysicalAddress, + IN PVOID MiniPortExtension, + IN PVOID MiniPortEndpoint) +{ + PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer; + PUSBPORT_ENDPOINT Endpoint; + ULONG Offset; + ULONG_PTR VirtualAddress; + + DPRINT_CORE("USBPORT_GetMappedVirtualAddress ... \n"); + + Endpoint = (PUSBPORT_ENDPOINT)((ULONG_PTR)MiniPortEndpoint - + sizeof(USBPORT_ENDPOINT)); + + if (!Endpoint) + { + ASSERT(FALSE); + } + + HeaderBuffer = Endpoint->HeaderBuffer; + + Offset = (ULONG_PTR)PhysicalAddress - HeaderBuffer->PhysicalAddress; + VirtualAddress = HeaderBuffer->VirtualAddress + Offset; + + return (PVOID)VirtualAddress; +} + +ULONG +NTAPI +USBPORT_InvalidateEndpoint(IN PVOID Context1, + IN PVOID Context2) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_ENDPOINT Endpoint; + + DPRINT_CORE("USBPORT_InvalidateEndpoint: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)Context1 - + sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoDevice = FdoExtension->CommonExtension.SelfDevice; + + Endpoint = (PUSBPORT_ENDPOINT)((ULONG_PTR)Context2 - + sizeof(USBPORT_ENDPOINT)); + + if (Context2) + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_ONLY); + } + else + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + NULL, + INVALIDATE_ENDPOINT_ONLY); + } + + return 0; +} + +VOID +NTAPI +USBPORT_CompleteTransfer(IN PURB Urb, + IN USBD_STATUS TransferStatus) +{ + struct _URB_CONTROL_TRANSFER *UrbTransfer; + PUSBPORT_TRANSFER Transfer; + NTSTATUS Status; + PIRP Irp; + KIRQL OldIrql; + PRKEVENT Event; + BOOLEAN WriteToDevice; + BOOLEAN IsFlushSuccess; + PMDL Mdl; + ULONG_PTR CurrentVa; + SIZE_T TransferLength; + PUSBPORT_ENDPOINT Endpoint; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDMA_OPERATIONS DmaOperations; + + DPRINT("USBPORT_CompleteTransfer: Urb - %p, TransferStatus - %X\n", + Urb, + TransferStatus); + + UrbTransfer = &Urb->UrbControlTransfer; + Transfer = UrbTransfer->hca.Reserved8[0]; + + Transfer->USBDStatus = TransferStatus; + Status = USBPORT_USBDStatusToNtStatus(Urb, TransferStatus); + + UrbTransfer->TransferBufferLength = Transfer->CompletedTransferLen; + + if (Transfer->Flags & TRANSFER_FLAG_DMA_MAPPED) + { + Endpoint = Transfer->Endpoint; + FdoDevice = Endpoint->FdoDevice; + FdoExtension = FdoDevice->DeviceExtension; + DmaOperations = FdoExtension->DmaAdapter->DmaOperations; + + WriteToDevice = Transfer->Direction == USBPORT_DMA_DIRECTION_TO_DEVICE; + Mdl = UrbTransfer->TransferBufferMDL; + CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); + TransferLength = UrbTransfer->TransferBufferLength; + + IsFlushSuccess = DmaOperations->FlushAdapterBuffers(FdoExtension->DmaAdapter, + Mdl, + Transfer->MapRegisterBase, + (PVOID)CurrentVa, + TransferLength, + WriteToDevice); + + if (!IsFlushSuccess) + { + DPRINT("USBPORT_CompleteTransfer: no FlushAdapterBuffers !!!\n"); + ASSERT(FALSE); + } + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + DmaOperations->FreeMapRegisters(FdoExtension->DmaAdapter, + Transfer->MapRegisterBase, + Transfer->NumberOfMapRegisters); + + KeLowerIrql(OldIrql); + } + + if (Urb->UrbHeader.UsbdFlags & USBD_FLAG_ALLOCATED_MDL) + { + IoFreeMdl(Transfer->TransferBufferMDL); + Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_MDL; + } + + Urb->UrbControlTransfer.hca.Reserved8[0] = NULL; + Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_TRANSFER; + + Irp = Transfer->Irp; + + if (Irp) + { + if (!NT_SUCCESS(Status)) + { + //DbgBreakPoint(); + DPRINT1("USBPORT_CompleteTransfer: Irp - %p complete with Status - %lx\n", + Irp, + Status); + + USBPORT_DumpingURB(Urb); + } + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + KeLowerIrql(OldIrql); + } + + Event = Transfer->Event; + + if (Event) + { + KeSetEvent(Event, EVENT_INCREMENT, FALSE); + } + + ExFreePoolWithTag(Transfer, USB_PORT_TAG); + + DPRINT_CORE("USBPORT_CompleteTransfer: exit\n"); +} + +IO_ALLOCATION_ACTION +NTAPI +USBPORT_MapTransfer(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDMA_ADAPTER DmaAdapter; + PUSBPORT_TRANSFER Transfer; + PURB Urb; + PUSBPORT_ENDPOINT Endpoint; + PMDL Mdl; + ULONG_PTR CurrentVa; + PUSBPORT_SCATTER_GATHER_LIST sgList; + SIZE_T CurrentLength; + ULONG ix; + BOOLEAN WriteToDevice; + PHYSICAL_ADDRESS PhAddr = {{0, 0}}; + PHYSICAL_ADDRESS PhAddress = {{0, 0}}; + SIZE_T TransferLength; + SIZE_T SgCurrentLength; + SIZE_T ElementLength; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + PDMA_OPERATIONS DmaOperations; + + DPRINT_CORE("USBPORT_MapTransfer: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + DmaAdapter = FdoExtension->DmaAdapter; + DmaOperations = DmaAdapter->DmaOperations; + + Transfer = Context; + + Urb = Transfer->Urb; + Endpoint = Transfer->Endpoint; + TransferLength = Transfer->TransferParameters.TransferBufferLength; + + Mdl = Urb->UrbControlTransfer.TransferBufferMDL; + CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); + + Transfer->SgList.CurrentVa = CurrentVa; + Transfer->SgList.MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority); + + sgList = &Transfer->SgList; + sgList->Flags = 0; + + Transfer->MapRegisterBase = MapRegisterBase; + + ix = 0; + CurrentLength = 0; + + do + { + WriteToDevice = Transfer->Direction == USBPORT_DMA_DIRECTION_TO_DEVICE; + ASSERT(Transfer->Direction != 0); + + PhAddress = DmaOperations->MapTransfer(DmaAdapter, + Mdl, + MapRegisterBase, + (PVOID)CurrentVa, + &TransferLength, + WriteToDevice); + + DPRINT_CORE("USBPORT_MapTransfer: PhAddress.LowPart - %p, PhAddress.HighPart - %x, TransferLength - %x\n", + PhAddress.LowPart, + PhAddress.HighPart, + TransferLength); + + PhAddress.HighPart = 0; + SgCurrentLength = TransferLength; + + do + { + ElementLength = 0x1000 - (PhAddress.LowPart & 0xFFF); + + if (ElementLength > SgCurrentLength) + ElementLength = SgCurrentLength; + + DPRINT_CORE("USBPORT_MapTransfer: PhAddress.LowPart - %p, HighPart - %x, ElementLength - %x\n", + PhAddress.LowPart, + PhAddress.HighPart, + ElementLength); + + sgList->SgElement[ix].SgPhysicalAddress = PhAddress; + sgList->SgElement[ix].SgTransferLength = ElementLength; + sgList->SgElement[ix].SgOffset = CurrentLength + + (TransferLength - SgCurrentLength); + + PhAddress.LowPart += ElementLength; + SgCurrentLength -= ElementLength; + + ++ix; + } + while (SgCurrentLength); + + if ((PhAddr.LowPart == PhAddress.LowPart) && + (PhAddr.HighPart == PhAddress.HighPart)) + { + ASSERT(FALSE); + } + + PhAddr = PhAddress; + + CurrentLength += TransferLength; + CurrentVa += TransferLength; + + TransferLength = Transfer->TransferParameters.TransferBufferLength - + CurrentLength; + } + while (CurrentLength != Transfer->TransferParameters.TransferBufferLength); + + Transfer->SgList.SgElementCount = ix; + Transfer->Flags |= TRANSFER_FLAG_DMA_MAPPED; + + ASSERT(Transfer->TransferParameters.TransferBufferLength <= + Endpoint->EndpointProperties.MaxTransferSize); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + InsertTailList(&Endpoint->TransferList, &Transfer->TransferLink); + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; + InterlockedDecrement(&DeviceHandle->DeviceHandleLock); + + if (USBPORT_EndpointWorker(Endpoint, 0)) + { + USBPORT_InvalidateEndpointHandler(FdoDevice, + Endpoint, + INVALIDATE_ENDPOINT_WORKER_THREAD); + } + + return DeallocateObjectKeepRegisters; +} + +VOID +NTAPI +USBPORT_FlushMapTransfers(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PLIST_ENTRY MapTransferList; + PUSBPORT_TRANSFER Transfer; + ULONG NumMapRegisters; + PMDL Mdl; + SIZE_T TransferBufferLength; + ULONG_PTR VirtualAddr; + KIRQL OldIrql; + NTSTATUS Status; + PDMA_OPERATIONS DmaOperations; + + DPRINT_CORE("USBPORT_FlushMapTransfers: ... \n"); + + FdoExtension = FdoDevice->DeviceExtension; + DmaOperations = FdoExtension->DmaAdapter->DmaOperations; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + while (TRUE) + { + MapTransferList = &FdoExtension->MapTransferList; + + if (IsListEmpty(&FdoExtension->MapTransferList)) + { + KeLowerIrql(OldIrql); + return; + } + + Transfer = CONTAINING_RECORD(MapTransferList->Flink, + USBPORT_TRANSFER, + TransferLink); + + RemoveHeadList(MapTransferList); + + Mdl = Transfer->Urb->UrbControlTransfer.TransferBufferMDL; + TransferBufferLength = Transfer->TransferParameters.TransferBufferLength; + VirtualAddr = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); + + NumMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr, + TransferBufferLength); + + Transfer->NumberOfMapRegisters = NumMapRegisters; + + Status = DmaOperations->AllocateAdapterChannel(FdoExtension->DmaAdapter, + FdoDevice, + NumMapRegisters, + USBPORT_MapTransfer, + Transfer); + + if (!NT_SUCCESS(Status)) + ASSERT(FALSE); + } + + KeLowerIrql(OldIrql); +} + +USBD_STATUS +NTAPI +USBPORT_AllocateTransfer(IN PDEVICE_OBJECT FdoDevice, + IN PURB Urb, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PIRP Irp, + IN PRKEVENT Event) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + SIZE_T TransferLength; + PMDL Mdl; + ULONG_PTR VirtualAddr; + ULONG PagesNeed = 0; + SIZE_T PortTransferLength; + SIZE_T FullTransferLength; + PUSBPORT_TRANSFER Transfer; + PUSBPORT_PIPE_HANDLE PipeHandle; + USBD_STATUS USBDStatus; + + DPRINT_CORE("USBPORT_AllocateTransfer: FdoDevice - %p, Urb - %p, DeviceHandle - %p, Irp - %p, Event - %p\n", + FdoDevice, + Urb, + DeviceHandle, + Irp, + Event); + + FdoExtension = FdoDevice->DeviceExtension; + + TransferLength = Urb->UrbControlTransfer.TransferBufferLength; + PipeHandle = Urb->UrbControlTransfer.PipeHandle; + + if (TransferLength) + { + Mdl = Urb->UrbControlTransfer.TransferBufferMDL; + VirtualAddr = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); + + PagesNeed = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr, + TransferLength); + } + + if (Urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER) + { + DPRINT1("USBPORT_AllocateTransfer: ISOCH_TRANSFER UNIMPLEMENTED. FIXME.\n"); + } + + PortTransferLength = sizeof(USBPORT_TRANSFER) + + PagesNeed * sizeof(USBPORT_SCATTER_GATHER_ELEMENT); + + FullTransferLength = PortTransferLength + + FdoExtension->MiniPortInterface->Packet.MiniPortTransferSize; + + Transfer = ExAllocatePoolWithTag(NonPagedPool, + FullTransferLength, + USB_PORT_TAG); + + if (Transfer) + { + RtlZeroMemory(Transfer, FullTransferLength); + + Transfer->Irp = Irp; + Transfer->Urb = Urb; + Transfer->Endpoint = PipeHandle->Endpoint; + Transfer->Event = Event; + Transfer->PortTransferLength = PortTransferLength; + Transfer->FullTransferLength = FullTransferLength; + + Transfer->MiniportTransfer = (PVOID)((ULONG_PTR)Transfer + + PortTransferLength); + + Urb->UrbControlTransfer.hca.Reserved8[0] = Transfer; + Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_TRANSFER; + + USBDStatus = USBD_STATUS_SUCCESS; + } + else + { + USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES; + } + + DPRINT_CORE("USBPORT_AllocateTransfer: return USBDStatus - %x\n", + USBDStatus); + + return USBDStatus; +} + +NTSTATUS +NTAPI +USBPORT_Dispatch(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PUSBPORT_COMMON_DEVICE_EXTENSION DeviceExtension; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status = STATUS_SUCCESS; + + DeviceExtension = DeviceObject->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + + if (DeviceExtension->PnpStateFlags & USBPORT_PNP_STATE_FAILED) + { + DPRINT1("USBPORT_Dispatch: USBPORT_PNP_STATE_FAILED\n"); + DbgBreakPoint(); + } + + switch (IoStack->MajorFunction) + { + case IRP_MJ_DEVICE_CONTROL: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO IRP_MJ_DEVICE_CONTROL. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_PdoDeviceControl(DeviceObject, Irp); + } + else + { + DPRINT("USBPORT_Dispatch: FDO IRP_MJ_DEVICE_CONTROL. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_FdoDeviceControl(DeviceObject, Irp); + } + + break; + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO IRP_MJ_INTERNAL_DEVICE_CONTROL. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_PdoInternalDeviceControl(DeviceObject, Irp); + } + else + { + DPRINT("USBPORT_Dispatch: FDO IRP_MJ_INTERNAL_DEVICE_CONTROL. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_FdoInternalDeviceControl(DeviceObject, Irp); + } + + break; + + case IRP_MJ_POWER: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO IRP_MJ_POWER. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_PdoPower(DeviceObject, Irp); + } + else + { + DPRINT("USBPORT_Dispatch: FDO IRP_MJ_POWER. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_FdoPower(DeviceObject, Irp); + } + + break; + + case IRP_MJ_SYSTEM_CONTROL: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO IRP_MJ_SYSTEM_CONTROL. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + else + { + DPRINT("USBPORT_Dispatch: FDO IRP_MJ_SYSTEM_CONTROL. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + IoSkipCurrentIrpStackLocation(Irp); + Status = IoCallDriver(DeviceExtension->LowerDevice, Irp); + } + + break; + + case IRP_MJ_PNP: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO IRP_MJ_PNP. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_PdoPnP(DeviceObject, Irp); + } + else + { + DPRINT("USBPORT_Dispatch: FDO IRP_MJ_PNP. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_FdoPnP(DeviceObject, Irp); + } + + break; + + case IRP_MJ_CREATE: + case IRP_MJ_CLOSE: + DPRINT("USBPORT_Dispatch: IRP_MJ_CREATE | IRP_MJ_CLOSE\n"); + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + + default: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO unhandled IRP_MJ_???. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + } + else + { + DPRINT("USBPORT_Dispatch: FDO unhandled IRP_MJ_???. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + } + + Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + break; + } + + DPRINT("USBPORT_Dispatch: Status - %x\n", Status); + return Status; +} + +ULONG +NTAPI +USBPORT_GetHciMn(VOID) +{ + return USBPORT_HCI_MN; +} + +NTSTATUS +NTAPI +USBPORT_RegisterUSBPortDriver(IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PUSBPORT_REGISTRATION_PACKET RegPacket) +{ + PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; + + DPRINT("USBPORT_RegisterUSBPortDriver: DriverObject - %p, Version - %p, RegPacket - %p\n", + DriverObject, + Version, + RegPacket); + + DPRINT("USBPORT_RegisterUSBPortDriver: sizeof(USBPORT_MINIPORT_INTERFACE) - %x\n", + sizeof(USBPORT_MINIPORT_INTERFACE)); + + DPRINT("USBPORT_RegisterUSBPortDriver: sizeof(USBPORT_DEVICE_EXTENSION) - %x\n", + sizeof(USBPORT_DEVICE_EXTENSION)); + + if (Version < 100) // 100 - USB1.1; 200 - USB2.0 + { + return STATUS_UNSUCCESSFUL; + } + + if (!USBPORT_Initialized) + { + InitializeListHead(&USBPORT_MiniPortDrivers); + InitializeListHead(&USBPORT_USB1FdoList); + InitializeListHead(&USBPORT_USB2FdoList); + + KeInitializeSpinLock(&USBPORT_SpinLock); + USBPORT_Initialized = TRUE; + } + + MiniPortInterface = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBPORT_MINIPORT_INTERFACE), + USB_PORT_TAG); + if (!MiniPortInterface) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(MiniPortInterface, sizeof(USBPORT_MINIPORT_INTERFACE)); + + MiniPortInterface->DriverObject = DriverObject; + MiniPortInterface->DriverUnload = DriverObject->DriverUnload; + MiniPortInterface->Version = Version; + + ExInterlockedInsertTailList(&USBPORT_MiniPortDrivers, + &MiniPortInterface->DriverLink, + &USBPORT_SpinLock); + + DriverObject->DriverExtension->AddDevice = USBPORT_AddDevice; + DriverObject->DriverUnload = USBPORT_Unload; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_PNP] = USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_POWER] = USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBPORT_Dispatch; + + RegPacket->UsbPortDbgPrint = USBPORT_DbgPrint; + RegPacket->UsbPortTestDebugBreak = USBPORT_TestDebugBreak; + RegPacket->UsbPortAssertFailure = USBPORT_AssertFailure; + RegPacket->UsbPortGetMiniportRegistryKeyValue = USBPORT_GetMiniportRegistryKeyValue; + RegPacket->UsbPortInvalidateRootHub = USBPORT_InvalidateRootHub; + RegPacket->UsbPortInvalidateEndpoint = USBPORT_InvalidateEndpoint; + RegPacket->UsbPortCompleteTransfer = USBPORT_MiniportCompleteTransfer; + RegPacket->UsbPortCompleteIsoTransfer = USBPORT_CompleteIsoTransfer; + RegPacket->UsbPortLogEntry = USBPORT_LogEntry; + RegPacket->UsbPortGetMappedVirtualAddress = USBPORT_GetMappedVirtualAddress; + RegPacket->UsbPortRequestAsyncCallback = USBPORT_RequestAsyncCallback; + RegPacket->UsbPortReadWriteConfigSpace = USBPORT_ReadWriteConfigSpace; + RegPacket->UsbPortWait = USBPORT_Wait; + RegPacket->UsbPortInvalidateController = USBPORT_InvalidateController; + RegPacket->UsbPortBugCheck = USBPORT_BugCheck; + RegPacket->UsbPortNotifyDoubleBuffer = USBPORT_NotifyDoubleBuffer; + + RtlCopyMemory(&MiniPortInterface->Packet, + RegPacket, + sizeof(USBPORT_REGISTRATION_PACKET)); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + return STATUS_SUCCESS; +} diff --git a/reactos/drivers/usb/usbport/usbport.h b/reactos/drivers/usb/usbport/usbport.h new file mode 100644 index 00000000000..4771c05601c --- /dev/null +++ b/reactos/drivers/usb/usbport/usbport.h @@ -0,0 +1,1121 @@ +#ifndef USBPORT_H__ +#define USBPORT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_INTERFACE_USB_ID_UHCI 0x00 +#define PCI_INTERFACE_USB_ID_OHCI 0x10 +#define PCI_INTERFACE_USB_ID_EHCI 0x20 +#define PCI_INTERFACE_USB_ID_XHCI 0x30 + +#ifdef USBD_TRANSFER_DIRECTION // due hubbusif.h included usbdi.h (Which overwrites...) +#undef USBD_TRANSFER_DIRECTION +#define USBD_TRANSFER_DIRECTION 0x00000001 +#endif + +#define USBPORT_RECIPIENT_ROOT_HUB BMREQUEST_TO_DEVICE +#define USBPORT_RECIPIENT_ROOT_PORT BMREQUEST_TO_OTHER + +#define INVALIDATE_CONTROLLER_RESET 1 +#define INVALIDATE_CONTROLLER_SURPRISE_REMOVE 2 +#define INVALIDATE_CONTROLLER_SOFT_INTERRUPT 3 + +#define INVALIDATE_ENDPOINT_ONLY 0 +#define INVALIDATE_ENDPOINT_WORKER_THREAD 1 +#define INVALIDATE_ENDPOINT_WORKER_DPC 2 +#define INVALIDATE_ENDPOINT_INT_NEXT_SOF 3 + +#define USBPORT_DMA_DIRECTION_FROM_DEVICE 1 +#define USBPORT_DMA_DIRECTION_TO_DEVICE 2 + +#define USB_PORT_TAG 'pbsu' +#define URB_FUNCTION_MAX 0x31 + +/* Hub Class Feature Selectors (Recipient - Port) */ +#define FEATURE_PORT_CONNECTION 0 +#define FEATURE_PORT_ENABLE 1 +#define FEATURE_PORT_SUSPEND 2 +#define FEATURE_PORT_OVER_CURRENT 3 +#define FEATURE_PORT_RESET 4 +#define FEATURE_PORT_POWER 8 +#define FEATURE_PORT_LOW_SPEED 9 +#define FEATURE_C_PORT_CONNECTION 16 +#define FEATURE_C_PORT_ENABLE 17 +#define FEATURE_C_PORT_SUSPEND 18 +#define FEATURE_C_PORT_OVER_CURRENT 19 +#define FEATURE_C_PORT_RESET 20 + +/* Hub Class Feature Selectors (Recipient - Hub) */ +#define FEATURE_C_HUB_LOCAL_POWER 0 +#define FEATURE_C_HUB_OVER_CURRENT 1 + +/* Flags */ +#define USBPORT_FLAG_INT_CONNECTED 0x00000001 +#define USBPORT_FLAG_HC_STARTED 0x00000002 +#define USBPORT_FLAG_HC_POLLING 0x00000004 +#define USBPORT_FLAG_WORKER_THREAD_ON 0x00000008 +#define USBPORT_FLAG_HC_SUSPEND 0x00000100 +#define USBPORT_FLAG_INTERRUPT_ENABLED 0x00000400 +#define USBPORT_FLAG_SELECTIVE_SUSPEND 0x00000800 +#define USBPORT_FLAG_DOS_SYMBOLIC_NAME 0x00010000 +#define USBPORT_FLAG_LEGACY_SUPPORT 0x00080000 +#define USBPORT_FLAG_HC_WAKE_SUPPORT 0x00200000 +#define USBPORT_FLAG_DIAGNOSTIC_MODE 0x00800000 //IOCTL_USB_DIAGNOSTIC_MODE_ON +#define USBPORT_FLAG_COMPANION_HC 0x01000000 +#define USBPORT_FLAG_REGISTERED_FDO 0x02000000 +#define USBPORT_FLAG_NO_HACTION 0x04000000 +#define USBPORT_FLAG_BIOS_DISABLE_SS 0x08000000 //Selective Suspend +#define USBPORT_FLAG_PWR_AND_CHIRP_LOCK 0x10000000 +#define USBPORT_FLAG_POWER_AND_CHIRP_OK 0x40000000 +#define USBPORT_FLAG_RH_INIT_CALLBACK 0x80000000 + +/* PnP state Flags */ +#define USBPORT_PNP_STATE_NOT_INIT 0x00000001 +#define USBPORT_PNP_STATE_STARTED 0x00000002 +#define USBPORT_PNP_STATE_FAILED 0x00000004 +#define USBPORT_PNP_STATE_STOPPED 0x00000008 + +/* Timer Flags */ +#define USBPORT_TMFLAG_TIMER_QUEUED 0x00000001 +#define USBPORT_TMFLAG_HC_SUSPENDED 0x00000002 +#define USBPORT_TMFLAG_HC_RESUME 0x00000004 +#define USBPORT_TMFLAG_RH_SUSPENDED 0x00000008 +#define USBPORT_TMFLAG_TIMER_STARTED 0x00000010 +#define USBPORT_TMFLAG_WAKE 0x00000020 +#define USBPORT_TMFLAG_IDLE_QUEUEITEM_ON 0x00000040 + +/* Miniport Flags */ +#define USBPORT_MPFLAG_INTERRUPTS_ENABLED 0x00000001 +#define USBPORT_MPFLAG_SUSPENDED 0x00000002 + +/* Device handle Flags (USBPORT_DEVICE_HANDLE) */ +#define DEVICE_HANDLE_FLAG_ROOTHUB 0x00000002 +#define DEVICE_HANDLE_FLAG_REMOVED 0x00000008 +#define DEVICE_HANDLE_FLAG_INITIALIZED 0x00000010 + +/* Endpoint Flags (USBPORT_ENDPOINT) */ +#define ENDPOINT_FLAG_DMA_TYPE 0x00000001 +#define ENDPOINT_FLAG_ROOTHUB_EP0 0x00000002 +#define ENDPOINT_FLAG_NUKE 0x00000008 +#define ENDPOINT_FLAG_QUEUENE_EMPTY 0x00000010 +#define ENDPOINT_FLAG_ABORTING 0x00000020 +#define ENDPOINT_FLAG_IDLE 0x00000100 +#define ENDPOINT_FLAG_OPENED 0x00000200 +#define ENDPOINT_FLAG_CLOSED 0x00000400 + +/* UsbdFlags Flags (URB) */ +#define USBD_FLAG_ALLOCATED_MDL 0x00000002 +#define USBD_FLAG_NOT_ISO_TRANSFER 0x00000010 +#define USBD_FLAG_ALLOCATED_TRANSFER 0x00000020 + +/* Pipe handle Flags (USBPORT_PIPE_HANDLE) */ +#define PIPE_HANDLE_FLAG_CLOSED 0x00000001 +#define PIPE_HANDLE_FLAG_NULL_PACKET_SIZE 0x00000002 + +/* Transfer Flags (USBPORT_TRANSFER) */ +#define TRANSFER_FLAG_CANCELED 0x00000001 +#define TRANSFER_FLAG_DMA_MAPPED 0x00000002 +#define TRANSFER_FLAG_SUBMITED 0x00000008 +#define TRANSFER_FLAG_ABORTED 0x00000010 +#define TRANSFER_FLAG_ISO 0x00000020 +#define TRANSFER_FLAG_DEVICE_GONE 0x00000080 +#define TRANSFER_FLAG_SPLITED 0x00000100 + +extern KSPIN_LOCK USBPORT_SpinLock; +extern LIST_ENTRY USBPORT_MiniPortDrivers; + +typedef USBD_STATUS* PUSBD_STATUS; + +typedef struct _USBPORT_COMMON_BUFFER_HEADER { + ULONG Length; + ULONG_PTR BaseVA; + PHYSICAL_ADDRESS LogicalAddress; + SIZE_T BufferLength; + ULONG_PTR VirtualAddress; + ULONG_PTR PhysicalAddress; +} USBPORT_COMMON_BUFFER_HEADER, *PUSBPORT_COMMON_BUFFER_HEADER; + +typedef struct _USBPORT_ENDPOINT *PUSBPORT_ENDPOINT; + +typedef struct _USBPORT_PIPE_HANDLE { + ULONG Flags; + ULONG PipeFlags; + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + UCHAR Padded; + PUSBPORT_ENDPOINT Endpoint; + LIST_ENTRY PipeLink; +} USBPORT_PIPE_HANDLE, *PUSBPORT_PIPE_HANDLE; + +typedef struct _USBPORT_CONFIGURATION_HANDLE { + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + LIST_ENTRY InterfaceHandleList; + //USB_CONFIGURATION_DESCRIPTOR CfgDescriptor; // Body. +} USBPORT_CONFIGURATION_HANDLE, *PUSBPORT_CONFIGURATION_HANDLE; + +typedef struct _USBPORT_INTERFACE_HANDLE { + LIST_ENTRY InterfaceLink; + UCHAR AlternateSetting; + UCHAR Pad1[3]; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + UCHAR Pad2[3]; + USBPORT_PIPE_HANDLE PipeHandle[1]; +} USBPORT_INTERFACE_HANDLE, *PUSBPORT_INTERFACE_HANDLE; + +typedef struct _USBPORT_DEVICE_HANDLE { + ULONG Flags; + USHORT DeviceAddress; + USHORT PortNumber; + USBPORT_PIPE_HANDLE PipeHandle; + ULONG DeviceSpeed; + BOOL IsRootHub; + LIST_ENTRY PipeHandleList; + PUSBPORT_CONFIGURATION_HANDLE ConfigHandle; + struct _USBPORT_DEVICE_HANDLE *HubDeviceHandle; + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + LIST_ENTRY DeviceHandleLink; + LONG DeviceHandleLock; + ULONG TtCount; +} USBPORT_DEVICE_HANDLE, *PUSBPORT_DEVICE_HANDLE; + +typedef struct _USBPORT_ENDPOINT { + ULONG Flags; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer; + PUSBPORT_DEVICE_HANDLE DeviceHandle; + USBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG EndpointWorker; + ULONG FrameNumber; + /* Locks */ + KSPIN_LOCK EndpointSpinLock; + KIRQL EndpointOldIrql; + KIRQL EndpointStateOldIrql; + UCHAR Padded[2]; + LONG LockCounter; + LONG FlushPendingLock; + /* State */ + ULONG StateLast; + ULONG StateNext; + LIST_ENTRY StateChangeLink; + KSPIN_LOCK StateChangeSpinLock; + /* Transfer lists */ + LIST_ENTRY PendingTransferList; + LIST_ENTRY TransferList; + LIST_ENTRY CancelList; + LIST_ENTRY AbortList; + /* Links */ + LIST_ENTRY EndpointLink; + LIST_ENTRY WorkerLink; + LIST_ENTRY CloseLink; + LIST_ENTRY DispatchLink; + LIST_ENTRY FlushLink; + LIST_ENTRY FlushControllerLink; + LIST_ENTRY FlushAbortLink; +} USBPORT_ENDPOINT, *PUSBPORT_ENDPOINT; + +typedef struct _USBPORT_TRANSFER { + ULONG Flags; + PIRP Irp; + PURB Urb; + PRKEVENT Event; + PVOID MiniportTransfer; + SIZE_T PortTransferLength; // Only port part + SIZE_T FullTransferLength; // Port + miniport + PUSBPORT_ENDPOINT Endpoint; + USBPORT_TRANSFER_PARAMETERS TransferParameters; + PMDL TransferBufferMDL; + ULONG Direction; + LIST_ENTRY TransferLink; + USBD_STATUS USBDStatus; + ULONG CompletedTransferLen; + ULONG NumberOfMapRegisters; + PVOID MapRegisterBase; + ULONG TimeOut; + LARGE_INTEGER Time; + // SgList should be LAST field + USBPORT_SCATTER_GATHER_LIST SgList; // Non IsoTransfer +} USBPORT_TRANSFER, *PUSBPORT_TRANSFER; + +typedef struct _USBPORT_IRP_TABLE { + struct _USBPORT_IRP_TABLE * LinkNextTable; + PIRP irp[0X200]; +} USBPORT_IRP_TABLE, *PUSBPORT_IRP_TABLE; + +typedef struct _USBPORT_COMMON_DEVICE_EXTENSION { + PDEVICE_OBJECT SelfDevice; + PDEVICE_OBJECT LowerPdoDevice; // PhysicalDeviceObject + PDEVICE_OBJECT LowerDevice; // TopOfStackDeviceObject + ULONG IsPDO; + UNICODE_STRING SymbolicLinkName; + BOOL IsInterfaceEnabled; + DEVICE_POWER_STATE DevicePowerState; + ULONG PnpStateFlags; +} USBPORT_COMMON_DEVICE_EXTENSION, *PUSBPORT_COMMON_DEVICE_EXTENSION; + +typedef struct _USBPORT_DEVICE_EXTENSION { + USBPORT_COMMON_DEVICE_EXTENSION CommonExtension; + ULONG Flags; + PDEVICE_OBJECT RootHubPdo; // RootHubDeviceObject + KSPIN_LOCK RootHubCallbackSpinLock; + LONG RHInitCallBackLock; + LONG ChirpRootPortLock; + KSEMAPHORE ControllerSemaphore; + ULONG FdoNameNumber; + UNICODE_STRING DosDeviceSymbolicName; + ULONG UsbBIOSx; + LIST_ENTRY ControllerLink; + ULONG CommonBufferLimit; + /* Miniport */ + ULONG MiniPortFlags; + PVOID MiniPortExt; + PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; + USBPORT_RESOURCES UsbPortResources; + PUSBPORT_COMMON_BUFFER_HEADER MiniPortCommonBuffer; + KSPIN_LOCK MiniportSpinLock; + /* Bus Interface */ + BUS_INTERFACE_STANDARD BusInterface; + USHORT VendorID; + USHORT DeviceID; + UCHAR RevisionID; + UCHAR ProgIf; + UCHAR SubClass; + UCHAR BaseClass; + /* Dma Adapter */ + PDMA_ADAPTER DmaAdapter; + ULONG NumberMapRegs; + /* Interrupt */ + PKINTERRUPT InterruptObject; + KDPC IsrDpc; + LONG IsrDpcCounter; + LONG IsrDpcHandlerCounter; + KSPIN_LOCK MiniportInterruptsSpinLock; + KTIMER TimerSoftInterrupt; + KDPC SoftInterruptDpc; + /* Endpoints */ + ULONG PeriodicEndpoints; + LIST_ENTRY EndpointList; + KSPIN_LOCK EndpointListSpinLock; + LIST_ENTRY EpStateChangeList; + KSPIN_LOCK EpStateChangeSpinLock; + LIST_ENTRY EndpointClosedList; + KSPIN_LOCK EndpointClosedSpinLock; + LIST_ENTRY WorkerList; + /* Transfers */ + LIST_ENTRY MapTransferList; + KSPIN_LOCK MapTransferSpinLock; + LIST_ENTRY DoneTransferList; + KSPIN_LOCK DoneTransferSpinLock; + KDPC TransferFlushDpc; + KSPIN_LOCK FlushTransferSpinLock; + KSPIN_LOCK FlushPendingTransferSpinLock; + /* Timer */ + ULONG TimerValue; // Timer period (500) msec. default + ULONG TimerFlags; + KTIMER TimerObject; + KDPC TimerDpc; + KSPIN_LOCK TimerFlagsSpinLock; + /* Worker Thread */ + PRKTHREAD WorkerThread; + HANDLE WorkerThreadHandle; + KEVENT WorkerThreadEvent; + KSPIN_LOCK WorkerThreadEventSpinLock; + /* Usb Devices */ + ULONG UsbAddressBitMap[4]; + LIST_ENTRY DeviceHandleList; + KSPIN_LOCK DeviceHandleSpinLock; + KSEMAPHORE DeviceSemaphore; + /* Device Capabilities */ + DEVICE_CAPABILITIES Capabilities; + ULONG BusNumber; + ULONG PciDeviceNumber; + ULONG PciFunctionNumber; + ULONG TotalBusBandwidth; + /* Idle */ + LARGE_INTEGER IdleTime; + IO_CSQ IdleIoCsq; + KSPIN_LOCK IdleIoCsqSpinLock; + LIST_ENTRY IdleIrpList; + LONG IdleLockCounter; + /* Bad Requests */ + IO_CSQ BadRequestIoCsq; + KSPIN_LOCK BadRequestIoCsqSpinLock; + LIST_ENTRY BadRequestList; + LONG BadRequestLockCounter; + /* Irp Queues */ + PUSBPORT_IRP_TABLE PendingIrpTable; + PUSBPORT_IRP_TABLE ActiveIrpTable; + /* Power */ + LONG SetPowerLockCounter; + KSPIN_LOCK PowerWakeSpinLock; + KSPIN_LOCK SetPowerD0SpinLock; + KDPC WorkerRequestDpc; + KDPC HcWakeDpc; + ULONG Padded[34]; // Miniport extension should be aligned on 0x100 +} USBPORT_DEVICE_EXTENSION, *PUSBPORT_DEVICE_EXTENSION; + +C_ASSERT(sizeof(USBPORT_DEVICE_EXTENSION) == 0x400); + +typedef struct _USBPORT_RH_DESCRIPTORS { + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + USB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USB_ENDPOINT_DESCRIPTOR EndPointDescriptor; + USB_HUB_DESCRIPTOR Descriptor; // Size may be: 7 + 2[1..32] (7 + 2..64) +} USBPORT_RH_DESCRIPTORS, *PUSBPORT_RH_DESCRIPTORS; + +typedef struct _USBPORT_RHDEVICE_EXTENSION { + USBPORT_COMMON_DEVICE_EXTENSION CommonExtension; + ULONG Flags; + PDEVICE_OBJECT FdoDevice; + ULONG PdoNameNumber; + USBPORT_DEVICE_HANDLE DeviceHandle; + PUSBPORT_RH_DESCRIPTORS RootHubDescriptors; + PUSBPORT_ENDPOINT Endpoint; + ULONG ConfigurationValue; + PRH_INIT_CALLBACK RootHubInitCallback; + PVOID RootHubInitContext; + DEVICE_CAPABILITIES Capabilities; + PIRP WakeIrp; +} USBPORT_RHDEVICE_EXTENSION, *PUSBPORT_RHDEVICE_EXTENSION; + +typedef struct _USBPORT_ASYNC_CALLBACK_DATA { + ULONG Reserved; + PDEVICE_OBJECT FdoDevice; + KTIMER AsyncTimer; + KDPC AsyncTimerDpc; + ASYNC_TIMER_CALLBACK *CallbackFunction; + ULONG CallbackContext; +} USBPORT_ASYNC_CALLBACK_DATA, *PUSBPORT_ASYNC_CALLBACK_DATA; + +C_ASSERT(sizeof(USBPORT_ASYNC_CALLBACK_DATA) == 88); + +typedef struct _TIMER_WORK_QUEUE_ITEM { + WORK_QUEUE_ITEM WqItem; + PDEVICE_OBJECT FdoDevice; + ULONG Context; +} TIMER_WORK_QUEUE_ITEM, *PTIMER_WORK_QUEUE_ITEM; + +/* usbport.c */ +NTSTATUS +NTAPI +USBPORT_USBDStatusToNtStatus( + IN PURB Urb, + IN USBD_STATUS USBDStatus); + +NTSTATUS +NTAPI +USBPORT_Wait( + IN PVOID Context, + IN ULONG Milliseconds); + +VOID +NTAPI +USBPORT_TransferFlushDpc( + IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +NTSTATUS +NTAPI +USBPORT_CreateWorkerThread( + IN PDEVICE_OBJECT FdoDevice); + +BOOLEAN +NTAPI +USBPORT_StartTimer( + IN PDEVICE_OBJECT FdoDevice, + IN ULONG Time); + +PUSBPORT_COMMON_BUFFER_HEADER +NTAPI +USBPORT_AllocateCommonBuffer( + IN PDEVICE_OBJECT FdoDevice, + IN SIZE_T BufferLength); + +VOID +NTAPI +USBPORT_FreeCommonBuffer( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer); + +USBD_STATUS +NTAPI +USBPORT_AllocateTransfer( + IN PDEVICE_OBJECT FdoDevice, + IN PURB Urb, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PIRP Irp, + IN PRKEVENT Event); + +VOID +NTAPI +USBPORT_FlushMapTransfers( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_IsrDpc( + IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +BOOLEAN +NTAPI +USBPORT_InterruptService( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext); + +VOID +NTAPI +USBPORT_SignalWorkerThread( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_CompleteTransfer( + IN PURB Urb, + IN USBD_STATUS TransferStatus); + +VOID +NTAPI +USBPORT_DpcHandler( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_WorkerRequestDpc( + IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +BOOLEAN +NTAPI +USBPORT_QueueDoneTransfer( + IN PUSBPORT_TRANSFER Transfer, + IN USBD_STATUS USBDStatus); + +VOID +NTAPI +USBPORT_MiniportInterrupts( + IN PDEVICE_OBJECT FdoDevice, + IN BOOLEAN IsEnable); + +NTSTATUS +NTAPI +USBPORT_SetRegistryKeyValue( + IN PDEVICE_OBJECT DeviceObject, + IN BOOL UseDriverKey, + IN ULONG Type, + IN PCWSTR ValueNameString, + IN PVOID Data, + IN ULONG DataSize); + +NTSTATUS +NTAPI +USBPORT_GetRegistryKeyValueFullInfo( + IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice, + IN BOOL UseDriverKey, + IN PCWSTR SourceString, + IN ULONG LengthStr, + IN PVOID Buffer, + IN ULONG NumberOfBytes); + +VOID +NTAPI +USBPORT_AddUSB1Fdo( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_AddUSB2Fdo( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_RemoveUSBxFdo( + IN PDEVICE_OBJECT FdoDevice); + +PDEVICE_OBJECT +NTAPI +USBPORT_FindUSB2Controller( + IN PDEVICE_OBJECT FdoDevice); + +PDEVICE_RELATIONS +NTAPI +USBPORT_FindCompanionControllers( + IN PDEVICE_OBJECT USB2FdoDevice, + IN BOOLEAN IsObRefer, + IN BOOLEAN IsFDOsReturned); + +VOID +NTAPI +USBPORT_InvalidateControllerHandler( + IN PDEVICE_OBJECT FdoDevice, + IN ULONG Type); + +/* debug.c */ +ULONG +NTAPI +USBPORT_DbgPrint( + IN PVOID Context, + IN ULONG Level, + IN PCH Format, + ...); + +ULONG +NTAPI +USBPORT_TestDebugBreak( + IN PVOID Context); + +ULONG +NTAPI +USBPORT_AssertFailure( + PVOID Context, + PVOID FailedAssertion, + PVOID FileName, + ULONG LineNumber, + PCHAR Message); + +VOID +NTAPI +USBPORT_BugCheck( + IN PVOID Context); + +ULONG +NTAPI +USBPORT_LogEntry( + IN PVOID BusContext, + IN ULONG DriverTag, + IN ULONG EnumTag, + IN ULONG P1, + IN ULONG P2, + IN ULONG P3); + +VOID +NTAPI +USBPORT_DumpingDeviceDescriptor( + IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor); + +VOID +NTAPI +USBPORT_DumpingConfiguration( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor); + +VOID +NTAPI +USBPORT_DumpingCapabilities( + IN PDEVICE_CAPABILITIES Capabilities); + +VOID +NTAPI +USBPORT_DumpingSetupPacket( + IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket); + +VOID +NTAPI +USBPORT_DumpingURB( + IN PURB Urb); + +VOID +NTAPI +USBPORT_DumpingIDs( + IN PVOID Buffer); + +/* device.c */ +NTSTATUS +NTAPI +USBPORT_HandleSelectConfiguration( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb); + +VOID +NTAPI +USBPORT_AddDeviceHandle( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle); + +VOID +NTAPI +USBPORT_RemoveDeviceHandle( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle); + +BOOLEAN +NTAPI +USBPORT_ValidateDeviceHandle( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle); + +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); + +NTSTATUS +NTAPI +USBPORT_InitializeDevice( + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PDEVICE_OBJECT FdoDevice); + +NTSTATUS +NTAPI +USBPORT_GetUsbDescriptor( + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PDEVICE_OBJECT FdoDevice, + IN UCHAR Type, + IN PUCHAR ConfigDesc, + IN PULONG ConfigDescSize); + +NTSTATUS +NTAPI +USBPORT_HandleSelectInterface( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN PURB Urb); + +NTSTATUS +NTAPI +USBPORT_RemoveDevice( + IN PDEVICE_OBJECT FdoDevice, + IN OUT PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN ULONG Flags); + +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); + +NTSTATUS +NTAPI +USBPORT_RestoreDevice( + IN PDEVICE_OBJECT FdoDevice, + IN OUT PUSBPORT_DEVICE_HANDLE OldDeviceHandle, + IN OUT PUSBPORT_DEVICE_HANDLE NewDeviceHandle); + +NTSTATUS +NTAPI +USBPORT_Initialize20Hub( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_DEVICE_HANDLE HubDeviceHandle, + IN ULONG TtCount); + +/* endpoint.c */ +NTSTATUS +NTAPI +USBPORT_OpenPipe( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle, + IN PUSBD_STATUS UsbdStatus); + +MPSTATUS +NTAPI +MiniportOpenEndpoint( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint); + +NTSTATUS +NTAPI +USBPORT_ReopenPipe( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint); + +VOID +NTAPI +USBPORT_ClosePipe( + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_PIPE_HANDLE PipeHandle); + +VOID +NTAPI +MiniportCloseEndpoint( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint); + +VOID +NTAPI +USBPORT_AddPipeHandle( + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle); + +VOID +NTAPI +USBPORT_RemovePipeHandle( + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle); + +BOOLEAN +NTAPI +USBPORT_ValidatePipeHandle( + IN PUSBPORT_DEVICE_HANDLE DeviceHandle, + IN PUSBPORT_PIPE_HANDLE PipeHandle); + +VOID +NTAPI +USBPORT_FlushClosedEndpointList( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_SetEndpointState( + IN PUSBPORT_ENDPOINT Endpoint, + IN ULONG State); + +ULONG +NTAPI +USBPORT_GetEndpointState( + IN PUSBPORT_ENDPOINT Endpoint); + +VOID +NTAPI +USBPORT_InvalidateEndpointHandler( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint, + IN ULONG Type); + +BOOLEAN +NTAPI +USBPORT_EndpointWorker( + IN PUSBPORT_ENDPOINT Endpoint, + IN BOOLEAN Flag); + +VOID +NTAPI +USBPORT_NukeAllEndpoints( + IN PDEVICE_OBJECT FdoDevice); + +BOOLEAN +NTAPI +USBPORT_EndpointHasQueuedTransfers( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint, + IN PULONG TransferCount); + +/* iface.c */ +NTSTATUS +NTAPI +USBPORT_PdoQueryInterface( + IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp); + +/* ioctl.c */ +NTSTATUS +NTAPI +USBPORT_PdoDeviceControl( + PDEVICE_OBJECT PdoDevice, + PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_FdoDeviceControl( + PDEVICE_OBJECT FdoDevice, + PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_FdoInternalDeviceControl( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_PdoInternalDeviceControl( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_GetSymbolicName( + IN PDEVICE_OBJECT RootHubPdo, + IN PUNICODE_STRING DestinationString); + +/* pnp.c */ +NTSTATUS +NTAPI +USBPORT_FdoPnP( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_PdoPnP( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +/* power.c */ +NTSTATUS +NTAPI +USBPORT_PdoPower( + IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_FdoPower( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +NTSTATUS +NTAPI +USBPORT_IdleNotification( + IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_AdjustDeviceCapabilities( + IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice); + +VOID +NTAPI +USBPORT_DoIdleNotificationCallback( + IN PVOID Context); + +VOID +NTAPI +USBPORT_CompletePdoWaitWake( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_DoSetPowerD0( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_HcWakeDpc( + IN PRKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +VOID +NTAPI +USBPORT_HcQueueWakeDpc( + IN PDEVICE_OBJECT FdoDevice); + +/* queue.c */ +VOID +NTAPI +USBPORT_InsertIdleIrp( + IN PIO_CSQ Csq, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_RemoveIdleIrp( + IN PIO_CSQ Csq, + IN PIRP Irp); + +PIRP +NTAPI +USBPORT_PeekNextIdleIrp( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext); + +VOID +NTAPI +USBPORT_AcquireIdleLock( + IN PIO_CSQ Csq, + IN PKIRQL Irql); + +VOID +NTAPI +USBPORT_ReleaseIdleLock( + IN PIO_CSQ Csq, + IN KIRQL Irql); + +VOID +NTAPI +USBPORT_CompleteCanceledIdleIrp( + IN PIO_CSQ Csq, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_InsertBadRequest( + IN PIO_CSQ Csq, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_RemoveBadRequest( + IN PIO_CSQ Csq, + IN PIRP Irp); + +PIRP +NTAPI +USBPORT_PeekNextBadRequest( + IN PIO_CSQ Csq, + IN PIRP Irp, + IN PVOID PeekContext); + +VOID +NTAPI +USBPORT_AcquireBadRequestLock( + IN PIO_CSQ Csq, + IN PKIRQL Irql); + +VOID +NTAPI +USBPORT_ReleaseBadRequestLock( + IN PIO_CSQ Csq, + IN KIRQL Irql); + +VOID +NTAPI +USBPORT_CompleteCanceledBadRequest( + IN PIO_CSQ Csq, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_InsertIrpInTable( + IN PUSBPORT_IRP_TABLE IrpTable, + IN PIRP Irp); + +PIRP +NTAPI +USBPORT_RemovePendingTransferIrp( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +PIRP +NTAPI +USBPORT_RemoveActiveTransferIrp( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_FindUrbInIrpTable( + IN PUSBPORT_IRP_TABLE IrpTable, + IN PURB Urb, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_CancelActiveTransferIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +VOID +NTAPI +USBPORT_FlushAbortList( + IN PUSBPORT_ENDPOINT Endpoint); + +VOID +NTAPI +USBPORT_FlushCancelList( + IN PUSBPORT_ENDPOINT Endpoint); + +VOID +NTAPI +USBPORT_QueueTransferUrb( + IN PURB Urb); + +VOID +NTAPI +USBPORT_FlushAllEndpoints( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_FlushPendingTransfers( + IN PUSBPORT_ENDPOINT Endpoint); + +BOOLEAN +NTAPI +USBPORT_QueueActiveUrbToEndpoint( + IN PUSBPORT_ENDPOINT Endpoint, + IN PURB Urb); + +VOID +NTAPI +USBPORT_FlushController( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_BadRequestFlush( + IN PDEVICE_OBJECT FdoDevice); + +VOID +NTAPI +USBPORT_AbortEndpoint( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint, + IN PIRP Irp); + +/* roothub.c */ +VOID +NTAPI +USBPORT_RootHubEndpointWorker( + PUSBPORT_ENDPOINT Endpoint); + +NTSTATUS +NTAPI +USBPORT_RootHubCreateDevice( + IN PDEVICE_OBJECT FdoDevice, + IN PDEVICE_OBJECT PdoDevice); + +ULONG +NTAPI +USBPORT_InvalidateRootHub( + PVOID Context); + +VOID +NTAPI +USBPORT_RootHubPowerAndChirpAllCcPorts( + IN PDEVICE_OBJECT FdoDevice); + +/* urb.c */ +NTSTATUS +NTAPI +USBPORT_HandleSubmitURB( + IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp, + IN PURB Urb); + +/* usb2.c */ +BOOLEAN +NTAPI +USBPORT_AllocateBandwidthUSB2( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint); + +VOID +NTAPI +USBPORT_FreeBandwidthUSB2( + IN PDEVICE_OBJECT FdoDevice, + IN PUSBPORT_ENDPOINT Endpoint); + +#endif /* USBPORT_H__ */ diff --git a/reactos/drivers/usb/usbport/usbport.rc b/reactos/drivers/usb/usbport/usbport.rc new file mode 100644 index 00000000000..15fc80168b2 --- /dev/null +++ b/reactos/drivers/usb/usbport/usbport.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB bus driver extension" +#define REACTOS_STR_INTERNAL_NAME "usbport" +#define REACTOS_STR_ORIGINAL_FILENAME "usbport.sys" +#include diff --git a/reactos/drivers/usb/usbport/usbport.spec b/reactos/drivers/usb/usbport/usbport.spec new file mode 100644 index 00000000000..dbe80be1ca7 --- /dev/null +++ b/reactos/drivers/usb/usbport/usbport.spec @@ -0,0 +1,2 @@ +@ stdcall USBPORT_GetHciMn() +@ stdcall USBPORT_RegisterUSBPortDriver(ptr long ptr) \ No newline at end of file diff --git a/reactos/sdk/include/reactos/drivers/usbport/usbmport.h b/reactos/sdk/include/reactos/drivers/usbport/usbmport.h new file mode 100644 index 00000000000..7cf214b32ba --- /dev/null +++ b/reactos/sdk/include/reactos/drivers/usbport/usbmport.h @@ -0,0 +1,653 @@ +#ifndef USBMPORT_H__ +#define USBMPORT_H__ + +#define USBPORT_HCI_MN 0x10000001 + +/* Tranfer types */ +#define USBPORT_TRANSFER_TYPE_ISOCHRONOUS 0 +#define USBPORT_TRANSFER_TYPE_CONTROL 1 +#define USBPORT_TRANSFER_TYPE_BULK 2 +#define USBPORT_TRANSFER_TYPE_INTERRUPT 3 + +/* Endpoint states */ +#define USBPORT_ENDPOINT_UNKNOWN 0 +#define USBPORT_ENDPOINT_PAUSED 2 +#define USBPORT_ENDPOINT_ACTIVE 3 +#define USBPORT_ENDPOINT_REMOVE 4 +#define USBPORT_ENDPOINT_CLOSED 5 + +/* Endpoint status */ +#define USBPORT_ENDPOINT_RUN 0 +#define USBPORT_ENDPOINT_HALT 1 +#define USBPORT_ENDPOINT_CONTROL 4 + +/* Types of resources. For USBPORT_RESOURCES::ResourcesTypes */ +#define USBPORT_RESOURCES_PORT 1 +#define USBPORT_RESOURCES_INTERRUPT 2 +#define USBPORT_RESOURCES_MEMORY 4 + +typedef struct _USBPORT_RESOURCES { + ULONG ResourcesTypes; + ULONG HcFlavor; + ULONG InterruptVector; + KIRQL InterruptLevel; + UCHAR Padded1[3]; + KAFFINITY InterruptAffinity; + BOOLEAN ShareVector; + UCHAR Padded2[3]; + KINTERRUPT_MODE InterruptMode; + ULONG Reserved; + PVOID ResourceBase; + SIZE_T IoSpaceLength; + PVOID StartVA; + PVOID StartPA; + UCHAR LegacySupport; + BOOLEAN IsChirpHandled; + UCHAR Reserved2; + UCHAR Reserved3; +} USBPORT_RESOURCES, *PUSBPORT_RESOURCES; + +C_ASSERT(sizeof(USBPORT_RESOURCES) == 52); + +typedef ULONG MPSTATUS; // Miniport status +typedef ULONG RHSTATUS; // Roothub status + +#define MP_STATUS_SUCCESS 0 +#define MP_STATUS_FAILURE 1 +#define MP_STATUS_NO_RESOURCES 2 +#define MP_STATUS_NO_BANDWIDTH 3 +#define MP_STATUS_ERROR 4 +#define MP_STATUS_RESERVED1 5 +#define MP_STATUS_NOT_SUPPORTED 6 +#define MP_STATUS_HW_ERROR 7 +#define MP_STATUS_UNSUCCESSFUL 8 + +#define RH_STATUS_SUCCESS 0 +#define RH_STATUS_NO_CHANGES 1 +#define RH_STATUS_UNSUCCESSFUL 2 + +typedef USB_20_PORT_CHANGE USB_PORT_STATUS_CHANGE; + +typedef union _USBHUB_PORT_STATUS { +struct { + USB_PORT_STATUS UsbPortStatus; + USB_PORT_STATUS_CHANGE UsbPortStatusChange; + }; + ULONG AsULONG; +} USBHUB_PORT_STATUS, *PUSBHUB_PORT_STATUS; + +/* Hub status & hub status change bits. + See USB 2.0 spec Table 11-19 and Table 11-20. */ +#define HUB_STATUS_CHANGE_LOCAL_POWER 0x00010000 +#define HUB_STATUS_CHANGE_OVERCURRENT 0x00020000 + +/* Additional USB Class Codes from USB.org */ +#define USBC_DEVICE_CLASS_AUDIO_VIDEO 0x10 +#define USBC_DEVICE_CLASS_BILLBOARD 0x11 +#define USBC_DEVICE_CLASS_TYPE_C_BRIDGE 0x12 + +/* Miniport functions */ +typedef MPSTATUS +(NTAPI *PHCI_OPEN_ENDPOINT)( + PVOID, + PVOID, + PVOID); + +typedef MPSTATUS +(NTAPI *PHCI_REOPEN_ENDPOINT)( + PVOID, + PVOID, + PVOID); + +typedef VOID +(NTAPI *PHCI_QUERY_ENDPOINT_REQUIREMENTS)( + PVOID, + PVOID, + PULONG); + +typedef VOID +(NTAPI *PHCI_CLOSE_ENDPOINT)( + PVOID, + PVOID, + BOOLEAN); + +typedef MPSTATUS +(NTAPI *PHCI_START_CONTROLLER)( + PVOID, + PUSBPORT_RESOURCES); + +typedef VOID +(NTAPI *PHCI_STOP_CONTROLLER)( + PVOID, + BOOLEAN); + +typedef VOID +(NTAPI *PHCI_SUSPEND_CONTROLLER)(PVOID); + +typedef MPSTATUS +(NTAPI *PHCI_RESUME_CONTROLLER)(PVOID); + +typedef BOOLEAN +(NTAPI *PHCI_INTERRUPT_SERVICE)(PVOID); + +typedef VOID +(NTAPI *PHCI_INTERRUPT_DPC)( + PVOID, + BOOLEAN); + +typedef MPSTATUS +(NTAPI *PHCI_SUBMIT_TRANSFER)( + PVOID, + PVOID, + PVOID, + PVOID, + PVOID); + +typedef MPSTATUS +(NTAPI *PHCI_SUBMIT_ISO_TRANSFER)( + PVOID, + PVOID, + PVOID, + PVOID, + PVOID); + +typedef VOID +(NTAPI *PHCI_ABORT_TRANSFER)( + PVOID, + PVOID, + PVOID, + PULONG); + +typedef ULONG +(NTAPI *PHCI_GET_ENDPOINT_STATE)( + PVOID, + PVOID); + +typedef VOID +(NTAPI *PHCI_SET_ENDPOINT_STATE)( + PVOID, + PVOID, + ULONG); + +typedef VOID +(NTAPI *PHCI_POLL_ENDPOINT)( + PVOID, + PVOID); + +typedef VOID +(NTAPI *PHCI_CHECK_CONTROLLER)(PVOID); + +typedef ULONG +(NTAPI *PHCI_GET_32BIT_FRAME_NUMBER)(PVOID); + +typedef VOID +(NTAPI *PHCI_INTERRUPT_NEXT_SOF)(PVOID); + +typedef VOID +(NTAPI *PHCI_ENABLE_INTERRUPTS)(PVOID); + +typedef VOID +(NTAPI *PHCI_DISABLE_INTERRUPTS)(PVOID); + +typedef VOID +(NTAPI *PHCI_POLL_CONTROLLER)(PVOID); + +typedef VOID +(NTAPI *PHCI_SET_ENDPOINT_DATA_TOGGLE)( + PVOID, + PVOID, + ULONG); + +typedef ULONG +(NTAPI *PHCI_GET_ENDPOINT_STATUS)( + PVOID, + PVOID); + +typedef VOID +(NTAPI *PHCI_SET_ENDPOINT_STATUS)( + PVOID, + PVOID, + ULONG); + +typedef VOID +(NTAPI *PHCI_RESET_CONTROLLER)(PVOID); + +/* Roothub functions */ +typedef VOID +(NTAPI *PHCI_RH_GET_ROOT_HUB_DATA)( + PVOID, + PVOID); + +typedef MPSTATUS +(NTAPI *PHCI_RH_GET_STATUS)( + PVOID, + PUSHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_GET_PORT_STATUS)( + PVOID, + USHORT, + PUSBHUB_PORT_STATUS); + +typedef MPSTATUS +(NTAPI *PHCI_RH_GET_HUB_STATUS)( + PVOID, + PUSB_HUB_STATUS); + +typedef MPSTATUS +(NTAPI *PHCI_RH_SET_FEATURE_PORT_RESET)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_SET_FEATURE_PORT_POWER)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_SET_FEATURE_PORT_ENABLE)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_SET_FEATURE_PORT_SUSPEND)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_ENABLE)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_POWER)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_SUSPEND)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_ENABLE_CHANGE)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_CONNECT_CHANGE)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_RESET_CHANGE)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_SUSPEND_CHANGE)( + PVOID, + USHORT); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CLEAR_FEATURE_PORT_OVERCURRENT_CHANGE)( + PVOID, + USHORT); + +typedef VOID +(NTAPI *PHCI_RH_DISABLE_IRQ)(PVOID); + +typedef VOID +(NTAPI *PHCI_RH_ENABLE_IRQ)(PVOID); + +/* Miniport ioctl functions */ +typedef MPSTATUS +(NTAPI *PHCI_START_SEND_ONE_PACKET)( + PVOID, + PVOID, + PVOID, + PULONG, + PVOID, + PVOID, + ULONG, + USBD_STATUS *); + +typedef MPSTATUS +(NTAPI *PHCI_END_SEND_ONE_PACKET)( + PVOID, + PVOID, + PVOID, + PULONG, + PVOID, + PVOID, + ULONG, + USBD_STATUS *); + +typedef MPSTATUS +(NTAPI *PHCI_PASS_THRU)( + PVOID, + PVOID, + ULONG, + PVOID); + +/* Port functions */ +typedef ULONG +(NTAPI *PUSBPORT_DBG_PRINT)( + PVOID, + ULONG, + PCH, + ...); + +typedef ULONG +(NTAPI *PUSBPORT_TEST_DEBUG_BREAK)(PVOID); + +typedef ULONG +(NTAPI *PUSBPORT_ASSERT_FAILURE)( + PVOID, + PVOID, + PVOID, + ULONG, + PCHAR); + +typedef MPSTATUS +(NTAPI *PUSBPORT_GET_MINIPORT_REGISTRY_KEY_VALUE)( + PVOID, + BOOL, + PCWSTR, + SIZE_T, + PVOID, + SIZE_T); + +typedef ULONG +(NTAPI *PUSBPORT_INVALIDATE_ROOT_HUB)(PVOID); + +typedef ULONG +(NTAPI *PUSBPORT_INVALIDATE_ENDPOINT)( + PVOID, + PVOID); + +typedef ULONG +(NTAPI *PUSBPORT_COMPLETE_TRANSFER)( + PVOID, + PVOID, + PVOID, + USBD_STATUS, + SIZE_T); + +typedef ULONG +(NTAPI *PUSBPORT_COMPLETE_ISO_TRANSFER)( + PVOID, + PVOID, + PVOID, + ULONG); + +typedef ULONG +(NTAPI *PUSBPORT_LOG_ENTRY)( + PVOID, + ULONG, + ULONG, + ULONG, + ULONG, + ULONG); + +typedef PVOID +(NTAPI *PUSBPORT_GET_MAPPED_VIRTUAL_ADDRESS)( + PVOID, + PVOID, + PVOID); + +typedef VOID +(NTAPI ASYNC_TIMER_CALLBACK)( + IN PVOID MiniportExtension, + IN PVOID CallBackContext); + +typedef ULONG +(NTAPI *PUSBPORT_REQUEST_ASYNC_CALLBACK)( + PVOID, + ULONG, + PVOID, + SIZE_T, + ASYNC_TIMER_CALLBACK *); + +typedef MPSTATUS +(NTAPI *PUSBPORT_READ_WRITE_CONFIG_SPACE)( + PVOID, + BOOLEAN, + PVOID, + ULONG, + ULONG); + +typedef NTSTATUS +(NTAPI *PUSBPORT_WAIT)( + PVOID, + ULONG); + +typedef ULONG +(NTAPI *PUSBPORT_INVALIDATE_CONTROLLER)( + PVOID, + ULONG); + +typedef VOID +(NTAPI *PUSBPORT_BUG_CHECK)(PVOID); + +typedef ULONG +(NTAPI *PUSBPORT_NOTIFY_DOUBLE_BUFFER)( + PVOID, + PVOID, + PVOID, + SIZE_T); + +/* Miniport functions */ +typedef VOID +(NTAPI *PHCI_REBALANCE_ENDPOINT)( + PVOID, + PVOID, + PVOID); + +typedef VOID +(NTAPI *PHCI_FLUSH_INTERRUPTS)(PVOID); + +typedef MPSTATUS +(NTAPI *PHCI_RH_CHIRP_ROOT_PORT)( + PVOID, + USHORT); + +typedef VOID +(NTAPI *PHCI_TAKE_PORT_CONTROL)(PVOID); + +#define USB_MINIPORT_VERSION_OHCI 0x01 +#define USB_MINIPORT_VERSION_UHCI 0x02 +#define USB_MINIPORT_VERSION_EHCI 0x03 + +#define USB_MINIPORT_FLAGS_INTERRUPT 0x0001 +#define USB_MINIPORT_FLAGS_PORT_IO 0x0002 +#define USB_MINIPORT_FLAGS_MEMORY_IO 0x0004 +#define USB_MINIPORT_FLAGS_USB2 0x0010 +#define USB_MINIPORT_FLAGS_DISABLE_SS 0x0020 +#define USB_MINIPORT_FLAGS_NOT_LOCK_INT 0x0040 +#define USB_MINIPORT_FLAGS_POLLING 0x0080 +#define USB_MINIPORT_FLAGS_NO_DMA 0x0100 +#define USB_MINIPORT_FLAGS_WAKE_SUPPORT 0x0200 + +typedef struct _USBPORT_REGISTRATION_PACKET { + ULONG MiniPortVersion; + ULONG MiniPortFlags; + ULONG MiniPortBusBandwidth; + ULONG Reserved1; + SIZE_T MiniPortExtensionSize; + SIZE_T MiniPortEndpointSize; + SIZE_T MiniPortTransferSize; + ULONG Reserved2; + ULONG Reserved3; + SIZE_T MiniPortResourcesSize; + + /* Miniport */ + PHCI_OPEN_ENDPOINT OpenEndpoint; + PHCI_REOPEN_ENDPOINT ReopenEndpoint; + PHCI_QUERY_ENDPOINT_REQUIREMENTS QueryEndpointRequirements; + PHCI_CLOSE_ENDPOINT CloseEndpoint; + PHCI_START_CONTROLLER StartController; + PHCI_STOP_CONTROLLER StopController; + PHCI_SUSPEND_CONTROLLER SuspendController; + PHCI_RESUME_CONTROLLER ResumeController; + PHCI_INTERRUPT_SERVICE InterruptService; + PHCI_INTERRUPT_DPC InterruptDpc; + PHCI_SUBMIT_TRANSFER SubmitTransfer; + PHCI_SUBMIT_ISO_TRANSFER SubmitIsoTransfer; + PHCI_ABORT_TRANSFER AbortTransfer; + PHCI_GET_ENDPOINT_STATE GetEndpointState; + PHCI_SET_ENDPOINT_STATE SetEndpointState; + PHCI_POLL_ENDPOINT PollEndpoint; + PHCI_CHECK_CONTROLLER CheckController; + PHCI_GET_32BIT_FRAME_NUMBER Get32BitFrameNumber; + PHCI_INTERRUPT_NEXT_SOF InterruptNextSOF; + PHCI_ENABLE_INTERRUPTS EnableInterrupts; + PHCI_DISABLE_INTERRUPTS DisableInterrupts; + PHCI_POLL_CONTROLLER PollController; + PHCI_SET_ENDPOINT_DATA_TOGGLE SetEndpointDataToggle; + PHCI_GET_ENDPOINT_STATUS GetEndpointStatus; + PHCI_SET_ENDPOINT_STATUS SetEndpointStatus; + PHCI_RESET_CONTROLLER ResetController; + + /* Roothub */ + PHCI_RH_GET_ROOT_HUB_DATA RH_GetRootHubData; + PHCI_RH_GET_STATUS RH_GetStatus; + PHCI_RH_GET_PORT_STATUS RH_GetPortStatus; + PHCI_RH_GET_HUB_STATUS RH_GetHubStatus; + PHCI_RH_SET_FEATURE_PORT_RESET RH_SetFeaturePortReset; + PHCI_RH_SET_FEATURE_PORT_POWER RH_SetFeaturePortPower; + PHCI_RH_SET_FEATURE_PORT_ENABLE RH_SetFeaturePortEnable; + PHCI_RH_SET_FEATURE_PORT_SUSPEND RH_SetFeaturePortSuspend; + PHCI_RH_CLEAR_FEATURE_PORT_ENABLE RH_ClearFeaturePortEnable; + PHCI_RH_CLEAR_FEATURE_PORT_POWER RH_ClearFeaturePortPower; + PHCI_RH_CLEAR_FEATURE_PORT_SUSPEND RH_ClearFeaturePortSuspend; + PHCI_RH_CLEAR_FEATURE_PORT_ENABLE_CHANGE RH_ClearFeaturePortEnableChange; + PHCI_RH_CLEAR_FEATURE_PORT_CONNECT_CHANGE RH_ClearFeaturePortConnectChange; + PHCI_RH_CLEAR_FEATURE_PORT_RESET_CHANGE RH_ClearFeaturePortResetChange; + PHCI_RH_CLEAR_FEATURE_PORT_SUSPEND_CHANGE RH_ClearFeaturePortSuspendChange; + PHCI_RH_CLEAR_FEATURE_PORT_OVERCURRENT_CHANGE RH_ClearFeaturePortOvercurrentChange; + PHCI_RH_DISABLE_IRQ RH_DisableIrq; + PHCI_RH_ENABLE_IRQ RH_EnableIrq; + + /* Miniport ioctl */ + PHCI_START_SEND_ONE_PACKET StartSendOnePacket; + PHCI_END_SEND_ONE_PACKET EndSendOnePacket; + PHCI_PASS_THRU PassThru; + + /* Port */ + PUSBPORT_DBG_PRINT UsbPortDbgPrint; + PUSBPORT_TEST_DEBUG_BREAK UsbPortTestDebugBreak; + PUSBPORT_ASSERT_FAILURE UsbPortAssertFailure; + PUSBPORT_GET_MINIPORT_REGISTRY_KEY_VALUE UsbPortGetMiniportRegistryKeyValue; + PUSBPORT_INVALIDATE_ROOT_HUB UsbPortInvalidateRootHub; + PUSBPORT_INVALIDATE_ENDPOINT UsbPortInvalidateEndpoint; + PUSBPORT_COMPLETE_TRANSFER UsbPortCompleteTransfer; + PUSBPORT_COMPLETE_ISO_TRANSFER UsbPortCompleteIsoTransfer; + PUSBPORT_LOG_ENTRY UsbPortLogEntry; + PUSBPORT_GET_MAPPED_VIRTUAL_ADDRESS UsbPortGetMappedVirtualAddress; + PUSBPORT_REQUEST_ASYNC_CALLBACK UsbPortRequestAsyncCallback; + PUSBPORT_READ_WRITE_CONFIG_SPACE UsbPortReadWriteConfigSpace; + PUSBPORT_WAIT UsbPortWait; + PUSBPORT_INVALIDATE_CONTROLLER UsbPortInvalidateController; + PUSBPORT_BUG_CHECK UsbPortBugCheck; + PUSBPORT_NOTIFY_DOUBLE_BUFFER UsbPortNotifyDoubleBuffer; + + /* Miniport */ + PHCI_REBALANCE_ENDPOINT RebalanceEndpoint; + PHCI_FLUSH_INTERRUPTS FlushInterrupts; + PHCI_RH_CHIRP_ROOT_PORT RH_ChirpRootPort; + PHCI_TAKE_PORT_CONTROL TakePortControl; + ULONG Reserved4; + ULONG Reserved5; +} USBPORT_REGISTRATION_PACKET, *PUSBPORT_REGISTRATION_PACKET; + +typedef struct _USBPORT_MINIPORT_INTERFACE { + PDRIVER_OBJECT DriverObject; + LIST_ENTRY DriverLink; + PDRIVER_UNLOAD DriverUnload; + ULONG Version; + USBPORT_REGISTRATION_PACKET Packet; +} USBPORT_MINIPORT_INTERFACE, *PUSBPORT_MINIPORT_INTERFACE; + +C_ASSERT(sizeof(USBPORT_MINIPORT_INTERFACE) == 336); + +typedef struct _USBPORT_ENDPOINT_PROPERTIES { + USHORT DeviceAddress; + USHORT EndpointAddress; + USHORT TotalMaxPacketSize; // TransactionPerMicroframe * MaxPacketSize + UCHAR Period; + UCHAR Reserved1; + USB_DEVICE_SPEED DeviceSpeed; + ULONG UsbBandwidth; + ULONG ScheduleOffset; + ULONG TransferType; + ULONG Direction; + ULONG_PTR BufferVA; + ULONG_PTR BufferPA; + ULONG BufferLength; + ULONG Reserved3; + ULONG MaxTransferSize; + USHORT HubAddr; + USHORT PortNumber; + UCHAR InterruptScheduleMask; + UCHAR SplitCompletionMask; + UCHAR TransactionPerMicroframe; // 1 + additional transactions. Total: from 1 to 3) + UCHAR Reserved4; + ULONG MaxPacketSize; + ULONG Reserved6; +} USBPORT_ENDPOINT_PROPERTIES, *PUSBPORT_ENDPOINT_PROPERTIES; + +C_ASSERT(sizeof(USBPORT_ENDPOINT_PROPERTIES) == 64); + +typedef struct _USBPORT_SCATTER_GATHER_ELEMENT { + PHYSICAL_ADDRESS SgPhysicalAddress; + ULONG Reserved1; + ULONG SgTransferLength; + ULONG SgOffset; + ULONG Reserved2; +} USBPORT_SCATTER_GATHER_ELEMENT, *PUSBPORT_SCATTER_GATHER_ELEMENT; + +C_ASSERT(sizeof(USBPORT_SCATTER_GATHER_ELEMENT) == 24); + +typedef struct _USBPORT_SCATTER_GATHER_LIST { + ULONG Flags; + ULONG_PTR CurrentVa; + PVOID MappedSystemVa; + ULONG SgElementCount; + USBPORT_SCATTER_GATHER_ELEMENT SgElement[1]; +} USBPORT_SCATTER_GATHER_LIST, *PUSBPORT_SCATTER_GATHER_LIST; + +C_ASSERT(sizeof(USBPORT_SCATTER_GATHER_LIST) == 40); + +typedef struct _USBPORT_TRANSFER_PARAMETERS { + ULONG TransferFlags; + ULONG TransferBufferLength; + ULONG TransferCounter; + ULONG Reserved1; + ULONG Reserved2; + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; +} USBPORT_TRANSFER_PARAMETERS, *PUSBPORT_TRANSFER_PARAMETERS; + +C_ASSERT(sizeof(USBPORT_TRANSFER_PARAMETERS) == 28); + +typedef struct _USBPORT_ROOT_HUB_DATA { + ULONG NumberOfPorts; + ULONG HubCharacteristics; + ULONG PowerOnToPowerGood; + ULONG HubControlCurrent; +} USBPORT_ROOT_HUB_DATA, *PUSBPORT_ROOT_HUB_DATA; + +C_ASSERT(sizeof(USBPORT_ROOT_HUB_DATA) == 16); + +ULONG +NTAPI +USBPORT_GetHciMn(VOID); + +NTSTATUS +NTAPI +USBPORT_RegisterUSBPortDriver( + IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PUSBPORT_REGISTRATION_PACKET RegistrationPacket); + +#endif /* USBMPORT_H__ */