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__ */