From e7047d5447404df0133c05fe3e0a132078afdda9 Mon Sep 17 00:00:00 2001 From: vgalnt Date: Sat, 21 May 2016 01:22:43 +0800 Subject: [PATCH] vgal's usb changes --- README.md | 5 + reactos/drivers/hid/hidclass/fdo.c | 2451 +++++++- reactos/drivers/hid/hidclass/hidclass.c | 1728 ++++-- reactos/drivers/hid/hidclass/pdo.c | 972 +++- reactos/drivers/hid/hidclass/precomp.h | 262 +- reactos/drivers/hid/hidusb/hidusb.c | 756 ++- reactos/drivers/hid/hidusb/hidusb.h | 11 + reactos/drivers/hid/hidusb/hidusb.rc | 2 +- reactos/drivers/hid/kbdhid/kbdhid.c | 5 +- reactos/drivers/hid/mouhid/mouhid.c | 3 +- reactos/drivers/usb/CMakeLists.txt | 13 +- reactos/drivers/usb/usbccgp/pdo.c | 7 + .../drivers/usb/usbehci_new/CMakeLists.txt | 16 + reactos/drivers/usb/usbehci_new/dbg_ehci.h | 44 + reactos/drivers/usb/usbehci_new/debug.c | 35 + reactos/drivers/usb/usbehci_new/guid.c | 9 + reactos/drivers/usb/usbehci_new/hardware.h | 321 + reactos/drivers/usb/usbehci_new/roothub.c | 607 ++ reactos/drivers/usb/usbehci_new/usbehci.c | 3467 +++++++++++ reactos/drivers/usb/usbehci_new/usbehci.h | 303 + reactos/drivers/usb/usbehci_new/usbehci.rc | 5 + reactos/drivers/usb/usbhub/fdo.c | 19 +- reactos/drivers/usb/usbhub_new/CMakeLists.txt | 22 + reactos/drivers/usb/usbhub_new/dbg_uhub.h | 5 + reactos/drivers/usb/usbhub_new/debug.c | 135 + reactos/drivers/usb/usbhub_new/guid.c | 9 + reactos/drivers/usb/usbhub_new/ioctl.c | 1448 +++++ reactos/drivers/usb/usbhub_new/pnp.c | 2778 +++++++++ reactos/drivers/usb/usbhub_new/power.c | 821 +++ reactos/drivers/usb/usbhub_new/usbhub.c | 5143 +++++++++++++++++ reactos/drivers/usb/usbhub_new/usbhub.h | 643 +++ reactos/drivers/usb/usbhub_new/usbhub.rc | 5 + reactos/drivers/usb/usbmport.h | 682 +++ .../drivers/usb/usbohci_new/CMakeLists.txt | 15 + reactos/drivers/usb/usbohci_new/dbg_ohci.h | 29 + reactos/drivers/usb/usbohci_new/guid.c | 9 + reactos/drivers/usb/usbohci_new/hardware.h | 294 + reactos/drivers/usb/usbohci_new/roothub.c | 471 ++ reactos/drivers/usb/usbohci_new/usbohci.c | 2456 ++++++++ reactos/drivers/usb/usbohci_new/usbohci.h | 240 + reactos/drivers/usb/usbohci_new/usbohci.rc | 5 + reactos/drivers/usb/usbport/CMakeLists.txt | 28 + reactos/drivers/usb/usbport/debug.c | 250 + reactos/drivers/usb/usbport/device.c | 1873 ++++++ reactos/drivers/usb/usbport/endpoint.c | 1581 +++++ reactos/drivers/usb/usbport/guid.c | 9 + reactos/drivers/usb/usbport/iface.c | 916 +++ reactos/drivers/usb/usbport/ioctl.c | 369 ++ reactos/drivers/usb/usbport/pnp.c | 1724 ++++++ reactos/drivers/usb/usbport/power.c | 695 +++ reactos/drivers/usb/usbport/queue.c | 1389 +++++ reactos/drivers/usb/usbport/roothub.c | 1083 ++++ reactos/drivers/usb/usbport/urb.c | 1027 ++++ reactos/drivers/usb/usbport/usb2.c | 21 + reactos/drivers/usb/usbport/usbdebug.h | 128 + reactos/drivers/usb/usbport/usbport.c | 2890 +++++++++ reactos/drivers/usb/usbport/usbport.h | 1137 ++++ reactos/drivers/usb/usbport/usbport.rc | 5 + reactos/drivers/usb/usbport/usbport.spec | 2 + .../drivers/usb/usbuhci_new/CMakeLists.txt | 15 + reactos/drivers/usb/usbuhci_new/guid.c | 9 + reactos/drivers/usb/usbuhci_new/hardware.h | 131 + reactos/drivers/usb/usbuhci_new/roothub.c | 163 + reactos/drivers/usb/usbuhci_new/usbuhci.c | 364 ++ reactos/drivers/usb/usbuhci_new/usbuhci.h | 174 + reactos/drivers/usb/usbuhci_new/usbuhci.rc | 5 + reactos/sdk/lib/drivers/hidparser/api.c | 22 +- reactos/sdk/lib/drivers/hidparser/hidparser.c | 71 +- reactos/sdk/lib/drivers/hidparser/parser.h | 7 +- usbhub.sys.zip | Bin 0 -> 41507 bytes usbport.sys.zip | Bin 0 -> 41262 bytes 71 files changed, 40931 insertions(+), 1408 deletions(-) create mode 100644 README.md create mode 100644 reactos/drivers/usb/usbehci_new/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbehci_new/dbg_ehci.h create mode 100644 reactos/drivers/usb/usbehci_new/debug.c create mode 100644 reactos/drivers/usb/usbehci_new/guid.c create mode 100644 reactos/drivers/usb/usbehci_new/hardware.h create mode 100644 reactos/drivers/usb/usbehci_new/roothub.c create mode 100644 reactos/drivers/usb/usbehci_new/usbehci.c create mode 100644 reactos/drivers/usb/usbehci_new/usbehci.h create mode 100644 reactos/drivers/usb/usbehci_new/usbehci.rc create mode 100644 reactos/drivers/usb/usbhub_new/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbhub_new/dbg_uhub.h create mode 100644 reactos/drivers/usb/usbhub_new/debug.c create mode 100644 reactos/drivers/usb/usbhub_new/guid.c create mode 100644 reactos/drivers/usb/usbhub_new/ioctl.c create mode 100644 reactos/drivers/usb/usbhub_new/pnp.c create mode 100644 reactos/drivers/usb/usbhub_new/power.c create mode 100644 reactos/drivers/usb/usbhub_new/usbhub.c create mode 100644 reactos/drivers/usb/usbhub_new/usbhub.h create mode 100644 reactos/drivers/usb/usbhub_new/usbhub.rc create mode 100644 reactos/drivers/usb/usbmport.h create mode 100644 reactos/drivers/usb/usbohci_new/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbohci_new/dbg_ohci.h create mode 100644 reactos/drivers/usb/usbohci_new/guid.c create mode 100644 reactos/drivers/usb/usbohci_new/hardware.h create mode 100644 reactos/drivers/usb/usbohci_new/roothub.c create mode 100644 reactos/drivers/usb/usbohci_new/usbohci.c create mode 100644 reactos/drivers/usb/usbohci_new/usbohci.h create mode 100644 reactos/drivers/usb/usbohci_new/usbohci.rc create mode 100644 reactos/drivers/usb/usbport/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbport/debug.c create mode 100644 reactos/drivers/usb/usbport/device.c create mode 100644 reactos/drivers/usb/usbport/endpoint.c create mode 100644 reactos/drivers/usb/usbport/guid.c create mode 100644 reactos/drivers/usb/usbport/iface.c create mode 100644 reactos/drivers/usb/usbport/ioctl.c create mode 100644 reactos/drivers/usb/usbport/pnp.c create mode 100644 reactos/drivers/usb/usbport/power.c create mode 100644 reactos/drivers/usb/usbport/queue.c create mode 100644 reactos/drivers/usb/usbport/roothub.c create mode 100644 reactos/drivers/usb/usbport/urb.c create mode 100644 reactos/drivers/usb/usbport/usb2.c create mode 100644 reactos/drivers/usb/usbport/usbdebug.h create mode 100644 reactos/drivers/usb/usbport/usbport.c create mode 100644 reactos/drivers/usb/usbport/usbport.h create mode 100644 reactos/drivers/usb/usbport/usbport.rc create mode 100644 reactos/drivers/usb/usbport/usbport.spec create mode 100644 reactos/drivers/usb/usbuhci_new/CMakeLists.txt create mode 100644 reactos/drivers/usb/usbuhci_new/guid.c create mode 100644 reactos/drivers/usb/usbuhci_new/hardware.h create mode 100644 reactos/drivers/usb/usbuhci_new/roothub.c create mode 100644 reactos/drivers/usb/usbuhci_new/usbuhci.c create mode 100644 reactos/drivers/usb/usbuhci_new/usbuhci.h create mode 100644 reactos/drivers/usb/usbuhci_new/usbuhci.rc create mode 100644 usbhub.sys.zip create mode 100644 usbport.sys.zip diff --git a/README.md b/README.md new file mode 100644 index 00000000000..32a4e773745 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# reactos +ReactOS Mirror + +Драйвер USBPORT и драйвер USBOHCI для демонстрации возможности работы USB стека без ошибки CORE-9224. +Используются функции структуры DMA_OPERATIONS (DMA_ADAPTER) для организации обмена данных с OHCI контроллером. diff --git a/reactos/drivers/hid/hidclass/fdo.c b/reactos/drivers/hid/hidclass/fdo.c index 8ea65903b46..847068034b3 100644 --- a/reactos/drivers/hid/hidclass/fdo.c +++ b/reactos/drivers/hid/hidclass/fdo.c @@ -13,6 +13,1302 @@ #define NDEBUG #include +VOID +NTAPI +HidClassDumpDeviceDesc(IN PHIDP_DEVICE_DESC DeviceDescription) +{ + ULONG Idx; + PHIDP_COLLECTION_DESC CollectionDescription; + PHIDP_REPORT_IDS ReportIDs; + + DPRINT("[HIDCLASS]: DeviceDescription - %p\n", DeviceDescription); + DPRINT("[HIDCLASS]: DeviceDescription->CollectionDesc - %p\n", DeviceDescription->CollectionDesc); + DPRINT("[HIDCLASS]: DeviceDescription->CollectionDescLength - %x\n", DeviceDescription->CollectionDescLength); + DPRINT("[HIDCLASS]: DeviceDescription->ReportIDs - %p\n", DeviceDescription->ReportIDs); + DPRINT("[HIDCLASS]: DeviceDescription->ReportIDsLength - %x\n", DeviceDescription->ReportIDsLength); + + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.BreakOffset - %x\n", DeviceDescription->Dbg.BreakOffset); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.ErrorCode - %x\n", DeviceDescription->Dbg.ErrorCode); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.Args[0] - %x\n", DeviceDescription->Dbg.Args[0]); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.Args[1] - %x\n", DeviceDescription->Dbg.Args[1]); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.Args[2] - %x\n", DeviceDescription->Dbg.Args[2]); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.Args[3] - %x\n", DeviceDescription->Dbg.Args[3]); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.Args[4] - %x\n", DeviceDescription->Dbg.Args[4]); + DPRINT("[HIDCLASS]: DeviceDescription->Dbg.Args[5] - %x\n", DeviceDescription->Dbg.Args[5]); + + if (DeviceDescription->CollectionDescLength) + { + Idx = 0; + + do + { + CollectionDescription = &DeviceDescription->CollectionDesc[Idx]; + + DPRINT("[HIDCLASS]: CollectionDescription[%d] - %p\n", Idx, CollectionDescription); + DPRINT("[HIDCLASS]: CollectionDescription->UsagePage - %x\n", CollectionDescription->UsagePage); + DPRINT("[HIDCLASS]: CollectionDescription->Usage - %x\n", CollectionDescription->Usage); + DPRINT("[HIDCLASS]: CollectionDescription->CollectionNumber - %x\n", CollectionDescription->CollectionNumber); + DPRINT("[HIDCLASS]: CollectionDescription->InputLength - %x\n", CollectionDescription->InputLength); + DPRINT("[HIDCLASS]: CollectionDescription->OutputLength - %x\n", CollectionDescription->OutputLength); + DPRINT("[HIDCLASS]: CollectionDescription->FeatureLength - %x\n", CollectionDescription->FeatureLength); + DPRINT("[HIDCLASS]: CollectionDescription->PreparsedDataLength - %x\n", CollectionDescription->PreparsedDataLength); + DPRINT("[HIDCLASS]: CollectionDescription->PreparsedData - %p\n", CollectionDescription->PreparsedData); + DPRINT("------------------------------------------------------\n"); + + ++Idx; + } + while (Idx < DeviceDescription->CollectionDescLength); + } + + if (DeviceDescription->ReportIDsLength) + { + Idx = 0; + + do + { + ReportIDs = &DeviceDescription->ReportIDs[Idx]; + + DPRINT("[HIDCLASS]: ReportIDs[%d] - %p\n", Idx, ReportIDs); + DPRINT("[HIDCLASS]: ReportIDs->ReportID - %x\n", ReportIDs->ReportID); + DPRINT("[HIDCLASS]: ReportIDs->CollectionNumber - %x\n", ReportIDs->CollectionNumber); + DPRINT("[HIDCLASS]: ReportIDs->InputLength - %x\n", ReportIDs->InputLength); + DPRINT("[HIDCLASS]: ReportIDs->OutputLength - %x\n", ReportIDs->OutputLength); + DPRINT("[HIDCLASS]: ReportIDs->FeatureLength - %x\n", ReportIDs->FeatureLength); + DPRINT("----------------------------------------\n"); + + ++Idx; + } + while (Idx < DeviceDescription->ReportIDsLength); + } +} + +PVOID +NTAPI +HidClassGetSystemAddressForMdlSafe( + IN PMDL MemoryDescriptorList) +{ + PVOID VAddress = NULL; + + if (MemoryDescriptorList) + { + MemoryDescriptorList->MdlFlags |= MDL_MAPPING_CAN_FAIL; + + if (MemoryDescriptorList->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | + MDL_SOURCE_IS_NONPAGED_POOL)) + { + VAddress = MemoryDescriptorList->MappedSystemVa; + } + else + { + VAddress = MmMapLockedPages(MemoryDescriptorList, KernelMode); + } + + MemoryDescriptorList->MdlFlags &= ~MDL_MAPPING_CAN_FAIL; + } + + return VAddress; +} + +VOID +NTAPI +HidClassEnqueueInterruptReport( + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN PHIDCLASS_INT_REPORT_HEADER Header) +{ + PLIST_ENTRY Entry; + + DPRINT("HidClassEnqueueInterruptReport: ... \n"); + + Entry = NULL; + + if (FileContext->PendingReports >= FileContext->MaxReportQueueSize) + { + DPRINT1("[HIDCLASS] Report queue (size %x) is full \n", + FileContext->MaxReportQueueSize); + + Entry = RemoveHeadList(&FileContext->ReportList); + FileContext->PendingReports--; + } + + InsertTailList(&FileContext->ReportList, &Header->ReportLink); + FileContext->PendingReports++; + + if (Entry) + { + ExFreePoolWithTag(Entry, 0); + } +} + +PHIDCLASS_INT_REPORT_HEADER +NTAPI +HidClassDequeueInterruptReport( + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN ULONG ReadLength) +{ + PLIST_ENTRY ReportList; + PHIDCLASS_INT_REPORT_HEADER Header; + + DPRINT("HidClassDequeueInterruptReport: ... \n"); + + if (IsListEmpty(&FileContext->ReportList)) + { + return NULL; + } + + ReportList = &FileContext->ReportList; + + Header = CONTAINING_RECORD(ReportList->Flink, + HIDCLASS_INT_REPORT_HEADER, + ReportLink); + + RemoveHeadList(ReportList); + + if (ReadLength > 0 && (Header->InputLength > ReadLength)) + { + InsertHeadList(ReportList, &Header->ReportLink); + return NULL; + } + + InitializeListHead(&Header->ReportLink); + + FileContext->PendingReports--; + + return Header; +} + +VOID +NTAPI +HidClassCancelReadIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHIDCLASS_COLLECTION HidCollection; + PIO_STACK_LOCATION IoStack; + PHIDCLASS_FILEOP_CONTEXT FileContext; + KIRQL OldIrql; + + DPRINT("HidClassCancelReadIrp: Irp - %p\n", Irp); + + PDODeviceExtension = DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; + + HidCollection = &FDODeviceExtension->HidCollections[PDODeviceExtension->PdoIdx]; + IoStack = Irp->Tail.Overlay.CurrentStackLocation; + + FileContext = IoStack->FileObject->FsContext; + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + KeAcquireSpinLock(&FileContext->Lock, &OldIrql); + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + + HidCollection->NumPendingReads--; + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +NTSTATUS +NTAPI +HidClassEnqueueInterruptReadIrp( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN PIRP Irp) +{ + DPRINT("HidClassEnqueueInterruptReadIrp: Irp - %p\n", Irp); + + IoSetCancelRoutine(Irp, HidClassCancelReadIrp); + + if (Irp->Cancel) + { + if (IoSetCancelRoutine(Irp, NULL)) + { + return STATUS_CANCELLED; + } + + InitializeListHead(&Irp->Tail.Overlay.ListEntry); + } + else + { + InsertTailList(&FileContext->InterruptReadIrpList, + &Irp->Tail.Overlay.ListEntry); + } + + ++HidCollection->NumPendingReads; + IoMarkIrpPending(Irp); + + return STATUS_PENDING; +} + +PIRP +NTAPI +HidClassDequeueInterruptReadIrp( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext) +{ + PLIST_ENTRY ReadIrpList; + PLIST_ENTRY Entry; + PIRP Irp = NULL; + + ReadIrpList = &FileContext->InterruptReadIrpList; + + do + { + if (ReadIrpList->Flink == ReadIrpList) + { + break; + } + + Entry = RemoveHeadList(ReadIrpList); + + Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + + if (IoSetCancelRoutine(Irp, NULL)) + { + HidCollection->NumPendingReads--; + } + else + { + InitializeListHead(Entry); + Irp = NULL; + } + } + while (!Irp); + + DPRINT("HidClassDequeueInterruptReadIrp: Irp - %p\n", Irp); + + return Irp; +} + +PHIDP_COLLECTION_DESC +NTAPI +GetCollectionDesc( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR CollectionNumber) +{ + PHIDP_COLLECTION_DESC CollectionDescArray; + PHIDP_COLLECTION_DESC HidCollectionDesc = NULL; + ULONG NumCollections; + ULONG Idx = 0; + + DPRINT("GetCollectionDesc: CollectionNumber - %x\n", CollectionNumber); + + CollectionDescArray = FDODeviceExtension->Common.DeviceDescription.CollectionDesc; + + if (CollectionDescArray) + { + NumCollections = FDODeviceExtension->Common.DeviceDescription.CollectionDescLength; + + if (NumCollections) + { + while (CollectionDescArray[Idx].CollectionNumber != CollectionNumber) + { + ++Idx; + + if (Idx >= NumCollections) + { + return HidCollectionDesc; + } + } + + HidCollectionDesc = &CollectionDescArray[Idx]; + } + } + + return HidCollectionDesc; +} + +PHIDCLASS_COLLECTION +NTAPI +GetHidclassCollection( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN ULONG CollectionNumber) +{ + PHIDCLASS_COLLECTION HidCollections; + ULONG NumCollections; + ULONG Idx = 0; + PHIDCLASS_COLLECTION HidCollection = NULL; + + DPRINT("GetHidclassCollection: CollectionNumber - %x\n", CollectionNumber); + + HidCollections = FDODeviceExtension->HidCollections; + + if (HidCollections && HidCollections != HIDCLASS_NULL_POINTER) + { + NumCollections = FDODeviceExtension->Common.DeviceDescription.CollectionDescLength; + + if (NumCollections) + { + while (HidCollections[Idx].CollectionNumber != CollectionNumber) + { + ++Idx; + + if (Idx >= NumCollections) + { + return HidCollection; + } + } + + HidCollection = &HidCollections[Idx]; + } + } + + return HidCollection; +} + +PHIDP_REPORT_IDS +NTAPI +GetReportIdentifier( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR Id) +{ + PHIDP_DEVICE_DESC DeviceDescription; + PHIDP_REPORT_IDS ReportIDs; + PHIDP_REPORT_IDS Result = NULL; + ULONG NumCollections; + ULONG Idx; + + DPRINT("GetReportIdentifier: Id - %x\n", Id); + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + + ReportIDs = DeviceDescription->ReportIDs; + + if (ReportIDs) + { + NumCollections = DeviceDescription->ReportIDsLength; + + Idx = 0; + + if (NumCollections) + { + while (DeviceDescription->ReportIDs[Idx].ReportID != Id) + { + ++Idx; + + if (Idx >= NumCollections) + { + return Result; + } + } + + Result = &ReportIDs[Idx]; + } + } + + return Result; +} + +PHIDCLASS_SHUTTLE +NTAPI +GetShuttleFromIrp( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN PIRP Irp) +{ + ULONG ShuttleCount; + ULONG ix; + PHIDCLASS_SHUTTLE Shuttle; + PHIDCLASS_SHUTTLE Result = NULL; + + ShuttleCount = FDODeviceExtension->ShuttleCount; + + ix = 0; + + if (ShuttleCount) + { + Shuttle = &FDODeviceExtension->Shuttles[0]; + + while (Shuttle[ix].ShuttleIrp != Irp) + { + ++ix; + + if (ix >= ShuttleCount) + { + return Result; + } + } + + Result = &Shuttle[ix]; + } + + DPRINT("GetShuttleFromIrp: Irp - %p, Shuttle - %p\n", + Irp, + Result); + + return Result; +} + +ULONG +NTAPI +HidClassSetMaxReportSize( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PHIDP_DEVICE_DESC DeviceDescription; + PHIDP_REPORT_IDS ReportId; + ULONG Idx = 0; + ULONG InputLength; + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + FDODeviceExtension->MaxReportSize = 0; + + DPRINT("HidClassSetMaxReportSize: ReportIDsLength - %x\n", + DeviceDescription->ReportIDsLength); + + if (DeviceDescription->ReportIDsLength) + { + do + { + ReportId = &DeviceDescription->ReportIDs[Idx]; + + if (GetHidclassCollection(FDODeviceExtension, ReportId->CollectionNumber)) + { + InputLength = ReportId->InputLength; + + if (InputLength > FDODeviceExtension->MaxReportSize) + { + FDODeviceExtension->MaxReportSize = InputLength; + } + } + + ++Idx; + } + while (Idx < DeviceDescription->ReportIDsLength); + } + + DPRINT("HidClassSetMaxReportSize: MaxReportSize - %x\n", + FDODeviceExtension->MaxReportSize); + + return FDODeviceExtension->MaxReportSize; +} + +NTSTATUS +NTAPI +HidClassGetCollectionDescriptor( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR CollectionNumber, + OUT PVOID OutCollectionData, + OUT PULONG OutLength) +{ + PHIDP_COLLECTION_DESC HidCollectionDesc; + ULONG Length; + NTSTATUS Status; + + DPRINT("HidClassGetCollectionDescriptor: CollectionNumber - %x\n", CollectionNumber); + + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, + CollectionNumber); + + if (HidCollectionDesc) + { + Length = HidCollectionDesc->PreparsedDataLength; + + if (*OutLength >= Length) + { + Status = 0; + } + else + { + Length = *OutLength; + Status = STATUS_INVALID_BUFFER_SIZE; + } + + RtlCopyMemory(OutCollectionData, + HidCollectionDesc->PreparsedData, + Length); + + *OutLength = HidCollectionDesc->PreparsedDataLength; + } + else + { + DPRINT1("[HIDCLASS] Not found collection descriptor\n"); + Status = STATUS_DATA_ERROR; + } + + return Status; +} + +NTSTATUS +NTAPI +HidClassCopyInputReportToUser( + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN PVOID InputReportBuffer, + IN PULONG OutLength, + IN PVOID VAddress) +{ + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHIDP_REPORT_IDS ReportId; + UCHAR CollectionNumber; + PHIDP_COLLECTION_DESC HidCollectionDesc; + ULONG InputLength; + UCHAR Id; + NTSTATUS Status = STATUS_DEVICE_DATA_ERROR; + + DPRINT("HidClassCopyInputReportToUser: FileContext - %x\n", FileContext); + + PDODeviceExtension = FileContext->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; + + /* first byte of the buffer is the report ID for the report */ + Id = *(PUCHAR)InputReportBuffer; + + ReportId = GetReportIdentifier(FDODeviceExtension, Id); + + if (!ReportId) + { + return Status; + } + + CollectionNumber = ReportId->CollectionNumber; + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, CollectionNumber); + + if (!HidCollectionDesc) + { + return Status; + } + + if (!GetHidclassCollection(FDODeviceExtension, CollectionNumber)) + { + return Status; + } + + InputLength = HidCollectionDesc->InputLength; + + if (*OutLength < InputLength) + { + Status = STATUS_INVALID_BUFFER_SIZE; + } + else + { + RtlCopyMemory(VAddress, InputReportBuffer, InputLength); + + Status = STATUS_SUCCESS; + } + + *OutLength = InputLength; + + return Status; +} + +NTSTATUS +NTAPI +HidClassProcessInterruptReport( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN PVOID InputReport, + IN ULONG InputLength, + IN PIRP * OutIrp) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + PVOID VAddress; + NTSTATUS Status; + PHIDCLASS_INT_REPORT_HEADER ReportHeader; + KIRQL OldIrql; + ULONG ReturnedLength; + + KeAcquireSpinLock(&FileContext->Lock, &OldIrql); + + Irp = HidClassDequeueInterruptReadIrp(HidCollection, FileContext); + + DPRINT("HidClassProcessInterruptReport: FileContext - %p, Irp - %p\n", + FileContext, + Irp); + + if (Irp) + { + IoStack = Irp->Tail.Overlay.CurrentStackLocation; + + VAddress = HidClassGetSystemAddressForMdlSafe(Irp->MdlAddress); + + if (VAddress) + { + ReturnedLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + Status = HidClassCopyInputReportToUser(FileContext, + InputReport, + &ReturnedLength, + VAddress); + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = ReturnedLength; + } + else + { + Status = STATUS_INVALID_USER_BUFFER; + Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; + } + } + else + { + ReportHeader = ExAllocatePoolWithTag(NonPagedPool, + InputLength + sizeof(HIDCLASS_INT_REPORT_HEADER), + HIDCLASS_TAG); + + if (ReportHeader) + { + ReportHeader->InputLength = InputLength; + + RtlCopyMemory((PVOID)((ULONG_PTR)ReportHeader + sizeof(HIDCLASS_INT_REPORT_HEADER)), + InputReport, + InputLength); + + HidClassEnqueueInterruptReport(FileContext, ReportHeader); + + Status = STATUS_PENDING; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + *OutIrp = Irp; + + return Status; +} + +VOID +NTAPI +HidClassHandleInterruptReport( + IN PHIDCLASS_COLLECTION HidCollection, + IN PVOID InputReport, + IN ULONG InputLength, + IN BOOLEAN IsSessionSecurity) +{ + PHIDCLASS_FILEOP_CONTEXT FileContext; + PLIST_ENTRY Entry; + LIST_ENTRY IrpList; + PIRP Irp; + KIRQL OldIrql; + + DPRINT("HidClassHandleInterruptReport: ... \n"); + + InitializeListHead(&IrpList); + + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + + Entry = HidCollection->InterruptReportList.Flink; + + while (Entry != &HidCollection->InterruptReportList) + { + FileContext = CONTAINING_RECORD(Entry, + HIDCLASS_FILEOP_CONTEXT, + InterruptReportLink); + + if ((!HidCollection->CloseFlag || FileContext->IsMyPrivilegeTrue) && + !IsSessionSecurity) + { + HidClassProcessInterruptReport(HidCollection, + FileContext, + InputReport, + InputLength, + &Irp); + + if (Irp) + { + InsertTailList(&IrpList, &Irp->Tail.Overlay.ListEntry); + } + } + + Entry = Entry->Flink; + } + + KeReleaseSpinLock(&HidCollection->CollectSpinLock, OldIrql); + + while (TRUE) + { + Entry = IrpList.Flink; + + if (IsListEmpty(&IrpList)) + { + break; + } + + RemoveHeadList(&IrpList); + + Irp = CONTAINING_RECORD(Entry, + IRP, + Tail.Overlay.ListEntry); + + DPRINT("HidClassHandleInterruptReport: IoCompleteRequest - %p\n", + Irp); + + IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT); + } +} + +VOID +NTAPI +HidClassSetDeviceBusy( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + DPRINT("HidClassSetDeviceBusy: FIXME \n"); +} + +NTSTATUS +NTAPI +HidClassInterruptReadComplete( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHIDCLASS_SHUTTLE Shuttle; + PHIDP_REPORT_IDS ReportId; + ULONG HidDataLen; + PHIDCLASS_COLLECTION HidCollection; + PHIDP_COLLECTION_DESC HidCollectionDesc; + PHIDCLASS_PDO_DEVICE_EXTENSION * ClientPdoExtensions; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + LONG Length; + PVOID InputReport; + LONG OldState; + UCHAR Id; + + DPRINT("HidClassInterruptReadComplete: Irp - %p\n", Irp); + + FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)Context; + + InterlockedExchangeAdd(&FDODeviceExtension->OutstandingRequests, -1); + + Shuttle = GetShuttleFromIrp(FDODeviceExtension, Irp); + + if (!Shuttle) + { + DPRINT1("[HIDCLASS] Shuttle could not be found\n"); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + OldState = InterlockedCompareExchange(&Shuttle->ShuttleState, + HIDCLASS_SHUTTLE_DISABLED, + HIDCLASS_SHUTTLE_START_READ); + + if (Irp->IoStatus.Status >= 0) + { + //PCHAR Report; + + InputReport = Irp->UserBuffer; + Length = Irp->IoStatus.Information; + + //Report = InputReport; + //DPRINT("[HIDCLASS] ReportData[%x] %02x %02x %02x %02x %02x %02x %02x %02x\n", Length, + // Report[0] & 0xFF, Report[1] & 0xFF, Report[2] & 0xFF, Report[3] & 0xFF, Report[4] & 0xFF, Report[5] & 0xFF, Report[6] & 0xFF, Report[7] & 0xFF); + + if (Irp->IoStatus.Information > 0) + { + while (TRUE) + { + if (FDODeviceExtension->Common.DeviceDescription.ReportIDs[0].ReportID) + { + /* First byte of the buffer is the report ID for the report */ + Id = *(PUCHAR)InputReport; + InputReport = (PUCHAR)InputReport + 1; + --Length; + } + else + { + Id = 0; + } + + ReportId = GetReportIdentifier(FDODeviceExtension, Id); + + if (!ReportId) + { + break; + } + + if (Id) + { + HidDataLen = ReportId->InputLength - 1; + } + else + { + HidDataLen = ReportId->InputLength; + } + + if (HidDataLen <= 0 || HidDataLen > Length) + { + break; + } + + HidCollection = GetHidclassCollection(FDODeviceExtension, + ReportId->CollectionNumber); + + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, + ReportId->CollectionNumber); + + if (!HidCollection || !HidCollectionDesc) + { + break; + } + + ClientPdoExtensions = FDODeviceExtension->ClientPdoExtensions; + + if (!ClientPdoExtensions || + ClientPdoExtensions == HIDCLASS_NULL_POINTER) + { + goto NextData; + } + + PDODeviceExtension = ClientPdoExtensions[HidCollection->CollectionIdx]; + + if (!PDODeviceExtension) + { + goto NextData; + } + + if (PDODeviceExtension == HIDCLASS_NULL_POINTER || + PDODeviceExtension->HidPdoState != HIDCLASS_STATE_STARTED) + { + goto NextData; + } + + /* First byte of the buffer is the report ID for the report */ + *(PUCHAR)HidCollection->InputReport = Id; + + RtlCopyMemory((PUCHAR)HidCollection->InputReport + 1, + InputReport, + HidDataLen); + + DPRINT("HidClassInterruptReadComplete: FIXME CheckReportPowerEvent()\n"); + //CheckReportPowerEvent(FDODeviceExtension, + // HidCollection, + // HidCollection->InputReport, + // HidCollectionDesc->InputLength); + + HidClassHandleInterruptReport(HidCollection, + HidCollection->InputReport, + HidCollectionDesc->InputLength, + PDODeviceExtension->IsSessionSecurity); + +NextData: + /* Next hid data (HID_DATA) */ + InputReport = (PUCHAR)InputReport + HidDataLen; + Length -= HidDataLen; + + if (Length <= 0) + { + break; + } + } + } + + Shuttle->TimerPeriod.HighPart = -1; + Shuttle->TimerPeriod.LowPart = -1000 * 10000; + } + + if (OldState != HIDCLASS_SHUTTLE_START_READ) + { + /* Checks if shuttle state is a cancelling */ + if (Shuttle->CancellingShuttle) + { + DPRINT1("[HIDCLASS] Cancelling Shuttle %p\n", Shuttle); + /* Sets a ShuttleDoneEvent to a signaled state */ + KeSetEvent(&Shuttle->ShuttleDoneEvent, IO_NO_INCREMENT, FALSE); + } + else if (Irp->IoStatus.Status < 0) + { + DPRINT1("[HIDCLASS] Status - %x, TimerPeriod - %p, Shuttle - %p\n", + Irp->IoStatus.Status, + Shuttle->TimerPeriod.LowPart, + Shuttle); + + KeSetTimer(&Shuttle->ShuttleTimer, + Shuttle->TimerPeriod, + &Shuttle->ShuttleTimerDpc); + } + else + { + BOOLEAN IsSending; + + HidClassSubmitInterruptRead(FDODeviceExtension, + Shuttle, + &IsSending); + } + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +HidClassSubmitInterruptRead( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN PHIDCLASS_SHUTTLE Shuttle, + IN BOOLEAN * OutIsSending) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + LARGE_INTEGER DueTime; + LONG OldState; + NTSTATUS Status; + + Irp = Shuttle->ShuttleIrp; + + *OutIsSending = 0; + + DPRINT("HidClassSubmitInterruptRead: ShuttleIrp - %p\n", Irp); + + do + { + HidClassSetDeviceBusy(FDODeviceExtension); + + InterlockedExchange(&Shuttle->ShuttleState, HIDCLASS_SHUTTLE_START_READ); + + IoStack = Irp->Tail.Overlay.CurrentStackLocation; + Irp->Cancel = FALSE; + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + IoStack--; + + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_READ_REPORT; + IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; + IoStack->Parameters.DeviceIoControl.OutputBufferLength = FDODeviceExtension->MaxReportSize; + + IoSetCompletionRoutine(Irp, + HidClassInterruptReadComplete, + FDODeviceExtension, + TRUE, + TRUE, + TRUE); + + /* Resets a ShuttleEvent to a not signaled state */ + KeResetEvent(&Shuttle->ShuttleEvent); + + /* Checks if shuttle state is a cancelling */ + if (Shuttle->CancellingShuttle) + { + DPRINT("HidClassSubmitInterruptRead: Shuttle->CancellingShuttle\n"); + /* Sets a Shuttle Event objects to a signaled state */ + KeSetEvent(&Shuttle->ShuttleEvent, IO_NO_INCREMENT, FALSE); + KeSetEvent(&Shuttle->ShuttleDoneEvent, IO_NO_INCREMENT, FALSE); + return STATUS_CANCELLED; + } + + /* Increment count outstanding requests*/ + InterlockedExchangeAdd(&FDODeviceExtension->OutstandingRequests, 1); + + /* Submit request */ + Status = HidClassFDO_DispatchRequest(FDODeviceExtension->FDODeviceObject, + Irp); + + /* Sets a ShuttleEvent to a signaled state */ + KeSetEvent(&Shuttle->ShuttleEvent, IO_NO_INCREMENT, FALSE); + + *OutIsSending = TRUE; + + OldState = InterlockedExchange(&Shuttle->ShuttleState, + HIDCLASS_SHUTTLE_END_READ); + + if (OldState != HIDCLASS_SHUTTLE_DISABLED) + { + return Status; + } + + Status = Irp->IoStatus.Status; + } + while (Irp->IoStatus.Status >= 0); + + /* Checks if shuttle state is a cancelling */ + if (Shuttle->CancellingShuttle) + { + DPRINT("HidClassSubmitInterruptRead: Shuttle->CancellingShuttle\n"); + /* Sets a ShuttleDoneEvent to a signaled state */ + KeSetEvent(&Shuttle->ShuttleDoneEvent, IO_NO_INCREMENT, FALSE); + return Status; + } + + DueTime = Shuttle->TimerPeriod; + + KeSetTimer(&Shuttle->ShuttleTimer, + DueTime, + &Shuttle->ShuttleTimerDpc); + + return Status; +} + +NTSTATUS +NTAPI +HidClassAllShuttlesStart( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG ix = 0; + BOOLEAN IsSending; + + DPRINT("HidClassAllShuttlesStart: ShuttleCount - %x\n", + FDODeviceExtension->ShuttleCount); + + if (!(FDODeviceExtension->ShuttleCount)) + { + DPRINT1("ShuttleCount is 0\n"); + return Status; + } + + do + { + /* If ShuttleDoneEvent is currently set to a signaled state */ + if (KeReadStateEvent(&FDODeviceExtension->Shuttles[ix].ShuttleDoneEvent)) + { + FDODeviceExtension->Shuttles[ix].ShuttleState = HIDCLASS_SHUTTLE_END_READ; + + /* Resets a ShuttleDoneEvent to a not signaled state */ + KeResetEvent(&FDODeviceExtension->Shuttles[ix].ShuttleDoneEvent); + + /* Send Shuttle IRP to a lower driver (usbhub) */ + Status = HidClassSubmitInterruptRead(FDODeviceExtension, + &FDODeviceExtension->Shuttles[ix], + &IsSending); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Submit read failed with %x\n", Status); + + if (!IsSending) + { + break; + } + + Status = STATUS_SUCCESS; + } + } + + ++ix; + } + while (ix < FDODeviceExtension->ShuttleCount); + + if (Status == STATUS_PENDING) + { + Status = STATUS_SUCCESS; + } + + return Status; +} + +VOID +NTAPI +HidClassCancelAllShuttleIrps( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PHIDCLASS_SHUTTLE Shuttle; + ULONG ix; + + DPRINT("HidClassCancelAllShuttleIrps: ShuttleCount - %x\n", + FDODeviceExtension->ShuttleCount); + + + if (FDODeviceExtension->ShuttleCount) + { +{ /* HACK: force cancelling shuttles + (problem disconnecting from PC USB port CORE-9070) + */ + + for (ix = 0; ix < FDODeviceExtension->ShuttleCount; ++ix) + { + Shuttle = &FDODeviceExtension->Shuttles[ix]; + /* Sets cancelling state for shuttle */ + Shuttle->CancellingShuttle = 1; + } +} + + ix = 0; + + do + { + Shuttle = &FDODeviceExtension->Shuttles[ix]; + + InterlockedExchangeAdd(&Shuttle->CancellingShuttle, 1); + + KeWaitForSingleObject(&Shuttle->ShuttleEvent, + Executive, + KernelMode, + FALSE, + NULL); + + IoCancelIrp(Shuttle->ShuttleIrp); + + KeWaitForSingleObject(&Shuttle->ShuttleDoneEvent, + Executive, + KernelMode, + FALSE, + NULL); + + InterlockedExchangeAdd(&Shuttle->CancellingShuttle, -1); + + ++ix; + } + while (ix < FDODeviceExtension->ShuttleCount); + } + + return; +} + +VOID +NTAPI +HidClassDestroyShuttles( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PHIDCLASS_SHUTTLE Shuttles; + ULONG ix; + + DPRINT("HidClassDestroyShuttles: ShuttleCount - %x\n", + FDODeviceExtension->ShuttleCount); + + Shuttles = FDODeviceExtension->Shuttles; + + if (Shuttles && Shuttles != HIDCLASS_NULL_POINTER) + { + HidClassCancelAllShuttleIrps(FDODeviceExtension); + + ix = 0; + + if (FDODeviceExtension->ShuttleCount) + { + do + { + DPRINT("HidClassDestroyShuttles: Free ShuttleIrp - %p\n", + FDODeviceExtension->Shuttles[ix].ShuttleIrp); + + IoFreeIrp(FDODeviceExtension->Shuttles[ix].ShuttleIrp); + ExFreePoolWithTag(FDODeviceExtension->Shuttles[ix].ShuttleBuffer, 0); + + ++ix; + } + while (ix < FDODeviceExtension->ShuttleCount); + } + + ExFreePoolWithTag(FDODeviceExtension->Shuttles, 0); + FDODeviceExtension->Shuttles = HIDCLASS_NULL_POINTER; + } +} + +VOID +NTAPI +HidClassShuttleTimerDpc( + IN KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PHIDCLASS_SHUTTLE Shuttle; + LONG TimerValue; + BOOLEAN IsSending; + + Shuttle = (PHIDCLASS_SHUTTLE)DeferredContext; + TimerValue = Shuttle->TimerPeriod.LowPart; + + if (TimerValue > (-5000 * 10000)) + { + Shuttle->TimerPeriod.LowPart = TimerValue - 1000 * 10000; + } + + HidClassSubmitInterruptRead(Shuttle->FDODeviceExtension, + Shuttle, + &IsSending); +} + +NTSTATUS +NTAPI +HidClassInitializeShuttleIrps( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PHIDCLASS_SHUTTLE Shuttles; + PIRP Irp; + SIZE_T NumberOfBytes; + NTSTATUS Status = 0; + ULONG ix; + + DPRINT("HidClassInitializeShuttleIrps: ... \n"); + + Shuttles = ExAllocatePoolWithTag(NonPagedPool, + FDODeviceExtension->ShuttleCount * sizeof(HIDCLASS_SHUTTLE), + HIDCLASS_TAG); + + FDODeviceExtension->Shuttles = Shuttles; + + if (!Shuttles) + { + DPRINT1("[HIDCLASS] Alocate shuttles failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NumberOfBytes = FDODeviceExtension->MaxReportSize; + + RtlZeroMemory(Shuttles, + FDODeviceExtension->ShuttleCount * sizeof(HIDCLASS_SHUTTLE)); + + ix = 0; + + if (!FDODeviceExtension->ShuttleCount) + { + return Status; + } + + while (TRUE) + { + FDODeviceExtension->Shuttles[ix].FDODeviceExtension = FDODeviceExtension; + FDODeviceExtension->Shuttles[ix].CancellingShuttle = 0; + FDODeviceExtension->Shuttles[ix].TimerPeriod.HighPart = -1; + FDODeviceExtension->Shuttles[ix].TimerPeriod.LowPart = -1000 * 10000; + + KeInitializeTimer(&FDODeviceExtension->Shuttles[ix].ShuttleTimer); + + KeInitializeDpc(&FDODeviceExtension->Shuttles[ix].ShuttleTimerDpc, + HidClassShuttleTimerDpc, + &FDODeviceExtension->Shuttles[ix]); + + FDODeviceExtension->Shuttles[ix].ShuttleBuffer = ExAllocatePoolWithTag(NonPagedPool, + NumberOfBytes, + HIDCLASS_TAG); + + if (!FDODeviceExtension->Shuttles[ix].ShuttleBuffer) + { + DPRINT1("[HIDCLASS] Alocate shuttle buffer failed\n"); + break; + } + + Irp = IoAllocateIrp(FDODeviceExtension->FDODeviceObject->StackSize - 1, + FALSE); + + if (!Irp) + { + DPRINT1("[HIDCLASS] Alocate shuttle IRP failed\n"); + break; + } + + DPRINT("HidClassInitializeShuttleIrps: Allocate Irp - %p\n", Irp); + + Irp->UserBuffer = FDODeviceExtension->Shuttles[ix].ShuttleBuffer; + FDODeviceExtension->Shuttles[ix].ShuttleIrp = Irp; + + /* Init state of the ShuttleEvent is a signaled state */ + KeInitializeEvent(&FDODeviceExtension->Shuttles[ix].ShuttleEvent, + NotificationEvent, + TRUE); + + /* Init state of the ShuttleDoneEvent is a signaled state */ + KeInitializeEvent(&FDODeviceExtension->Shuttles[ix].ShuttleDoneEvent, + NotificationEvent, + TRUE); + + ++ix; + + if (ix >= FDODeviceExtension->ShuttleCount) + { + return Status; + } + } + + return STATUS_INSUFFICIENT_RESOURCES; +} + NTSTATUS NTAPI HidClassFDO_QueryCapabilitiesCompletionRoutine( @@ -149,67 +1445,58 @@ HidClassFDO_DispatchRequestSynchronous( IN PIRP Irp) { KEVENT Event; - PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; NTSTATUS Status; - PIO_STACK_LOCATION IoStack; + LARGE_INTEGER Timeout = {{0, 0}}; - // - // init event - // + /* Init event */ KeInitializeEvent(&Event, NotificationEvent, FALSE); - // - // get device extension - // - CommonDeviceExtension = DeviceObject->DeviceExtension; - - // - // set completion routine - // - IoSetCompletionRoutine(Irp, HidClassFDO_DispatchRequestSynchronousCompletion, &Event, TRUE, TRUE, TRUE); - - ASSERT(Irp->CurrentLocation > 0); - // - // create stack location - // - IoSetNextIrpStackLocation(Irp); - - // - // get next stack location - // - IoStack = IoGetCurrentIrpStackLocation(Irp); - - // - // store device object - // - IoStack->DeviceObject = DeviceObject; - - // - // sanity check - // - ASSERT(CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction] != NULL); + /* Set completion routine */ + IoSetCompletionRoutine(Irp, + HidClassFDO_DispatchRequestSynchronousCompletion, + &Event, + TRUE, + TRUE, + TRUE); - // - // call minidriver (hidusb) - // - Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp); + /* Send request */ + Status = HidClassFDO_DispatchRequest(DeviceObject, Irp); - // - // wait for the request to finish - // - if (Status == STATUS_PENDING) + if (Status != STATUS_PENDING) { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + return Status; + } + + Timeout.QuadPart -= 5000 * 10000; // (5 sec.) - // - // update status - // + /* Status == STATUS_PENDING */ + if (KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + &Timeout) != STATUS_TIMEOUT) + { Status = Irp->IoStatus.Status; + return Status; } - // - // done - // + /* Status == STATUS_TIMEOUT */ + IoCancelIrp(Irp); + + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + + Status = Irp->IoStatus.Status; + + if (Status == STATUS_CANCELLED) + { + Status = STATUS_IO_TIMEOUT; + } + + Irp->IoStatus.Status = Status; return Status; } @@ -227,13 +1514,20 @@ HidClassFDO_DispatchRequest( // CommonDeviceExtension = DeviceObject->DeviceExtension; - ASSERT(Irp->CurrentLocation > 0); - // // create stack location // IoSetNextIrpStackLocation(Irp); + if (Irp->CurrentLocation <= 0) + { + KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, + (ULONG_PTR)Irp, + 0, + 0, + 0); + } + // // get next stack location // @@ -268,13 +1562,17 @@ HidClassFDO_GetDescriptors( PIRP Irp; PIO_STACK_LOCATION IoStack; NTSTATUS Status; + PHID_DESCRIPTOR HidDescriptor; + PHIDP_REPORT_DESCRIPTOR ReportDesc; + SIZE_T ReportLength; + ULONG nx; // // get device extension // FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); - + HidDescriptor = &FDODeviceExtension->HidDescriptor; // // let's allocate irp // @@ -300,7 +1598,7 @@ HidClassFDO_GetDescriptors( IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR); IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; - Irp->UserBuffer = &FDODeviceExtension->HidDescriptor; + Irp->UserBuffer = HidDescriptor; // // send request @@ -316,6 +1614,15 @@ HidClassFDO_GetDescriptors( return Status; } + if (Irp->IoStatus.Information != sizeof(HID_DESCRIPTOR)) + { + DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR: not valid size %x\n", + Irp->IoStatus.Information); + + IoFreeIrp(Irp); + return STATUS_DEVICE_DATA_ERROR; + } + // // let's get device attributes // @@ -323,254 +1630,701 @@ HidClassFDO_GetDescriptors( IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES); Irp->UserBuffer = &FDODeviceExtension->Common.Attributes; - // - // send request - // - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) + // + // send request + // + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed to get device descriptor + // + DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status); + IoFreeIrp(Irp); + return Status; + } + + // + // sanity checks + // + ASSERT(HidDescriptor->bLength == sizeof(HID_DESCRIPTOR)); + ASSERT(HidDescriptor->bNumDescriptors > 0); + + if (HidDescriptor->DescriptorList[0].bReportType != HID_REPORT_DESCRIPTOR_TYPE) + { + DPRINT1("[HIDCLASS] bReportType != HID_REPORT_DESCRIPTOR_TYPE (%x)\n", + HidDescriptor->DescriptorList[0].bReportType); + + IoFreeIrp(Irp); + return STATUS_DEVICE_DATA_ERROR; + } + + ReportLength = HidDescriptor->DescriptorList[0].wReportLength; + + if (!ReportLength) + { + DPRINT1("[HIDCLASS] wReportLength == 0 \n"); + IoFreeIrp(Irp); + return STATUS_DEVICE_DATA_ERROR; + } + + /* allocate report descriptor */ + ReportDesc = ExAllocatePoolWithTag(NonPagedPool, ReportLength, HIDCLASS_TAG); + + if (!ReportDesc) + { + DPRINT1("[HIDCLASS] report descriptor not allocated \n"); + IoFreeIrp(Irp); + return STATUS_INSUFFICIENT_RESOURCES; + } + + nx = 0; + + while (TRUE) + { + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_REPORT_DESCRIPTOR; + IoStack->Parameters.DeviceIoControl.OutputBufferLength = ReportLength; + Irp->UserBuffer = ReportDesc; + + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + + if (NT_SUCCESS(Status)) + { + break; + } + + Retry: + ++nx; + + if (nx >= 3) + { + goto Exit; + } + } + + if (Irp->IoStatus.Information != ReportLength) + { + Status = STATUS_DEVICE_DATA_ERROR; + goto Retry; + } + + /* save pointer on report descriptor in extension */ + FDODeviceExtension->ReportDescriptor = ReportDesc; + +Exit: + + /* deallocate report descriptor if not success */ + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(ReportDesc, 0); + } + + IoFreeIrp(Irp); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HidClassAllocCollectionResources( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN ULONG CollectionNumber) +{ + PHIDCLASS_COLLECTION HIDCollection; + ULONG DescriptorSize; + PHIDP_COLLECTION_DESC CollectionDescArray; + PVOID CollectionData; + PVOID InputReport; + PHIDP_DEVICE_DESC DeviceDescription; + ULONG InputLength; + NTSTATUS Status; + + DPRINT("[HIDCLASS] HidClassAllocCollectionResources (%x)\n", CollectionNumber); + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + + HIDCollection = GetHidclassCollection(FDODeviceExtension, CollectionNumber); + + if (!HIDCollection) + { + DPRINT1("[HIDCLASS] No HIDCollection\n"); + return STATUS_DEVICE_DATA_ERROR; + } + + DescriptorSize = HIDCollection->HidCollectInfo.DescriptorSize; + + if (!DescriptorSize) + { + DPRINT1("[HIDCLASS] DescriptorSize is 0\n"); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + CollectionData = ExAllocatePoolWithTag(NonPagedPool, + DescriptorSize, + HIDCLASS_TAG); + + HIDCollection->CollectionData = CollectionData; + + if (CollectionData) + { + Status = HidClassGetCollectionDescriptor(FDODeviceExtension, + HIDCollection->CollectionNumber, + CollectionData, + &DescriptorSize); + } + else + { + DPRINT1("[HIDCLASS] Failed allocate CollectionData\n"); + HIDCollection->CollectionData = HIDCLASS_NULL_POINTER; + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + CollectionDescArray = DeviceDescription->CollectionDesc; + InputLength = CollectionDescArray[HIDCollection->CollectionIdx].InputLength; + + if (InputLength) + { + if (HIDCollection->HidCollectInfo.Polled) + { + HIDCollection->InputReport = HIDCLASS_NULL_POINTER; + } + else + { + InputReport = ExAllocatePoolWithTag(NonPagedPool, + InputLength, + HIDCLASS_TAG); + + + HIDCollection->InputReport = InputReport; + + if (!InputReport) + { + DPRINT1("[HIDCLASS] Failed allocate InputReport\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + FDODeviceExtension->NotAllocCollectResources = FALSE; + } + else + { + DPRINT1("[HIDCLASS] InputLength is 0\n"); + HIDCollection->InputReport = HIDCLASS_NULL_POINTER; + } + + return Status; +} + +NTSTATUS +NTAPI +HidClassInitializeCollection( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN ULONG CollectionIdx) +{ + PHIDCLASS_COLLECTION HIDCollection; + PHIDP_COLLECTION_DESC HidCollectionDesc; + HID_COLLECTION_INFORMATION CollectionInfo; + PHIDP_DEVICE_DESC DeviceDescription; + ULONG CollectionNumber; + + DPRINT("[HIDCLASS] HidClassInitializeCollection (%x)\n", CollectionIdx); + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + HIDCollection = &FDODeviceExtension->HidCollections[CollectionIdx]; + + RtlZeroMemory(HIDCollection, sizeof(HIDCLASS_COLLECTION)); + + CollectionNumber = DeviceDescription->CollectionDesc[CollectionIdx].CollectionNumber; + HIDCollection->CollectionNumber = CollectionNumber; + HIDCollection->CollectionIdx = CollectionIdx; + HIDCollection->CloseFlag = 0; + + InitializeListHead(&HIDCollection->InterruptReportList); + KeInitializeSpinLock(&HIDCollection->CollectSpinLock); + KeInitializeSpinLock(&HIDCollection->CollectCloseSpinLock); + + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, CollectionNumber); + + if (!HidCollectionDesc) + { + DPRINT1("[HIDCLASS] No HidCollectionDesc (%x)\n", CollectionNumber); + return STATUS_DATA_ERROR; + } + + CollectionInfo.DescriptorSize = HidCollectionDesc->PreparsedDataLength; + CollectionInfo.Polled = FDODeviceExtension->Common.DriverExtension->DevicesArePolled; + CollectionInfo.VendorID = FDODeviceExtension->Common.Attributes.VendorID; + CollectionInfo.ProductID = FDODeviceExtension->Common.Attributes.ProductID; + CollectionInfo.VersionNumber = FDODeviceExtension->Common.Attributes.VersionNumber; + + RtlCopyMemory(&HIDCollection->HidCollectInfo, + &CollectionInfo, + sizeof(HID_COLLECTION_INFORMATION)); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HidClassFDO_StartDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + NTSTATUS Status; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + ULONG OldFdoState; + PHIDCLASS_COLLECTION HidCollections; + PHIDP_DEVICE_DESC DeviceDescription; + ULONG CollectionIdx; + ULONG CollectionNumber; + SIZE_T Length; + + DPRINT("[HIDCLASS] HidClassFDO_StartDevice: DeviceObject - %p, Irp - %p\n", DeviceObject, Irp); + + /* Get device extension */ + FDODeviceExtension = DeviceObject->DeviceExtension; + ASSERT(FDODeviceExtension->Common.IsFDO); + + /* Begin FDO start */ + OldFdoState = FDODeviceExtension->HidFdoState; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_STARTING; + + /* Query capabilities */ + Status = HidClassFDO_QueryCapabilities(DeviceObject, + &FDODeviceExtension->Capabilities); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } + + /* Let's start the lower device too */ + IoSkipCurrentIrpStackLocation(Irp); + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } + + /* Only first time initialize needed */ + if (OldFdoState == HIDCLASS_STATE_NOT_INIT) + { + /* Let's get the descriptors */ + Status = HidClassFDO_GetDescriptors(DeviceObject); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + FDODeviceExtension->ReportDescriptor = HIDCLASS_NULL_POINTER; + goto ExitError; + } + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + + /* Now get the the collection description */ + Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, + FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, + NonPagedPool, + DeviceDescription); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } + +#ifndef NDEBUG + if (DeviceDescription->ReportIDsLength > 1) + HidClassDumpDeviceDesc(DeviceDescription); +#endif + + /* Device resources alloceted successful */ + FDODeviceExtension->IsDeviceResourcesAlloceted = TRUE; + + /* Now allocete array of HIDCLASS_COLLECTION */ + Length = DeviceDescription->CollectionDescLength * sizeof(HIDCLASS_COLLECTION); + HidCollections = ExAllocatePoolWithTag(NonPagedPool, Length, HIDCLASS_TAG); + FDODeviceExtension->HidCollections = HidCollections; + + if (HidCollections) + { + RtlZeroMemory(HidCollections, Length); + } + else + { + DPRINT1("[HIDCLASS] HidCollections not allocated\n"); + FDODeviceExtension->ReportDescriptor = HIDCLASS_NULL_POINTER; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ExitError; + } + + FDODeviceExtension->NotAllocCollectResources = TRUE; + + /* Initialize collections array */ + if (DeviceDescription->CollectionDescLength) + { + CollectionIdx = 0; + + do + { + Status = HidClassInitializeCollection(FDODeviceExtension, + CollectionIdx); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed initialize Collection (Idx %x)\n", + CollectionIdx); + break; + } + + CollectionNumber = DeviceDescription->CollectionDesc[CollectionIdx].CollectionNumber; + + /* Allocete resources for current collection */ + Status = HidClassAllocCollectionResources(FDODeviceExtension, + CollectionNumber); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed alloc Collection (Idx %x) resources\n", + CollectionIdx); + break; + } + + ++CollectionIdx; + } + while (CollectionIdx < DeviceDescription->CollectionDescLength); + } + + /* For polled devices shuttles not needed */ + if (FDODeviceExtension->Common.DriverExtension->DevicesArePolled) + { + DPRINT("[HIDCLASS] DevicesArePolled \n"); + FDODeviceExtension->ShuttleCount = 0; + FDODeviceExtension->Shuttles = HIDCLASS_NULL_POINTER; + } + + /* Initialize shuttle IRPs for first time */ + if (!FDODeviceExtension->NotAllocCollectResources && + !FDODeviceExtension->Common.DriverExtension->DevicesArePolled) + { + HidClassDestroyShuttles(FDODeviceExtension); + + if (HidClassSetMaxReportSize(FDODeviceExtension)) + { + FDODeviceExtension->ShuttleCount = HIDCLASS_MINIMUM_SHUTTLE_IRPS; + + Status = HidClassInitializeShuttleIrps(FDODeviceExtension); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed initialize ShuttleIrps\n"); + FDODeviceExtension->ShuttleCount = 0; + } + } + } + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed alloc Collection (Idx %x) resources\n", + CollectionIdx); + + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } + + /* Re-enumerate PhysicalDeviceObject */ + IoInvalidateDeviceRelations(FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject, + BusRelations); + } + else if (OldFdoState != HIDCLASS_STATE_DISABLED) + { + DPRINT1("[HIDCLASS] FDO (%p) should be stopped before starting.\n", + DeviceObject); + + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + Status = STATUS_DEVICE_CONFIGURATION_ERROR; + } + + if (!NT_SUCCESS(Status)) + { +ExitError: + DPRINT("[HIDCLASS] HidClassFDO_StartDevice failed with %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + return Status; + } + + /* FDO start successful */ + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_STARTED; + + /* Complete request */ + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +VOID +NTAPI +HidClassFreeCollectionResources( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR CollectionNumber) +{ + PHIDCLASS_COLLECTION HidCollection; + + DPRINT("HidClassFreeCollectionResources: ... \n"); + + HidCollection = GetHidclassCollection(FDODeviceExtension, CollectionNumber); + + if (!HidCollection) + { + return; + } + + if (HidCollection->HidCollectInfo.Polled) + { + if (HidCollection->PollReport && + HidCollection->PollReport != HIDCLASS_NULL_POINTER) + { + ExFreePoolWithTag(HidCollection->PollReport, 0); + } + + HidCollection->PollReport = HIDCLASS_NULL_POINTER; + } + else + { + if (HidCollection->InputReport && + HidCollection->InputReport != HIDCLASS_NULL_POINTER) + { + ExFreePoolWithTag(HidCollection->InputReport, 0); + } + } + + HidCollection->InputReport = HIDCLASS_NULL_POINTER; + + if (HidCollection->CollectionData && + HidCollection->CollectionData != HIDCLASS_NULL_POINTER) + { + ExFreePoolWithTag(HidCollection->CollectionData, 0); + } + + HidCollection->CollectionData = HIDCLASS_NULL_POINTER; +} + +VOID +NTAPI +HidClassFreeDeviceResources( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PHIDCLASS_COLLECTION HidCollections; + PHIDP_REPORT_DESCRIPTOR ReportDesc; + ULONG ix; + + DPRINT("HidClassFreeDeviceResources: CollectionDescLength - %x\n", + FDODeviceExtension->Common.DeviceDescription.CollectionDescLength); + + ix = 0; + + if (FDODeviceExtension->Common.DeviceDescription.CollectionDescLength) { - // - // failed to get device descriptor - // - DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status); - IoFreeIrp(Irp); - return Status; + do + { + HidClassFreeCollectionResources(FDODeviceExtension, + FDODeviceExtension->HidCollections[ix].CollectionNumber); + ++ix; + } + while (ix < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength); } - // - // sanity checks - // - ASSERT(FDODeviceExtension->HidDescriptor.bLength == sizeof(HID_DESCRIPTOR)); - ASSERT(FDODeviceExtension->HidDescriptor.bNumDescriptors > 0); - ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength > 0); - ASSERT(FDODeviceExtension->HidDescriptor.DescriptorList[0].bReportType == HID_REPORT_DESCRIPTOR_TYPE); + if (FDODeviceExtension->IsDeviceResourcesAlloceted) + { + HidP_FreeCollectionDescription(&FDODeviceExtension->Common.DeviceDescription); + } - // - // now allocate space for the report descriptor - // - FDODeviceExtension->ReportDescriptor = ExAllocatePoolWithTag(NonPagedPool, - FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, - HIDCLASS_TAG); - if (!FDODeviceExtension->ReportDescriptor) + ReportDesc = FDODeviceExtension->ReportDescriptor; + FDODeviceExtension->Common.DeviceDescription.CollectionDescLength = 0; + + if (ReportDesc && + ReportDesc != HIDCLASS_NULL_POINTER) { - // - // not enough memory - // - IoFreeIrp(Irp); - return STATUS_INSUFFICIENT_RESOURCES; + ExFreePoolWithTag(ReportDesc, 0); } - // - // init stack location - // - IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_REPORT_DESCRIPTOR; - IoStack->Parameters.DeviceIoControl.OutputBufferLength = FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength; - Irp->UserBuffer = FDODeviceExtension->ReportDescriptor; + HidCollections = FDODeviceExtension->HidCollections; + FDODeviceExtension->ReportDescriptor = HIDCLASS_NULL_POINTER; - // - // send request - // - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) + if (HidCollections && + HidCollections != HIDCLASS_NULL_POINTER) { - // - // failed to get device descriptor - // - DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status); - IoFreeIrp(Irp); - return Status; + ExFreePoolWithTag(HidCollections, 0); } - // - // completed successfully - // - IoFreeIrp(Irp); - return STATUS_SUCCESS; + FDODeviceExtension->HidCollections = HIDCLASS_NULL_POINTER; } - -NTSTATUS -HidClassFDO_StartDevice( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) +VOID +NTAPI +HidClassDeleteDeviceObjects( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) { - NTSTATUS Status; - PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PDEVICE_RELATIONS DeviceRelations; + PDEVICE_OBJECT FDODeviceObject; + ULONG ix; - // - // get device extension - // - FDODeviceExtension = DeviceObject->DeviceExtension; - ASSERT(FDODeviceExtension->Common.IsFDO); + DPRINT("HidClassDeleteDeviceObjects: ... \n"); - // - // query capabilities - // - Status = HidClassFDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities); - if (!NT_SUCCESS(Status)) + FDODeviceObject = FDODeviceExtension->FDODeviceObject; + + DeviceRelations = FDODeviceExtension->DeviceRelations; + FDODeviceExtension->FDODeviceObject = HIDCLASS_NULL_POINTER; + + if (DeviceRelations && + DeviceRelations != HIDCLASS_NULL_POINTER) { - DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status); - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + ix = 0; + + DPRINT("HidClassDeleteDeviceObjects: DeviceRelations->Count - %x\n", + DeviceRelations->Count); + + if (DeviceRelations->Count) + { + do + { + DPRINT("HidClassDeleteDeviceObjects: IoDeleteDevice(PDO %p)\n", + FDODeviceExtension->DeviceRelations->Objects[ix]); + + ObDereferenceObject(FDODeviceExtension->DeviceRelations->Objects[ix]); + IoDeleteDevice(FDODeviceExtension->DeviceRelations->Objects[ix]); + + ++ix; + } + while (ix < FDODeviceExtension->DeviceRelations->Count); + } + + ExFreePoolWithTag(FDODeviceExtension->DeviceRelations, 0); } - // - // let's start the lower device too - // - IoSkipCurrentIrpStackLocation(Irp); - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) + FDODeviceExtension->DeviceRelations = HIDCLASS_NULL_POINTER; + + if (FDODeviceExtension->ClientPdoExtensions && + FDODeviceExtension->ClientPdoExtensions != HIDCLASS_NULL_POINTER) { - DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status); - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + ExFreePoolWithTag(FDODeviceExtension->ClientPdoExtensions, 0); } - // - // let's get the descriptors - // - Status = HidClassFDO_GetDescriptors(DeviceObject); - if (!NT_SUCCESS(Status)) + FDODeviceExtension->ClientPdoExtensions = HIDCLASS_NULL_POINTER; + + DPRINT("HidClassDeleteDeviceObjects: IoDeleteDevice(FDO %p)\n", + FDODeviceObject); + + ObDereferenceObject(FDODeviceObject); + IoDeleteDevice(FDODeviceObject); +} + +NTSTATUS +NTAPI +HidClassCleanUpFDO( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + NTSTATUS Status; + + DPRINT("HidClassCleanUpFDO: OpenCount - %x\n", FDODeviceExtension->OpenCount); + + if (FDODeviceExtension->OpenCount) { - DPRINT1("[HIDCLASS] Failed to retrieve the descriptors %x\n", Status); - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + Status = STATUS_UNSUCCESSFUL; } - - // - // now get the the collection description - // - Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, NonPagedPool, &FDODeviceExtension->Common.DeviceDescription); - if (!NT_SUCCESS(Status)) + else { - DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status); - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + HidClassFreeDeviceResources(FDODeviceExtension); + + // FIXME: + //IoWMIRegistrationControl(FDODeviceExtension->FDODeviceObject, + // WMIREG_ACTION_DEREGISTER); + + HidClassDeleteDeviceObjects(FDODeviceExtension); + Status = STATUS_SUCCESS; } - // - // complete request - // - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } NTSTATUS +NTAPI HidClassFDO_RemoveDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS Status; PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHID_DEVICE_EXTENSION HidDeviceExtension; + ULONG FdoPrevState; + + DPRINT("HidClassFDO_RemoveDevice: Irp - %p\n", Irp); - // // get device extension - // FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); - /* FIXME cleanup */ + FdoPrevState = FDODeviceExtension->HidFdoPrevState; - // - // dispatch to minidriver - // - IoSkipCurrentIrpStackLocation(Irp); - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (FdoPrevState == HIDCLASS_STATE_FAILED || + FdoPrevState == HIDCLASS_STATE_DISABLED || + HidClassAllPdoInitialized(FDODeviceExtension, 0)) + { + HidClassDestroyShuttles(FDODeviceExtension); - // - // complete request - // - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); + Irp->IoStatus.Status = STATUS_SUCCESS; - // - // detach and delete device - // - IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); - IoDeleteDevice(DeviceObject); + IoSkipCurrentIrpStackLocation(Irp); - return Status; -} + Status = HidClassFDO_DispatchRequest(FDODeviceExtension->FDODeviceObject, + Irp); -NTSTATUS -HidClassFDO_CopyDeviceRelations( - IN PDEVICE_OBJECT DeviceObject, - OUT PDEVICE_RELATIONS *OutRelations) -{ - PDEVICE_RELATIONS DeviceRelations; - PHIDCLASS_FDO_EXTENSION FDODeviceExtension; - ULONG Index; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_DELETED; - // - // get device extension - // - FDODeviceExtension = DeviceObject->DeviceExtension; - ASSERT(FDODeviceExtension->Common.IsFDO); + DerefDriverExt(FDODeviceExtension->Common.DriverExtension->DriverObject); + FDODeviceExtension->Common.DriverExtension = HIDCLASS_NULL_POINTER; - // - // allocate result - // - DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, - sizeof(DEVICE_RELATIONS) + (FDODeviceExtension->DeviceRelations->Count - 1) * sizeof(PDEVICE_OBJECT), - HIDCLASS_TAG); - if (!DeviceRelations) - { - // - // no memory - // - *OutRelations = NULL; - return STATUS_INSUFFICIENT_RESOURCES; - } + HidDeviceExtension = &FDODeviceExtension->Common.HidDeviceExtension; + IoDetachDevice(HidDeviceExtension->NextDeviceObject); - // - // copy device objects - // - for (Index = 0; Index < FDODeviceExtension->DeviceRelations->Count; Index++) + HidClassCleanUpFDO(FDODeviceExtension); + } + else { - // - // reference pdo - // - ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[Index]); - - // - // store object - // - DeviceRelations->Objects[Index] = FDODeviceExtension->DeviceRelations->Objects[Index]; + Status = STATUS_DEVICE_CONFIGURATION_ERROR; } - // - // set object count - // - DeviceRelations->Count = FDODeviceExtension->DeviceRelations->Count; - - // - // store result - // - *OutRelations = DeviceRelations; - return STATUS_SUCCESS; + return Status; } NTSTATUS HidClassFDO_DeviceRelations( - IN PDEVICE_OBJECT DeviceObject, + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, IN PIRP Irp) { - PHIDCLASS_FDO_EXTENSION FDODeviceExtension; PIO_STACK_LOCATION IoStack; NTSTATUS Status; PDEVICE_RELATIONS DeviceRelations; + ULONG PdoIdx; + KIRQL OldIrql; - // - // get device extension - // - FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); + DPRINT("[HIDCLASS]: HidClassFDO_DeviceRelations FDODeviceExtension %p\n", + FDODeviceExtension); + // // get current irp stack location // @@ -585,45 +2339,115 @@ HidClassFDO_DeviceRelations( // only bus relations are handled // IoSkipCurrentIrpStackLocation(Irp); - return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp); + + return IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, + Irp); } - if (FDODeviceExtension->DeviceRelations == NULL) + if (FDODeviceExtension->DeviceRelations && + FDODeviceExtension->DeviceRelations != HIDCLASS_NULL_POINTER) { - // - // time to create the pdos - // - Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations); + Status = STATUS_SUCCESS; + } + else + { + /* time to create the pdos */ + Status = HidClassCreatePDOs(FDODeviceExtension->FDODeviceObject, + &FDODeviceExtension->DeviceRelations); + if (!NT_SUCCESS(Status)) { - // - // failed - // DPRINT1("[HIDCLASS] HidClassPDO_CreatePDO failed with %x\n", Status); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; + return Status; } - // - // sanity check - // + ASSERT(FDODeviceExtension->DeviceRelations->Count > 0); } - // - // now copy device relations - // - Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations); - // - // store result - // - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + DeviceRelations = FDODeviceExtension->DeviceRelations; + KeAcquireSpinLock(&FDODeviceExtension->HidRelationSpinLock, &OldIrql); + + DPRINT("[HIDCLASS] IsNotifyPresence - %x\n", + FDODeviceExtension->IsNotifyPresence); + + if (FDODeviceExtension->IsNotifyPresence) + { + PDEVICE_RELATIONS NewDeviceRelations; + PDEVICE_OBJECT DeviceObject; + ULONG Length; + + FDODeviceExtension->IsRelationsOn = TRUE; + KeReleaseSpinLock(&FDODeviceExtension->HidRelationSpinLock, OldIrql); + + /* now copy device relations */ + Length = sizeof(DEVICE_RELATIONS) + + DeviceRelations->Count * sizeof(PDEVICE_OBJECT); + + NewDeviceRelations = ExAllocatePoolWithTag(PagedPool, + Length, + HIDCLASS_TAG); + + RtlCopyMemory(NewDeviceRelations, DeviceRelations, Length); + + /* store result */ + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = (ULONG_PTR)NewDeviceRelations; + + DPRINT("[HIDCLASS] IoStatus: Status %x, Information - %p\n", + Status, + NewDeviceRelations); + + if (NewDeviceRelations) + { + PdoIdx = 0; + + DPRINT("[HIDCLASS] DeviceRelations->Count - %x\n", + DeviceRelations->Count); + + if ( FDODeviceExtension->DeviceRelations->Count ) + { + do + { + ObReferenceObject(FDODeviceExtension->DeviceRelations->Objects[PdoIdx]); + DeviceObject = FDODeviceExtension->DeviceRelations->Objects[PdoIdx]; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + ++PdoIdx; + } + while ( PdoIdx < FDODeviceExtension->DeviceRelations->Count ); + } + } + } + else + { + FDODeviceExtension->IsRelationsOn = FALSE; + KeReleaseSpinLock(&FDODeviceExtension->HidRelationSpinLock, OldIrql); + + DeviceRelations = ExAllocatePoolWithTag(PagedPool, + sizeof(DEVICE_RELATIONS), + HIDCLASS_TAG); + + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + + if (DeviceRelations) + { + if (DeviceRelations != HIDCLASS_NULL_POINTER) + { + ExFreePoolWithTag(DeviceRelations, 0); + } + + DeviceRelations = HIDCLASS_NULL_POINTER; + DeviceRelations->Count = 0; + DeviceRelations->Objects[0] = NULL; + } + } + + if (!Irp->IoStatus.Information) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } - // - // complete request - // - IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } @@ -634,18 +2458,26 @@ HidClassFDO_PnP( { PIO_STACK_LOCATION IoStack; PHIDCLASS_FDO_EXTENSION FDODeviceExtension; - NTSTATUS Status; + NTSTATUS Status = ERROR_SEVERITY_WARNING; + BOOLEAN IsCompleteIrp = FALSE; - // // get device extension - // FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); - // + if (0)//IoAcquireRemoveLock(&FDODeviceExtension->HidRemoveLock, 0)) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + // get current irp stack location - // IoStack = IoGetCurrentIrpStackLocation(Irp); + + DPRINT1("[HIDCLASS]: FDO IoStack->MinorFunction %x\n", + IoStack->MinorFunction); + switch (IoStack->MinorFunction) { case IRP_MN_START_DEVICE: @@ -658,26 +2490,89 @@ HidClassFDO_PnP( } case IRP_MN_QUERY_DEVICE_RELATIONS: { - return HidClassFDO_DeviceRelations(DeviceObject, Irp); + DPRINT("HidClassFDO_PnP: QueryDeviceRelations.Type - %x\n", + IoStack->Parameters.QueryDeviceRelations.Type); + + if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations) + { + break; + } + + Status = HidClassFDO_DeviceRelations(FDODeviceExtension, Irp); + + if (NT_SUCCESS(Status)) + { + Irp->IoStatus.Status = Status; + break; + } + + IsCompleteIrp = 1; + break; + } + case IRP_MN_SURPRISE_REMOVAL: + { + /* FIXME cancel IdleNotification */ + HidClassDestroyShuttles(FDODeviceExtension); + /* fall through */ } case IRP_MN_QUERY_REMOVE_DEVICE: + { + /* FIXME handle power Irps */ + Irp->IoStatus.Status = STATUS_SUCCESS; + FDODeviceExtension->HidFdoPrevState = FDODeviceExtension->HidFdoState; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_REMOVED; + break; + } case IRP_MN_QUERY_STOP_DEVICE: + { + Irp->IoStatus.Status = STATUS_SUCCESS; + FDODeviceExtension->HidFdoPrevState = FDODeviceExtension->HidFdoState; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_STOPPING; + break; + } case IRP_MN_CANCEL_REMOVE_DEVICE: + { + Irp->IoStatus.Status = STATUS_SUCCESS; + FDODeviceExtension->HidFdoState = FDODeviceExtension->HidFdoPrevState; + break; + } case IRP_MN_CANCEL_STOP_DEVICE: { - // - // set status to success and fall through - // Irp->IoStatus.Status = STATUS_SUCCESS; + FDODeviceExtension->HidFdoState = FDODeviceExtension->HidFdoPrevState; + break; + } + case IRP_MN_STOP_DEVICE: + { + if (FDODeviceExtension->HidFdoPrevState == HIDCLASS_STATE_STARTED) + { + HidClassCancelAllShuttleIrps(FDODeviceExtension); + } + + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_DISABLED; + IoCopyCurrentIrpStackLocationToNext(Irp); + + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + + IsCompleteIrp = 1; + break; } default: { - // - // dispatch to mini driver - // - IoCopyCurrentIrpStackLocationToNext(Irp); - Status = HidClassFDO_DispatchRequest(DeviceObject, Irp); - return Status; + break; } } + + //IoReleaseRemoveLock(&FDODeviceExtension->HidRemoveLock, 0); + + if (!IsCompleteIrp) + { + IoCopyCurrentIrpStackLocationToNext(Irp); + Status = HidClassFDO_DispatchRequest(DeviceObject, Irp); + return Status; + } + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; } diff --git a/reactos/drivers/hid/hidclass/hidclass.c b/reactos/drivers/hid/hidclass/hidclass.c index ac8c8ab97d0..805c57133d5 100644 --- a/reactos/drivers/hid/hidclass/hidclass.c +++ b/reactos/drivers/hid/hidclass/hidclass.c @@ -14,13 +14,30 @@ #include static LPWSTR ClientIdentificationAddress = L"HIDCLASS"; -static ULONG HidClassDeviceNumber = 0; +static ULONG HidClassDeviceNumber; +LIST_ENTRY DriverExtList; +FAST_MUTEX DriverExtListMutex; + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + return STATUS_SUCCESS; +} NTSTATUS NTAPI DllInitialize( IN PUNICODE_STRING RegistryPath) { + DPRINT("DllInitialize: ... \n"); + + InitializeListHead(&DriverExtList); + ExInitializeFastMutex(&DriverExtListMutex); + HidClassDeviceNumber = 0; + return STATUS_SUCCESS; } @@ -28,9 +45,117 @@ NTSTATUS NTAPI DllUnload(VOID) { + DPRINT("DllUnload: ... \n"); return STATUS_SUCCESS; } +PHIDCLASS_DRIVER_EXTENSION +NTAPI +RefDriverExt( + IN PDRIVER_OBJECT DriverObject) +{ + PHIDCLASS_DRIVER_EXTENSION DriverExtension = NULL; + PLIST_ENTRY Entry; + PDRIVER_OBJECT driverObject; + PHIDCLASS_DRIVER_EXTENSION driverExtension; + + DPRINT("RefDriverExt: DriverObject - %p\n", DriverObject); + + /* increments the given driver object extension's reference count */ + + ExAcquireFastMutex(&DriverExtListMutex); + + Entry = DriverExtList.Flink; + + if (!IsListEmpty(&DriverExtList)) + { + driverExtension = CONTAINING_RECORD(Entry, + HIDCLASS_DRIVER_EXTENSION, + DriverExtLink.Flink); + + driverObject = driverExtension->DriverObject; + + while (driverObject != DriverObject) + { + Entry = Entry->Flink; + + if (Entry == &DriverExtList) + { + goto Exit; + } + } + + DriverExtension = CONTAINING_RECORD(Entry, + HIDCLASS_DRIVER_EXTENSION, + DriverExtLink.Flink); + + ++DriverExtension->RefCount; + } + +Exit: + ExReleaseFastMutex(&DriverExtListMutex); + DPRINT("RefDriverExt: return DriverExtension - %p\n", DriverExtension); + return DriverExtension; +} + +PHIDCLASS_DRIVER_EXTENSION +NTAPI +DerefDriverExt( + IN PDRIVER_OBJECT DriverObject) +{ + PHIDCLASS_DRIVER_EXTENSION Result = NULL; + PLIST_ENTRY Entry; + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + BOOLEAN IsRemoveEntry; + + DPRINT("DerefDriverExt: DriverObject - %p\n", DriverObject); + + /* decrements the given driver object extension's reference count */ + + ExAcquireFastMutex(&DriverExtListMutex); + + Entry = DriverExtList.Flink; + + if (!IsListEmpty(&DriverExtList)) + { + while (TRUE) + { + DriverExtension = CONTAINING_RECORD(Entry, + HIDCLASS_DRIVER_EXTENSION, + DriverExtLink.Flink); + + if (DriverExtension->DriverObject == DriverObject) + { + break; + } + + Entry = Entry->Flink; + + if (Entry == &DriverExtList) + { + goto Exit; + } + } + + --DriverExtension->RefCount; + IsRemoveEntry = DriverExtension->RefCount < 0; + + /* if reference count < 0 then remove given driver object extension's link */ + if (IsRemoveEntry) + { + RemoveEntryList(Entry); + } + + Result = DriverExtension; + } + +Exit: + + ExReleaseFastMutex(&DriverExtListMutex); + DPRINT("DerefDriverExt: Result - %p\n", Result); + return Result; +} + NTSTATUS NTAPI HidClassAddDevice( @@ -44,80 +169,137 @@ HidClassAddDevice( PHIDCLASS_FDO_EXTENSION FDODeviceExtension; ULONG DeviceExtensionSize; PHIDCLASS_DRIVER_EXTENSION DriverExtension; + PHID_DEVICE_EXTENSION HidDeviceExtension; - /* increment device number */ + /* Increment device number */ InterlockedIncrement((PLONG)&HidClassDeviceNumber); - /* construct device name */ + /* Construct device name */ swprintf(CharDeviceName, L"\\Device\\_HID%08x", HidClassDeviceNumber); - /* initialize device name */ + /* Initialize device name */ RtlInitUnicodeString(&DeviceName, CharDeviceName); - /* get driver object extension */ - DriverExtension = IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress); + /* Get driver object extension */ + DriverExtension = RefDriverExt(DriverObject); + if (!DriverExtension) { - /* device removed */ + /* Device removed */ ASSERT(FALSE); return STATUS_DEVICE_CONFIGURATION_ERROR; } - /* calculate device extension size */ - DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + DriverExtension->DeviceExtensionSize; + ASSERT(DriverObject == DriverExtension->DriverObject); + + /* Calculate device extension size */ + DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + + DriverExtension->DeviceExtensionSize; + + /* Now create the device */ + Status = IoCreateDevice(DriverObject, + DeviceExtensionSize, + &DeviceName, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &NewDeviceObject); - /* now create the device */ - Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &NewDeviceObject); if (!NT_SUCCESS(Status)) { - /* failed to create device object */ + /* Failed to create device object */ + DPRINT1("IoCreateDevice failed. Status - %x", Status); ASSERT(FALSE); + DerefDriverExt(DriverObject); return Status; } - /* get device extension */ + DPRINT("HidClassAddDevice: added FDO IoCreateDevice (%p)\n", NewDeviceObject); + ObReferenceObject(NewDeviceObject); + + ASSERT(DriverObject->DeviceObject == NewDeviceObject); + ASSERT(NewDeviceObject->DriverObject == DriverObject); + + /* Get device extension */ FDODeviceExtension = NewDeviceObject->DeviceExtension; - /* zero device extension */ - RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION)); + /* Zero device extension */ + RtlZeroMemory(FDODeviceExtension, DeviceExtensionSize); + + HidDeviceExtension = &FDODeviceExtension->Common.HidDeviceExtension; - /* initialize device extension */ + /* Initialize device extension */ FDODeviceExtension->Common.IsFDO = TRUE; FDODeviceExtension->Common.DriverExtension = DriverExtension; - FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = PhysicalDeviceObject; - FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = (PVOID)((ULONG_PTR)FDODeviceExtension + sizeof(HIDCLASS_FDO_EXTENSION)); - FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, PhysicalDeviceObject); - if (FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject == NULL) + HidDeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; + FDODeviceExtension->FDODeviceObject = NewDeviceObject; + FDODeviceExtension->OutstandingRequests = 0; + FDODeviceExtension->BusNumber = HidClassDeviceNumber; + + /* Initialize FDO flags */ + FDODeviceExtension->IsNotifyPresence = TRUE; + FDODeviceExtension->IsRelationsOn = TRUE; + FDODeviceExtension->IsDeviceResourcesAlloceted = FALSE; + + /* Initialize SpinLocks */ + KeInitializeSpinLock(&FDODeviceExtension->HidRelationSpinLock); + KeInitializeSpinLock(&FDODeviceExtension->HidRemoveDeviceSpinLock); + + /* Initialize remove lock for FDO */ + IoInitializeRemoveLock(&FDODeviceExtension->HidRemoveLock, + HIDCLASS_REMOVE_LOCK_TAG, + HIDCLASS_FDO_MAX_LOCKED_MINUTES, + HIDCLASS_FDO_HIGH_WATERMARK); + + /* Calculate and save pointer to minidriver-specific portion device extension */ + HidDeviceExtension->MiniDeviceExtension = (PVOID)((ULONG_PTR)FDODeviceExtension + + sizeof(HIDCLASS_FDO_EXTENSION)); + + ASSERT((PhysicalDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); + + /* Attach new FDO to stack */ + HidDeviceExtension->NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, + PhysicalDeviceObject); + + if (HidDeviceExtension->NextDeviceObject == NULL) { - /* no PDO */ + DPRINT1("HidClassAddDevice: Attach failed. IoDeleteDevice (%p)\n", + NewDeviceObject); + IoDeleteDevice(NewDeviceObject); - DPRINT1("[HIDCLASS] failed to attach to device stack\n"); return STATUS_DEVICE_REMOVED; } - /* sanity check */ - ASSERT(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); - - /* increment stack size */ + /* Increment stack size */ NewDeviceObject->StackSize++; - /* init device object */ - NewDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; + /* FDO state is not initialized */ + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_NOT_INIT; + + /* Init device object */ + NewDeviceObject->Flags |= DO_DIRECT_IO; + NewDeviceObject->Flags |= PhysicalDeviceObject->Flags & DO_POWER_PAGABLE; NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - /* now call driver provided add device routine */ + /* Now call driver provided add device routine */ ASSERT(DriverExtension->AddDevice != 0); Status = DriverExtension->AddDevice(DriverObject, NewDeviceObject); - if (!NT_SUCCESS(Status)) + + if (NT_SUCCESS(Status)) { - /* failed */ - DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status); - IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject); - IoDeleteDevice(NewDeviceObject); - return Status; + return STATUS_SUCCESS; } - /* succeeded */ + DPRINT1("HidClassAddDevice: Failed with %x, IoDeleteDevice(%p)\n", + Status, + NewDeviceObject); + + IoDetachDevice(HidDeviceExtension->NextDeviceObject); + ObDereferenceObject(NewDeviceObject); + IoDeleteDevice(NewDeviceObject); + + DerefDriverExt(DriverObject); + return Status; } @@ -126,7 +308,23 @@ NTAPI HidClassDriverUnload( IN PDRIVER_OBJECT DriverObject) { - UNIMPLEMENTED + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + + DPRINT("HidClassDriverUnload: ... \n"); + + DriverExtension = DerefDriverExt(DriverObject); + DriverExtension->DriverUnload(DriverObject); +} + +BOOLEAN +NTAPI +HidClassPrivilegeCheck( + IN PIRP Irp) +{ + LUID PrivilegeValue; + + PrivilegeValue = RtlConvertLongToLuid(SE_TCB_PRIVILEGE); + return SeSinglePrivilegeCheck(PrivilegeValue, Irp->RequestorMode); } NTSTATUS @@ -135,80 +333,298 @@ HidClass_Create( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { + NTSTATUS Status; PIO_STACK_LOCATION IoStack; PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; - PHIDCLASS_FILEOP_CONTEXT Context; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHIDCLASS_FILEOP_CONTEXT FileContext; + PHIDCLASS_COLLECTION HidCollection; + //ULONG SessionId; + ULONG HidFdoState; + ULONG HidPdoState; + BOOLEAN IsPrivilege; + KIRQL OldIrql; - // - // get device extension - // + DPRINT("HidClass_Create: Irp - %p\n", Irp); + + Status = STATUS_SUCCESS;// IoGetRequestorSessionId(Irp, &SessionId); FIXME + + if (!NT_SUCCESS(Status)) + { + DPRINT1("HidClass_Create: unable to get requestor SessionId\n"); + goto Exit; + } + + /* Get common extension */ CommonDeviceExtension = DeviceObject->DeviceExtension; + if (CommonDeviceExtension->IsFDO) { - // - // only supported for PDO - // - Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_UNSUCCESSFUL; + DPRINT1("HidClass_Create: only supported for PDO\n"); + Status = STATUS_UNSUCCESSFUL; + goto Exit; } - // - // must be a PDO - // - ASSERT(CommonDeviceExtension->IsFDO == FALSE); - - // - // get device extension - // + /* Get device extensions */ PDODeviceExtension = DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; - // - // get stack location - // + /* Get stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IoStack->FileObject); + + Irp->IoStatus.Information = 0; + + /* Get collection */ + HidCollection = GetHidclassCollection(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); + + if (!HidCollection) + { + DPRINT1("HidClass_Create: couldn't find collection\n"); + Status = STATUS_DEVICE_NOT_CONNECTED; + goto Exit; + } + + /* Check privilege */ + IsPrivilege = HidClassPrivilegeCheck(Irp); DPRINT("ShareAccess %x\n", IoStack->Parameters.Create.ShareAccess); DPRINT("Options %x\n", IoStack->Parameters.Create.Options); DPRINT("DesiredAccess %x\n", IoStack->Parameters.Create.SecurityContext->DesiredAccess); - // - // allocate context - // - Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG); - if (!Context) + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + + /* Validate parameters */ + + if (PDODeviceExtension->RestrictionsForAnyOpen || + (PDODeviceExtension->OpenCount && !IoStack->Parameters.Create.ShareAccess)) { - // - // no memory - // - Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_INSUFFICIENT_RESOURCES; + DPRINT1("HidClass_Create: STATUS_SHARING_VIOLATION \n"); + Status = STATUS_SHARING_VIOLATION; + goto UnlockExit; } - // - // init context - // - RtlZeroMemory(Context, sizeof(HIDCLASS_FILEOP_CONTEXT)); - Context->DeviceExtension = PDODeviceExtension; - KeInitializeSpinLock(&Context->Lock); - InitializeListHead(&Context->ReadPendingIrpListHead); - InitializeListHead(&Context->IrpCompletedListHead); - KeInitializeEvent(&Context->IrpReadComplete, NotificationEvent, FALSE); + if (((IoStack->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA) && + PDODeviceExtension->RestrictionsForRead) || + ((IoStack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA) && + PDODeviceExtension->RestrictionsForWrite)) + { + DPRINT1("HidClass_Create: STATUS_SHARING_VIOLATION \n"); + Status = STATUS_SHARING_VIOLATION; + goto UnlockExit; + } - // - // store context - // - ASSERT(IoStack->FileObject); - IoStack->FileObject->FsContext = Context; + if ((PDODeviceExtension->OpensForRead > 0 && + !(IoStack->Parameters.Create.ShareAccess & FILE_SHARE_READ)) || + (PDODeviceExtension->OpensForWrite > 0 && + !(IoStack->Parameters.Create.ShareAccess & FILE_SHARE_WRITE))) + { + DPRINT1("HidClass_Create: STATUS_SHARING_VIOLATION \n"); + Status = STATUS_SHARING_VIOLATION; + goto UnlockExit; + } - // - // done - // - Irp->IoStatus.Status = STATUS_SUCCESS; + if (IoStack->Parameters.Create.Options & 1) // FIXME const. + { + DPRINT1("HidClass_Create: STATUS_NOT_A_DIRECTORY \n"); + Status = STATUS_NOT_A_DIRECTORY; + goto UnlockExit; + } + + /* Get PnP states */ + HidFdoState = FDODeviceExtension->HidFdoState; + HidPdoState = PDODeviceExtension->HidPdoState; + + DPRINT("HidClass_Create: HidFdoState - %p, HidPdoState - %p\n", + HidFdoState, + HidPdoState); + + /* Validate PnP states */ + if ((HidFdoState != HIDCLASS_STATE_STARTED && + HidFdoState != HIDCLASS_STATE_STOPPING && + HidFdoState != HIDCLASS_STATE_DISABLED) || + (HidPdoState != HIDCLASS_STATE_STARTED && + HidPdoState != HIDCLASS_STATE_FAILED && + HidPdoState != HIDCLASS_STATE_STOPPING)) + { + DPRINT1("HidClass_Create: STATUS_DEVICE_NOT_CONNECTED \n"); + Status = STATUS_DEVICE_NOT_CONNECTED; + goto UnlockExit; + } + + /* Allocate file context */ + FileContext = ExAllocatePoolWithTag(NonPagedPool, + sizeof(HIDCLASS_FILEOP_CONTEXT), + HIDCLASS_TAG); + + if (!FileContext) + { + DPRINT1("HidClass_Create: Allocate context failed\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + goto UnlockExit; + } + + /* Initialize file context */ + + RtlZeroMemory(FileContext, sizeof(HIDCLASS_FILEOP_CONTEXT)); + + FileContext->DeviceExtension = PDODeviceExtension; + FileContext->FileObject = IoStack->FileObject; + + KeInitializeSpinLock(&FileContext->Lock); + InitializeListHead(&FileContext->InterruptReadIrpList); + InitializeListHead(&FileContext->ReportList); + +//InitializeListHead(&FileContext->ReadPendingIrpListHead); +//InitializeListHead(&FileContext->IrpCompletedListHead); +//KeInitializeEvent(&FileContext->IrpReadComplete, NotificationEvent, FALSE); + + FileContext->MaxReportQueueSize = HIDCLASS_MAX_REPORT_QUEUE_SIZE; + FileContext->PendingReports = 0; + FileContext->RetryReads = 0; + + InsertTailList(&HidCollection->InterruptReportList, + &FileContext->InterruptReportLink); + + FileContext->FileAttributes = IoStack->Parameters.Create.FileAttributes; + FileContext->DesiredAccess = IoStack->Parameters.Create.SecurityContext->DesiredAccess; + FileContext->ShareAccess = IoStack->Parameters.Create.ShareAccess; + + FileContext->IsMyPrivilegeTrue = IsPrivilege; + //FileContext->SessionId = SessionId; FIXME + + /* Store pointer to file context */ + IoStack->FileObject->FsContext = FileContext; + + /* Increment open counters */ + InterlockedExchangeAdd(&FDODeviceExtension->OpenCount, 1); + InterlockedExchangeAdd(&PDODeviceExtension->OpenCount, 1); + + if (IoStack->Parameters.Create.SecurityContext->DesiredAccess & FILE_READ_DATA) + { + PDODeviceExtension->OpensForRead++; + } + + if (IoStack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA) + { + PDODeviceExtension->OpensForWrite++; + } + + if (!(IoStack->Parameters.Create.ShareAccess & FILE_SHARE_READ)) + { + PDODeviceExtension->RestrictionsForRead++; + } + + if (!(IoStack->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) + { + PDODeviceExtension->RestrictionsForWrite++; + } + + if (!IoStack->Parameters.Create.ShareAccess) + { + PDODeviceExtension->RestrictionsForAnyOpen++; + } + +UnlockExit: + KeReleaseSpinLock(&HidCollection->CollectSpinLock, OldIrql); + +Exit: + Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; + DPRINT("HidClass_Create: exit - %x\n", Status); + return Status; +} + +VOID +NTAPI +HidClassCompleteReadsForFileContext( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext) +{ + KIRQL OldIrql; + PIRP Irp; + PLIST_ENTRY Entry; + LIST_ENTRY List; + + DPRINT("HidClassCompleteReadsForFileContext: ... \n"); + + InitializeListHead(&List); + + KeAcquireSpinLock(&FileContext->Lock, &OldIrql); + + while (TRUE) + { + Irp = HidClassDequeueInterruptReadIrp(HidCollection, FileContext); + + if (!Irp) + { + break; + } + + InsertTailList(&List, &Irp->Tail.Overlay.ListEntry); + } + + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + while (TRUE) + { + if (IsListEmpty(&List)) + { + break; + } + + Entry = RemoveHeadList(&List); + + Irp = CONTAINING_RECORD(Entry, + IRP, + Tail.Overlay.ListEntry); + + Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED; + + DPRINT("HidClassCompleteReadsForFileContext: Irp - %p\n", Irp); + + IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT); + } +} + +VOID +NTAPI +HidClassFlushReportQueue( + IN PHIDCLASS_FILEOP_CONTEXT FileContext) +{ + KIRQL OldIrql; + PHIDCLASS_INT_REPORT_HEADER Header; + + KeAcquireSpinLock(&FileContext->Lock, &OldIrql); + + while (TRUE) + { + Header = HidClassDequeueInterruptReport(FileContext, MAXULONG); + + if (!Header) + { + break; + } + + ExFreePoolWithTag(Header, 0); + } + + KeReleaseSpinLock(&FileContext->Lock, OldIrql); +} + +VOID +NTAPI +HidClassDestroyFileContext( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext) +{ + DPRINT("HidClassDestroyFileContext: FileContext - %p\n", FileContext); + + HidClassFlushReportQueue(FileContext); + HidClassCompleteReadsForFileContext(HidCollection, FileContext); + ExFreePoolWithTag(FileContext, 0); } NTSTATUS @@ -217,13 +633,16 @@ HidClass_Close( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { + NTSTATUS Status; PIO_STACK_LOCATION IoStack; PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; PHIDCLASS_FILEOP_CONTEXT IrpContext; - BOOLEAN IsRequestPending = FALSE; - KIRQL OldLevel; - PLIST_ENTRY Entry; - PIRP ListIrp; + PHIDCLASS_COLLECTION HidCollection; + KIRQL OldIrql; + + DPRINT("HidClass_Close: Irp - %p\n", Irp); // // get device extension @@ -235,14 +654,18 @@ HidClass_Close( // if (CommonDeviceExtension->IsFDO) { - // + DPRINT1("HidClass_Close: Error ... \n"); // how did the request get there - // - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_INVALID_PARAMETER_1; + Status = STATUS_INVALID_PARAMETER_1; + goto Exit; } + Irp->IoStatus.Information = 0; + + /* get device extensions */ + PDODeviceExtension = DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; + // // get stack location // @@ -258,554 +681,596 @@ HidClass_Close( // get irp context // IrpContext = IoStack->FileObject->FsContext; - ASSERT(IrpContext); - // - // acquire lock - // - KeAcquireSpinLock(&IrpContext->Lock, &OldLevel); - - if (!IsListEmpty(&IrpContext->ReadPendingIrpListHead)) + if (!IrpContext) { - // - // FIXME cancel irp - // - IsRequestPending = TRUE; + DPRINT1("HidClass_Close: Error ... \n"); + Status = STATUS_DEVICE_NOT_CONNECTED; + goto Exit; } - // - // signal stop - // - IrpContext->StopInProgress = TRUE; + InterlockedExchangeAdd(&FDODeviceExtension->OpenCount, -1); - // - // release lock - // - KeReleaseSpinLock(&IrpContext->Lock, OldLevel); + HidCollection = GetHidclassCollection(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); - if (IsRequestPending) + if (!HidCollection) { - // - // wait for request to complete - // - DPRINT1("[HIDCLASS] Waiting for read irp completion...\n"); - KeWaitForSingleObject(&IrpContext->IrpReadComplete, Executive, KernelMode, FALSE, NULL); + DPRINT1("HidClass_Close: Error ... \n"); + Status = STATUS_DATA_ERROR; + goto Exit; } - // - // acquire lock - // - KeAcquireSpinLock(&IrpContext->Lock, &OldLevel); + if (FDODeviceExtension->HidFdoState == HIDCLASS_STATE_DELETED) + { + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + RemoveEntryList(&IrpContext->InterruptReportLink); + KeReleaseSpinLock(&HidCollection->CollectSpinLock, OldIrql); - // - // sanity check - // - ASSERT(IsListEmpty(&IrpContext->ReadPendingIrpListHead)); + if (IrpContext->IsMyPrivilegeTrue) + { + KeAcquireSpinLock(&HidCollection->CollectCloseSpinLock, &OldIrql); - // - // now free all irps - // - while (!IsListEmpty(&IrpContext->IrpCompletedListHead)) - { - // - // remove head irp - // - Entry = RemoveHeadList(&IrpContext->IrpCompletedListHead); + while (IrpContext->CloseCounter) + { + IrpContext->CloseCounter--; + HidCollection->CloseFlag--; + } - // - // get irp - // - ListIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + IrpContext->CloseCounter--; - // - // free the irp - // - IoFreeIrp(ListIrp); + KeReleaseSpinLock(&HidCollection->CollectCloseSpinLock, OldIrql); + } + + HidClassDestroyFileContext(HidCollection, IrpContext); + + //FIXME RemoveLock support + ASSERT(FALSE); + + if (0)//IoAcquireRemoveLock(&FDODeviceExtension->HidRemoveLock, 0)) + { + HidClassCleanUpFDO(FDODeviceExtension); + } } + else + { + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + InterlockedExchangeAdd(&PDODeviceExtension->OpenCount, -1); - // - // release lock - // - KeReleaseSpinLock(&IrpContext->Lock, OldLevel); + if (IrpContext->DesiredAccess & FILE_READ_DATA) + { + PDODeviceExtension->OpensForRead--; + } - // - // remove context - // - IoStack->FileObject->FsContext = NULL; + if (IrpContext->DesiredAccess & FILE_WRITE_DATA) + { + PDODeviceExtension->OpensForWrite--; + } - // - // free context - // - ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); + if (!(IrpContext->ShareAccess & FILE_SHARE_READ)) + { + PDODeviceExtension->RestrictionsForRead--; + } - // - // complete request - // - Irp->IoStatus.Status = STATUS_SUCCESS; + if (!(IrpContext->ShareAccess & FILE_SHARE_WRITE)) + { + PDODeviceExtension->RestrictionsForWrite--; + } + + if (!IrpContext->ShareAccess) + { + PDODeviceExtension->RestrictionsForAnyOpen--; + } + + RemoveEntryList(&IrpContext->InterruptReportLink); + KeReleaseSpinLock(&HidCollection->CollectSpinLock, OldIrql); + + if (IrpContext->IsMyPrivilegeTrue) + { + KeAcquireSpinLock(&HidCollection->CollectCloseSpinLock, &OldIrql); + + while (IrpContext->CloseCounter) + { + IrpContext->CloseCounter--; + HidCollection->CloseFlag--; + } + + IrpContext->CloseCounter--; + + KeReleaseSpinLock(&HidCollection->CollectCloseSpinLock, OldIrql); + } + + HidClassDestroyFileContext(HidCollection, IrpContext); + } + + Status = STATUS_SUCCESS; + +Exit: + /* complete request */ + Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; + return Status; } -NTSTATUS +VOID NTAPI -HidClass_ReadCompleteIrp( +HidClassCompleteIrpAsynchronously( IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Ctx) + IN PVOID Context) { - PHIDCLASS_IRP_CONTEXT IrpContext; - KIRQL OldLevel; - PUCHAR Address; - ULONG Offset; - PHIDP_COLLECTION_DESC CollectionDescription; - PHIDP_REPORT_IDS ReportDescription; - BOOLEAN IsEmpty; + PHIDCLASS_COMPLETION_WORKITEM CompletionWorkItem; - // - // get irp context - // - IrpContext = Ctx; + DPRINT("HidClassCompleteIrpAsynchronously: ... \n"); - DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql()); - DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp->IoStatus.Status); - DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp->IoStatus.Information); - DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp); - DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext->InputReportBuffer); - DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext->InputReportBufferLength); - DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext->OriginalIrp); + CompletionWorkItem = (PHIDCLASS_COMPLETION_WORKITEM)Context; + IoCompleteRequest(CompletionWorkItem->Irp, 0); + IoFreeWorkItem(CompletionWorkItem->CompleteWorkItem); + ExFreePoolWithTag(CompletionWorkItem, 0); +} - // - // copy result - // - if (Irp->IoStatus.Information) - { - // - // get address - // - Address = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority); - if (Address) - { - // - // reports may have a report id prepended - // - Offset = 0; +NTSTATUS +NTAPI +HidClass_Read( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PIO_STACK_LOCATION IoStack; + PFILE_OBJECT FileObject; + PHIDCLASS_COLLECTION HidCollection; + PHIDP_COLLECTION_DESC HidCollectionDesc; + PHIDCLASS_FILEOP_CONTEXT FileContext; + PHIDCLASS_INT_REPORT_HEADER Header; + PHIDCLASS_COMPLETION_WORKITEM CompletionWorkItem; + ULONG HidFdoState; + ULONG HidPdoState; + ULONG Length; + PVOID VAddress; + PVOID StartVAddress; + ULONG ReportSize; + ULONG BufferRemaining; + PVOID InputReportBuffer; + NTSTATUS Status; + ULONG ix; + CCHAR Increment; + BOOLEAN IsNotRunning; + KIRQL OldIrql; - // - // get collection description - // - CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, - IrpContext->FileOp->DeviceExtension->CollectionNumber); - ASSERT(CollectionDescription); + DPRINT("HidClass_Read: Irp - %p\n", Irp); - // - // get report description - // - ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, - IrpContext->FileOp->DeviceExtension->CollectionNumber); - ASSERT(ReportDescription); + /* Get device extensions */ + CommonDeviceExtension = DeviceObject->DeviceExtension; + ASSERT(CommonDeviceExtension->IsFDO == FALSE); + PDODeviceExtension = DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; - if (CollectionDescription && ReportDescription) - { - // - // calculate offset - // - ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); - Offset = CollectionDescription->InputLength - ReportDescription->InputLength; - } + /* Get current stack location */ + IoStack = IoGetCurrentIrpStackLocation(Irp); - // - // copy result - // - RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength); - } + FileObject = IoStack->FileObject; + + if (!FileObject) + { + DPRINT1("HidClass_Read: error ... \n"); + Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_PRIVILEGE_NOT_HELD; } - // - // copy result status - // - IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status; - IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information; + FileContext = FileObject->FsContext; - // - // free input report buffer - // - ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG); + if (!FileContext) + { + DPRINT1("HidClass_Read: error ... \n"); + Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_PRIVILEGE_NOT_HELD; + } - // - // remove us from pending list - // - KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel); + ASSERT(IoStack->FileObject->Type == IO_TYPE_FILE); - // - // remove from pending list - // - RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + HidFdoState = FDODeviceExtension->HidFdoState; + HidPdoState = PDODeviceExtension->HidPdoState; - // - // is list empty - // - IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead); + if (((HidFdoState != HIDCLASS_STATE_STARTED) && + (HidFdoState != HIDCLASS_STATE_STOPPING) && + (HidFdoState != HIDCLASS_STATE_DISABLED)) || + ((HidPdoState != HIDCLASS_STATE_STARTED) && + (HidPdoState != HIDCLASS_STATE_FAILED) && + (HidPdoState != HIDCLASS_STATE_STOPPING))) + { + DPRINT1("HidClass_Read: Not valid state. FdoState - %x, PdoState - %x\n", + HidFdoState, + HidPdoState); - // - // insert into completed list - // - InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry); + Status = STATUS_DEVICE_NOT_CONNECTED; + goto Exit; + } - // - // release lock - // - KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel); + if (HidFdoState == HIDCLASS_STATE_DISABLED || + HidFdoState == HIDCLASS_STATE_STOPPING || + HidPdoState == HIDCLASS_STATE_FAILED || + HidPdoState == HIDCLASS_STATE_STOPPING) + { + IsNotRunning = TRUE; + } + else + { + IsNotRunning = FALSE; + } - // - // complete original request - // - IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT); + Irp->IoStatus.Information = 0; + HidCollection = GetHidclassCollection(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); - DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty); - if (IrpContext->FileOp->StopInProgress && IsEmpty) + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); + + if (!HidCollection || !HidCollectionDesc) { - // - // last pending irp - // - DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n"); - KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE); + DPRINT1("HidClass_Read: error ... \n"); + Status = STATUS_DEVICE_NOT_CONNECTED; + + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; } - if (IrpContext->FileOp->StopInProgress && IsEmpty) + Length = IoStack->Parameters.Read.Length; + + if (Length < HidCollectionDesc->InputLength) { - // - // last pending irp - // - DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n"); - KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE); + DPRINT1("HidClass_Read: error ... \n"); + Status = STATUS_INVALID_BUFFER_SIZE; + + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; } - // - // free irp context - // - ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); + DPRINT("HidClass_Read: Polled - %x\n", HidCollection->HidCollectInfo.Polled); - // - // done - // - return STATUS_MORE_PROCESSING_REQUIRED; -} + if (!HidCollection->HidCollectInfo.Polled) + { + KeAcquireSpinLock(&FileContext->Lock, &OldIrql); -PIRP -HidClass_GetIrp( - IN PHIDCLASS_FILEOP_CONTEXT Context) -{ - KIRQL OldLevel; - PIRP Irp = NULL; - PLIST_ENTRY ListEntry; + //FIXME: PowerState implement. + if (IsNotRunning /*|| (FDODeviceExtension->DevicePowerState != PowerDeviceD0)*/) + { + Status = HidClassEnqueueInterruptReadIrp(HidCollection, FileContext, Irp); + } + else + { + BufferRemaining = IoStack->Parameters.Read.Length; + VAddress = HidClassGetSystemAddressForMdlSafe(Irp->MdlAddress); + StartVAddress = VAddress; - // - // acquire lock - // - KeAcquireSpinLock(&Context->Lock, &OldLevel); + if (!VAddress) + { + DPRINT1("HidClass_Read: Invalid buffer address\n"); + Status = STATUS_INVALID_USER_BUFFER; + KeReleaseSpinLock(&FileContext->Lock, OldIrql); - // - // is list empty? - // - if (!IsListEmpty(&Context->IrpCompletedListHead)) - { - // - // grab first entry - // - ListEntry = RemoveHeadList(&Context->IrpCompletedListHead); + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; + } + + ix = 0; + Status = STATUS_SUCCESS; + + if (BufferRemaining > 0) + { + do + { + ReportSize = BufferRemaining; + Header = HidClassDequeueInterruptReport(FileContext, ReportSize); + + if (!Header) + { + break; + } + + InputReportBuffer = (PVOID)((ULONG_PTR)Header + + sizeof(PHIDCLASS_INT_REPORT_HEADER)); + + Status = HidClassCopyInputReportToUser(FileContext, + InputReportBuffer, + &ReportSize, + VAddress); + + ExFreePoolWithTag(Header, 0); + + if (!NT_SUCCESS(Status)) + { + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; + } + + VAddress = (PVOID)((ULONG_PTR)VAddress + ReportSize); + BufferRemaining -= ReportSize; + + ++ix; + } + while (BufferRemaining); + + if (!NT_SUCCESS(Status)) + { + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; + } + + if (ix > 0) + { + Irp->IoStatus.Information = (ULONG_PTR)VAddress - + (ULONG_PTR)StartVAddress; + + KeReleaseSpinLock(&FileContext->Lock, OldIrql); - // - // get irp - // - Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); - } + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } - // - // release lock - // - KeReleaseSpinLock(&Context->Lock, OldLevel); + goto Exit; + } + } - // - // done - // - return Irp; -} + Status = HidClassEnqueueInterruptReadIrp(HidCollection, + FileContext, + Irp); + } -NTSTATUS -HidClass_BuildIrp( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP RequestIrp, - IN PHIDCLASS_FILEOP_CONTEXT Context, - IN ULONG DeviceIoControlCode, - IN ULONG BufferLength, - OUT PIRP *OutIrp, - OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext) -{ - PIRP Irp; - PIO_STACK_LOCATION IoStack; - PHIDCLASS_IRP_CONTEXT IrpContext; - PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; - PHIDP_COLLECTION_DESC CollectionDescription; - PHIDP_REPORT_IDS ReportDescription; + KeReleaseSpinLock(&FileContext->Lock, OldIrql); - // - // get an irp from fresh list - // - Irp = HidClass_GetIrp(Context); - if (!Irp) - { - // - // build new irp - // - Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); - if (!Irp) + if (Status == STATUS_PENDING) { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; + return STATUS_PENDING; } } else { - // - // re-use irp - // - IoReuseIrp(Irp, STATUS_SUCCESS); + DPRINT("HidClass_Read: Polled collection not implemented. FIXME\n"); } - // - // allocate completion context - // - IrpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT), HIDCLASS_TAG); - if (!IrpContext) +Exit: + + Irp->IoStatus.Status = Status; + + if (FileContext->RetryReads > 1) { - // - // no memory - // - IoFreeIrp(Irp); - return STATUS_INSUFFICIENT_RESOURCES; + DPRINT("HidClass_Read: RetryReads - %x\n", FileContext->RetryReads); } - // - // get device extension - // - PDODeviceExtension = DeviceObject->DeviceExtension; - ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + if (InterlockedIncrement(&FileContext->RetryReads) > 4) + { + CompletionWorkItem = ExAllocatePoolWithTag(NonPagedPool, + sizeof(HIDCLASS_COMPLETION_WORKITEM), + HIDCLASS_TAG); - // - // init irp context - // - RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT)); - IrpContext->OriginalIrp = RequestIrp; - IrpContext->FileOp = Context; + if (CompletionWorkItem) + { + PIO_WORKITEM WorkItem; - // - // get collection description - // - CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, - IrpContext->FileOp->DeviceExtension->CollectionNumber); - ASSERT(CollectionDescription); + WorkItem = IoAllocateWorkItem(PDODeviceExtension->SelfDevice); + CompletionWorkItem->CompleteWorkItem = WorkItem; - // - // get report description - // - ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, - IrpContext->FileOp->DeviceExtension->CollectionNumber); - ASSERT(ReportDescription); + CompletionWorkItem->Irp = Irp; + IoMarkIrpPending(Irp); - // - // sanity check - // - ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); + IoQueueWorkItem(CompletionWorkItem->CompleteWorkItem, + HidClassCompleteIrpAsynchronously, + DelayedWorkQueue, + CompletionWorkItem); - if (Context->StopInProgress) - { - // - // stop in progress - // - DPRINT1("[HIDCLASS] Stop In Progress\n"); - Irp->IoStatus.Status = STATUS_CANCELLED; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_CANCELLED; + InterlockedExchangeAdd(&FileContext->RetryReads, -1); + return STATUS_PENDING; + } + Increment = IO_NO_INCREMENT; + } + else + { + Increment = IO_KEYBOARD_INCREMENT; } - // - // store report length - // - IrpContext->InputReportBufferLength = ReportDescription->InputLength; + IoCompleteRequest(Irp, Increment); + InterlockedExchangeAdd(&FileContext->RetryReads, -1); + return Status; +} - // - // allocate buffer - // - IrpContext->InputReportBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpContext->InputReportBufferLength, HIDCLASS_TAG); - if (!IrpContext->InputReportBuffer) +NTSTATUS +NTAPI +HidClassInterruptWriteComplete( + IN PDEVICE_OBJECT Device, + IN PIRP Irp, + IN PVOID Context) +{ + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHIDP_COLLECTION_DESC HidCollectionDesc; + NTSTATUS Status; + + DPRINT("HidClassInterruptWriteComplete: ... \n"); + + PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)Context; + Status = Irp->IoStatus.Status; + + ExFreePoolWithTag(Irp->UserBuffer, 0); + + Irp->UserBuffer = NULL; + + if (NT_SUCCESS(Status)) { - // - // no memory - // - IoFreeIrp(Irp); - ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); - return STATUS_INSUFFICIENT_RESOURCES; - } + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; - // - // get stack location - // - IoStack = IoGetNextIrpStackLocation(Irp); + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); - // - // init stack location - // - IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode; - IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength; - IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; - IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; - Irp->UserBuffer = IrpContext->InputReportBuffer; - IoStack->DeviceObject = DeviceObject; + if (HidCollectionDesc) + { + HidClassSetDeviceBusy(FDODeviceExtension); + Irp->IoStatus.Information = HidCollectionDesc->OutputLength; + } + } - // - // store result - // - *OutIrp = Irp; - *OutIrpContext = IrpContext; + if (Irp->PendingReturned) + { + IoMarkIrpPending(Irp); + } - // - // done - // - return STATUS_SUCCESS; + return Status; } NTSTATUS NTAPI -HidClass_Read( +HidClass_Write( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; PIO_STACK_LOCATION IoStack; - PHIDCLASS_FILEOP_CONTEXT Context; - KIRQL OldLevel; + PFILE_OBJECT FileObject; + PVOID Report; + PHIDP_REPORT_IDS ReportId; + PHIDP_COLLECTION_DESC HidCollectionDesc; + PHID_XFER_PACKET XferPacket; NTSTATUS Status; - PIRP NewIrp; - PHIDCLASS_IRP_CONTEXT NewIrpContext; - PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; - // - // get current stack location - // - IoStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT("HidClass_Write: PDO - %p, Irp - %p\n", DeviceObject, Irp); - // - // get device extension - // + /* Get device extensions */ CommonDeviceExtension = DeviceObject->DeviceExtension; ASSERT(CommonDeviceExtension->IsFDO == FALSE); + PDODeviceExtension = DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; - // - // sanity check - // - ASSERT(IoStack->FileObject); - ASSERT(IoStack->FileObject->FsContext); + if (PDODeviceExtension->HidPdoState != HIDCLASS_STATE_STARTED || + FDODeviceExtension->HidFdoState != HIDCLASS_STATE_STARTED) + { + Status = STATUS_DEVICE_NOT_CONNECTED; + goto Exit; + } - // - // get context - // - Context = IoStack->FileObject->FsContext; - ASSERT(Context); + /* Get current stack location */ + IoStack = IoGetCurrentIrpStackLocation(Irp); - // - // FIXME support polled devices - // - ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE); + FileObject = IoStack->FileObject; - if (Context->StopInProgress) + if (FileObject && FileObject->FsContext == NULL) { - // - // stop in progress - // - DPRINT1("[HIDCLASS] Stop In Progress\n"); - Irp->IoStatus.Status = STATUS_CANCELLED; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_CANCELLED; + Status = STATUS_PRIVILEGE_NOT_HELD; + goto Exit; } - // - // build irp request - // - Status = HidClass_BuildIrp(DeviceObject, - Irp, - Context, - IOCTL_HID_READ_REPORT, - IoStack->Parameters.Read.Length, - &NewIrp, - &NewIrpContext); - if (!NT_SUCCESS(Status)) + // FIXME CheckIdleState(); + + Report = HidClassGetSystemAddressForMdlSafe(Irp->MdlAddress); + + if (!Report) { - // - // failed - // - DPRINT1("HidClass_BuildIrp failed with %x\n", Status); - Irp->IoStatus.Status = Status; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + Status = STATUS_INVALID_USER_BUFFER; + goto Exit; } - // - // acquire lock - // - KeAcquireSpinLock(&Context->Lock, &OldLevel); + /* first byte of the buffer is the report ID for the report */ + ReportId = GetReportIdentifier(FDODeviceExtension, *(PUCHAR)Report); - // - // insert irp into pending list - // - InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry); + if (!ReportId || !ReportId->OutputLength) + { + Status = STATUS_INVALID_PARAMETER; + goto Exit; + } - // - // set completion routine - // - IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE); + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); - // - // make next location current - // - IoSetNextIrpStackLocation(NewIrp); + if (!HidCollectionDesc) + { + Status = STATUS_INVALID_PARAMETER; + goto Exit; + } - // - // release spin lock - // - KeReleaseSpinLock(&Context->Lock, OldLevel); + if (IoStack->Parameters.Write.Length != HidCollectionDesc->OutputLength) + { + Status = STATUS_INVALID_BUFFER_SIZE; + goto Exit; + } - // - // mark irp pending - // - IoMarkIrpPending(Irp); + XferPacket = ExAllocatePoolWithTag(NonPagedPool, + sizeof(HID_XFER_PACKET), + HIDCLASS_TAG); - // - // let's dispatch the request - // - ASSERT(Context->DeviceExtension); - Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp); + if (!XferPacket) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } - // - // complete - // - return STATUS_PENDING; -} + XferPacket->reportBuffer = Report; + XferPacket->reportBufferLen = ReportId->OutputLength; + XferPacket->reportId = *XferPacket->reportBuffer; -NTSTATUS -NTAPI -HidClass_Write( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - UNIMPLEMENTED - ASSERT(FALSE); - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_NOT_IMPLEMENTED; + if (!CommonDeviceExtension->DeviceDescription.ReportIDs->ReportID) + { + ++XferPacket->reportBuffer; + } + + Irp->UserBuffer = XferPacket; + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(HID_XFER_PACKET); + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_WRITE_REPORT; + + IoSetCompletionRoutine(Irp, + HidClassInterruptWriteComplete, + PDODeviceExtension, + TRUE, + TRUE, + TRUE); + + Status = HidClassFDO_DispatchRequest(FDODeviceExtension->FDODeviceObject, + Irp); + + Irp = (PIRP)HIDCLASS_NULL_POINTER; + +Exit: + + if (Irp && Irp != HIDCLASS_NULL_POINTER) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; } NTSTATUS @@ -934,9 +1399,18 @@ HidClass_DeviceControl( IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } + case IOCTL_GET_SYS_BUTTON_CAPS: + { + DPRINT1("[HIDCLASS] IOCTL_GET_SYS_BUTTON_CAPS not implemented\n"); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_NOT_IMPLEMENTED; + } default: { - DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode); + DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", + IoStack->Parameters.DeviceIoControl.IoControlCode); + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; @@ -950,7 +1424,7 @@ HidClass_InternalDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; IoCompleteRequest(Irp, IO_NO_INCREMENT); @@ -1012,6 +1486,21 @@ HidClass_PnP( } } +NTSTATUS +NTAPI +HidClass_SystemControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT("HidClass_SystemControl: FIXME. DeviceObject - %p, Irp - %p\n", + DeviceObject, + Irp); + + UNIMPLEMENTED; + //WmiSystemControl() + return 0; +} + NTSTATUS NTAPI HidClass_DispatchDefault( @@ -1019,26 +1508,35 @@ HidClass_DispatchDefault( IN PIRP Irp) { PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHID_DEVICE_EXTENSION HidDeviceExtension; + NTSTATUS Status; - // - // get common device extension - // + DPRINT("DispatchDefault: DeviceObject - %p, Irp - %p\n", DeviceObject, Irp); + + /* Get common device extension */ CommonDeviceExtension = DeviceObject->DeviceExtension; - // - // FIXME: support PDO - // - ASSERT(CommonDeviceExtension->IsFDO == TRUE); + if ( CommonDeviceExtension->IsFDO ) + { + /* Get device extensions */ + FDODeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = &FDODeviceExtension->Common.HidDeviceExtension; - // - // skip current irp stack location - // - IoSkipCurrentIrpStackLocation(Irp); + /* Copy current IRP stack location to next*/ + IoCopyCurrentIrpStackLocationToNext(Irp); - // - // dispatch to lower device object - // - return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp); + /* Dispatch to lower PDO */ + Status = HidClassFDO_DispatchRequest(HidDeviceExtension->PhysicalDeviceObject, + Irp); + } + else + { + Status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; } NTSTATUS @@ -1053,7 +1551,10 @@ HidClassDispatch( // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); - DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction); + + DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", + IoStack->MajorFunction, + IoStack->MinorFunction); // // dispatch request based on major function @@ -1062,25 +1563,75 @@ HidClassDispatch( { case IRP_MJ_CREATE: return HidClass_Create(DeviceObject, Irp); + case IRP_MJ_CLOSE: return HidClass_Close(DeviceObject, Irp); + case IRP_MJ_READ: return HidClass_Read(DeviceObject, Irp); + case IRP_MJ_WRITE: return HidClass_Write(DeviceObject, Irp); + case IRP_MJ_DEVICE_CONTROL: return HidClass_DeviceControl(DeviceObject, Irp); + case IRP_MJ_INTERNAL_DEVICE_CONTROL: return HidClass_InternalDeviceControl(DeviceObject, Irp); + case IRP_MJ_POWER: return HidClass_Power(DeviceObject, Irp); + case IRP_MJ_PNP: return HidClass_PnP(DeviceObject, Irp); + + case IRP_MJ_SYSTEM_CONTROL: + return HidClass_SystemControl(DeviceObject, Irp); + default: return HidClass_DispatchDefault(DeviceObject, Irp); } } +BOOLEAN +NTAPI +InsertDriverExtList( + IN PHIDCLASS_DRIVER_EXTENSION DriverExtension) +{ + BOOLEAN Result = TRUE; + PLIST_ENTRY Entry; + PHIDCLASS_DRIVER_EXTENSION driverExtension = NULL; + + DPRINT("InsertDriverExtList: DriverExtension - %p\n", DriverExtension); + + ExAcquireFastMutex(&DriverExtListMutex); + + /* Add link for DriverExtension to end list */ + for (Entry = DriverExtList.Flink; ; Entry = Entry->Flink) + { + if (Entry == &DriverExtList) + { + InsertTailList(&DriverExtList, &DriverExtension->DriverExtLink); + goto Exit; + } + + driverExtension = CONTAINING_RECORD(Entry, + HIDCLASS_DRIVER_EXTENSION, + DriverExtLink.Flink); + + if (driverExtension == DriverExtension) + { + break; + } + } + + Result = FALSE; + +Exit: + ExReleaseFastMutex(&DriverExtListMutex); + return Result; +} + NTSTATUS NTAPI HidRegisterMinidriver( @@ -1088,57 +1639,76 @@ HidRegisterMinidriver( { NTSTATUS Status; PHIDCLASS_DRIVER_EXTENSION DriverExtension; + PDRIVER_OBJECT MiniDriver; - /* check if the version matches */ + /* Check if the version matches */ if (MinidriverRegistration->Revision > HID_REVISION) { - /* revision mismatch */ + /* Revision mismatch */ + DPRINT1("HIDCLASS revision is %d. Should be HID_REVISION (1)\n", + MinidriverRegistration->Revision); + ASSERT(FALSE); return STATUS_REVISION_MISMATCH; } - /* now allocate the driver object extension */ - Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject, + MiniDriver = MinidriverRegistration->DriverObject; + DPRINT("HidRegisterMinidriver: MiniDriver - %p\n", MiniDriver); + + /* Now allocate the driver object extension */ + Status = IoAllocateDriverObjectExtension(MiniDriver, ClientIdentificationAddress, sizeof(HIDCLASS_DRIVER_EXTENSION), (PVOID *)&DriverExtension); if (!NT_SUCCESS(Status)) { - /* failed to allocate driver extension */ + /* Failed to allocate driver extension */ + DPRINT1("HidRegisterMinidriver: IoAllocateDriverObjectExtension failed %x\n", + Status); + ASSERT(FALSE); return Status; } - /* zero driver extension */ + /* Zero driver extension */ RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION)); - /* init driver extension */ - DriverExtension->DriverObject = MinidriverRegistration->DriverObject; + /* Initialize driver extension */ + DriverExtension->DriverObject = MiniDriver; DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize; DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled; - DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice; - DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload; - /* copy driver dispatch routines */ + /* Copy driver dispatch routines */ RtlCopyMemory(DriverExtension->MajorFunction, - MinidriverRegistration->DriverObject->MajorFunction, + MiniDriver->MajorFunction, sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1)); - /* initialize lock */ - KeInitializeSpinLock(&DriverExtension->Lock); - - /* now replace dispatch routines */ - DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice; - DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch; - DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch; - - /* done */ + MiniDriver->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_READ] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_POWER] = HidClassDispatch; + MiniDriver->MajorFunction[IRP_MJ_PNP] = HidClassDispatch; + + ASSERT(MiniDriver->DriverExtension->AddDevice); + DriverExtension->AddDevice = MiniDriver->DriverExtension->AddDevice; + MiniDriver->DriverExtension->AddDevice = HidClassAddDevice; + + ASSERT(MiniDriver->DriverUnload); + DriverExtension->DriverUnload = MiniDriver->DriverUnload; + MiniDriver->DriverUnload = HidClassDriverUnload; + + /* Initialize reference counter */ + DriverExtension->RefCount = 0; + + /* Add driver extension to list */ + if (!InsertDriverExtList(DriverExtension)) + { + DPRINT1("HidRegisterMinidriver: InsertDriverExtList failed\n"); + Status = STATUS_DEVICE_CONFIGURATION_ERROR; + } + return STATUS_SUCCESS; } diff --git a/reactos/drivers/hid/hidclass/pdo.c b/reactos/drivers/hid/hidclass/pdo.c index 92835a69a3a..8e6545e234e 100644 --- a/reactos/drivers/hid/hidclass/pdo.c +++ b/reactos/drivers/hid/hidclass/pdo.c @@ -15,6 +15,71 @@ #define NDEBUG #include +NTSTATUS +NTAPI +HidClassSymbolicLinkOnOff( + IN PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension, + IN ULONG CollectionNumber, + IN BOOLEAN IsEnable, + IN PDEVICE_OBJECT PDODeviceObject) +{ + PHIDCLASS_COLLECTION HidCollection; + NTSTATUS Status; + + DPRINT("HidClassSymbolicLinkOnOff: CollectionNumber - %x, IsEnable - %x\n", + CollectionNumber, + IsEnable); + + HidCollection = GetHidclassCollection(PDODeviceExtension->FDODeviceExtension, + CollectionNumber); + + if (!HidCollection) + { + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + if (IsEnable) + { + PDODeviceObject->Flags |= DO_DIRECT_IO; + PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + Status = IoRegisterDeviceInterface(PDODeviceObject, + &GUID_DEVINTERFACE_HID, + NULL, + &HidCollection->SymbolicLinkName); + + DPRINT("HidClassSymbolicLinkOnOff: SymbolicLinkName - %wZ\n", + &HidCollection->SymbolicLinkName); + + if (NT_SUCCESS(Status)) + { + Status = IoSetDeviceInterfaceState(&HidCollection->SymbolicLinkName, + TRUE); + } + } + else + { + if (HidCollection->SymbolicLinkName.Buffer && + HidCollection->SymbolicLinkName.Buffer != HIDCLASS_NULL_POINTER) + { + DPRINT("HidClassSymbolicLinkOnOff: SymbolicLinkName - %wZ\n", + &HidCollection->SymbolicLinkName); + + Status = IoSetDeviceInterfaceState(&HidCollection->SymbolicLinkName, + FALSE); + + ExFreePoolWithTag(HidCollection->SymbolicLinkName.Buffer, 0); + HidCollection->SymbolicLinkName.Buffer = HIDCLASS_NULL_POINTER; + } + else + { + Status = STATUS_SUCCESS; + } + } + + return Status; +} + PHIDP_COLLECTION_DESC HidClassPDO_GetCollectionDescription( PHIDP_DEVICE_DESC DeviceDescription, @@ -349,125 +414,469 @@ HidClassPDO_HandleQueryCompatibleId( return STATUS_SUCCESS; } +BOOLEAN +NTAPI +HidClassAnyPdoInitialized( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PDEVICE_RELATIONS DeviceRelations; + PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + ULONG ix = 0; + + DPRINT("HidClassAnyPdoInitialized: ... \n"); + + DeviceRelations = FDODeviceExtension->DeviceRelations; + + if (!DeviceRelations || DeviceRelations == HIDCLASS_NULL_POINTER) + { + return FALSE; + } + + do + { + PDODeviceExtension = DeviceRelations->Objects[ix]->DeviceExtension; + + if (PDODeviceExtension->HidPdoState != HIDCLASS_STATE_NOT_INIT) + { + return TRUE; + } + + ++ix; + } + while (ix < DeviceRelations->Count); + + return FALSE; +} + +BOOLEAN +NTAPI +HidClassAllPdoInitialized( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN BOOLEAN Type) +{ + PDEVICE_RELATIONS DeviceRelations; + ULONG ix; + BOOLEAN Result = TRUE; + + DPRINT("HidClassAllPdoInitialized: FDODeviceExtension - %p, Type - %x\n", + FDODeviceExtension, + Type); + + DeviceRelations = FDODeviceExtension->DeviceRelations; + + if (DeviceRelations && + DeviceRelations != HIDCLASS_NULL_POINTER) + { + ix = 0; + + if (DeviceRelations->Count) + { + while ((Type == FALSE) != + (((PHIDCLASS_PDO_DEVICE_EXTENSION)(DeviceRelations->Objects[ix]->DeviceExtension))->HidPdoState != 1)) + { + ++ix; + + if ( ix >= DeviceRelations->Count ) + { + DPRINT("HidClassAllPdoInitialized: Result - %x\n", Result); + return Result; + } + } + + Result = FALSE; + } + } + else + { + Result = (Type == FALSE); + } + + DPRINT("HidClassAllPdoInitialized: Result - %x\n", Result); + return Result; +} + +NTSTATUS +NTAPI +HidClassPdoStart( + IN PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension, + IN PIRP Irp) +{ + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHIDCLASS_COLLECTION HidCollection; + NTSTATUS Status; + + DPRINT("HidClassPdoStart: Irp - %p, HidPdoState - %x\n", + Irp, + PDODeviceExtension->HidPdoState); + + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; + + if (PDODeviceExtension->HidPdoState == HIDCLASS_STATE_NOT_INIT) + { + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_STARTING; + } + + HidCollection = GetHidclassCollection(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); + + if (!HidCollection) + { + return STATUS_DEVICE_DATA_ERROR; + } + + // FIXME: HidclassGetSessionSecurityState(...); + + if (HidClassAnyPdoInitialized(FDODeviceExtension)) + { + DPRINT("[HIDCLASS] HidClassAnyPdoInitialized return TRUE\n"); + + if (HidCollection->HidCollectInfo.Polled) + { + DPRINT1("[HIDCLASS] Polled collections not implemented! FIXME\n"); + ASSERT(PDODeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE); + return STATUS_NOT_SUPPORTED; + } + else if (!FDODeviceExtension->NotAllocCollectResources) + { + Status = HidClassAllShuttlesStart(FDODeviceExtension); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + } + } + + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_STARTED; + + HidClassSymbolicLinkOnOff(PDODeviceExtension, + PDODeviceExtension->CollectionNumber, + TRUE, + PDODeviceExtension->SelfDevice); + + if (!PDODeviceExtension->IsGenericHid && + PDODeviceExtension->Capabilities.DeviceWake > 1 && + PDODeviceExtension->Capabilities.SystemWake > 1) + { + DPRINT("HidClassPdoStart: FIXME RemoteWake and WMI\n"); + //IoWMIRegistrationControl(PDODeviceExtension->SelfDevice, + // WMIREG_ACTION_REGISTER); + } + + if (HidClassAllPdoInitialized(FDODeviceExtension, 1)) + { + DPRINT("HidClassPdoStart: FIXME HidClassStartIdleTimeout\n"); + //HidClassStartIdleTimeout(FDODeviceExtension, 1); + } + + return Status; +} + +VOID +NTAPI +HidClassCompleteReadsForCollection( + IN PHIDCLASS_COLLECTION HidCollection) +{ + KIRQL OldIrql; + PLIST_ENTRY ReportList; + PLIST_ENTRY Entry; + LIST_ENTRY ListHead; + PKSPIN_LOCK SpinLock; + PHIDCLASS_FILEOP_CONTEXT FileContext; + + DPRINT("HidClassCompleteReadsForCollection: HidCollection - %p\n", HidCollection); + + InitializeListHead(&ListHead); + + SpinLock = &HidCollection->CollectSpinLock; + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + + ReportList = &HidCollection->InterruptReportList; + + while (!IsListEmpty(ReportList)) + { + Entry = RemoveHeadList(ReportList); + InsertTailList(&ListHead, Entry); + } + + while (TRUE) + { + if (IsListEmpty(&ListHead)) + { + break; + } + + Entry = RemoveHeadList(&ListHead); + InsertTailList(&HidCollection->InterruptReportList, Entry); + + KeReleaseSpinLock(SpinLock, OldIrql); + + FileContext = CONTAINING_RECORD(Entry, + HIDCLASS_FILEOP_CONTEXT, + InterruptReportLink); + + HidClassCompleteReadsForFileContext(HidCollection, FileContext); + + KeAcquireSpinLock(SpinLock, &OldIrql); + } + + KeReleaseSpinLock(SpinLock, OldIrql); +} + +VOID +NTAPI +HidClassRemoveCollection( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension, + IN PIRP Irp) +{ + PHIDCLASS_COLLECTION HidCollections; + + DPRINT("HidClassRemoveCollection: Irp - %p\n", Irp); + + if (PDODeviceExtension->HidPdoPrevState == HIDCLASS_STATE_NOT_INIT || + PDODeviceExtension->HidPdoState == HIDCLASS_STATE_NOT_INIT) + { + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_NOT_INIT; + return; + } + + if (!PDODeviceExtension->IsGenericHid && FDODeviceExtension && + FDODeviceExtension->Capabilities.DeviceWake > 1 && //FIXME const. + FDODeviceExtension->Capabilities.SystemWake > 1) + { + DPRINT("HidClassRemoveCollection: FIXME WMI\n"); + //WMIRegistrationControl(PDODeviceExtension->SelfDevice, + // WMIREG_ACTION_DEREGISTER); + } + + DPRINT("HidClassRemoveCollection: FIXME cancel Wake Irp\n"); + + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_NOT_INIT; + + if (FDODeviceExtension) + { + HidCollections = FDODeviceExtension->HidCollections; + + if (HidCollections && + HidCollections != (PVOID)HIDCLASS_NULL_POINTER) + { + PHIDCLASS_COLLECTION HidCollection; + + HidCollection = &HidCollections[PDODeviceExtension->PdoIdx]; + + HidClassCompleteReadsForCollection(HidCollection); + + if (HidCollection->HidCollectInfo.Polled) + { + DPRINT("HidClassRemoveCollection: FIXME stop polling\n"); + } + + DPRINT("HidClassRemoveCollection: FIXME handle PowerEvent Irp\n"); + } + } +} + +NTSTATUS +NTAPI +HidClassQueryInterface( + IN PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + //PINTERFACE Interface; + + DPRINT("HidClassQueryInterface: ... \n"); + + IoStack = Irp->Tail.Overlay.CurrentStackLocation; + + if (RtlCompareMemory(IoStack->Parameters.QueryInterface.InterfaceType, + &GUID_HID_INTERFACE_NOTIFY, + sizeof(GUID)) == sizeof(GUID)) + { + DPRINT("HidClassQueryInterface: GUID_HID_INTERFACE_NOTIFY not implemented \n"); + } + else if (RtlCompareMemory(IoStack->Parameters.QueryInterface.InterfaceType, + &GUID_HID_INTERFACE_HIDPARSE, + sizeof(GUID)) == sizeof(GUID)) + { + DPRINT("HidClassQueryInterface: GUID_HID_INTERFACE_HIDPARSE not implemented \n"); + } + + return Irp->IoStatus.Status; +} + NTSTATUS HidClassPDO_PnP( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; PIO_STACK_LOCATION IoStack; NTSTATUS Status; PPNP_BUS_INFORMATION BusInformation; PDEVICE_RELATIONS DeviceRelation; - ULONG Index, bFound; + ULONG OldState; + ULONG PdoIdx; + BOOLEAN IsDeleteDevice = FALSE; + BOOLEAN IsNotPendingDelete = FALSE; + KIRQL OldIrql; - // - // get device extension - // + /* Get device extensions */ PDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; - // - // get current irp stack location - // + if (FDODeviceExtension) + { + IsNotPendingDelete = TRUE; + + KeAcquireSpinLock(&FDODeviceExtension->HidRemoveDeviceSpinLock, &OldIrql); + + // FIXME remove lock + if (0)//IoAcquireRemoveLock(&FDODeviceExtension->HidRemoveLock, 0) == STATUS_DELETE_PENDING) + { + DPRINT("[HIDCLASS]: PDO STATUS_DELETE_PENDING\n"); + IsNotPendingDelete = FALSE; + } + + KeReleaseSpinLock(&FDODeviceExtension->HidRemoveDeviceSpinLock, OldIrql); + } + + /* Get current irp stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); - // - // handle request - // switch (IoStack->MinorFunction) { case IRP_MN_QUERY_ID: { + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_ID IdType - %x\n", + IoStack->Parameters.QueryId.IdType); + if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID) { - // - // handle query device id - // Status = HidClassPDO_HandleQueryDeviceId(DeviceObject, Irp); break; } else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) { - // - // handle instance id - // Status = HidClassPDO_HandleQueryHardwareId(DeviceObject, Irp); break; } else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID) { - // - // handle instance id - // Status = HidClassPDO_HandleQueryInstanceId(DeviceObject, Irp); break; } else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) { - // - // handle instance id - // Status = HidClassPDO_HandleQueryCompatibleId(DeviceObject, Irp); break; } - DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType); - Status = STATUS_NOT_SUPPORTED; - Irp->IoStatus.Information = 0; + /* BusQueryDeviceSerialNumber (serial number for device) or unknown */ + DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", + IoStack->Parameters.QueryId.IdType); + + Status = Irp->IoStatus.Status; break; } case IRP_MN_QUERY_CAPABILITIES: { - if (IoStack->Parameters.DeviceCapabilities.Capabilities == NULL) + PDEVICE_CAPABILITIES DeviceCapabilities; + + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_CAPABILITIES\n"); + DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities; + + if (DeviceCapabilities == NULL) { - // - // invalid request - // + /* Invalid parameter of request */ + Irp->IoStatus.Information = 0; Status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } - // - // copy capabilities - // - RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, + /* Copy capabilities from PDO extension */ + RtlCopyMemory(DeviceCapabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); + + /* Correcting capabilities fields */ + DeviceCapabilities->LockSupported = 0; + DeviceCapabilities->EjectSupported = 0; + DeviceCapabilities->Removable = 0; + DeviceCapabilities->DockDevice = 0; + DeviceCapabilities->UniqueID = 0; + DeviceCapabilities->SilentInstall = 1; + + if (PDODeviceExtension->IsGenericHid) + { + DeviceCapabilities->RawDeviceOK = 1; + } + else + { + DeviceCapabilities->RawDeviceOK = 0; + } + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = (ULONG_PTR)DeviceCapabilities; break; } case IRP_MN_QUERY_BUS_INFORMATION: { - // - // - // - BusInformation = ExAllocatePoolWithTag(NonPagedPool, sizeof(PNP_BUS_INFORMATION), HIDCLASS_TAG); + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_BUS_INFORMATION\n"); + + BusInformation = ExAllocatePoolWithTag(NonPagedPool, + sizeof(PNP_BUS_INFORMATION), + HIDCLASS_TAG); + + if (!BusInformation) + { + Irp->IoStatus.Information = 0; + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + /* Fill in result */ + RtlCopyMemory(&BusInformation->BusTypeGuid, + &GUID_BUS_TYPE_HID, + sizeof(GUID)); - // - // fill in result - // - RtlCopyMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_HID, sizeof(GUID)); BusInformation->LegacyBusType = PNPBus; - BusInformation->BusNumber = 0; //FIXME + BusInformation->BusNumber = FDODeviceExtension->BusNumber; - // - // store result - // Irp->IoStatus.Information = (ULONG_PTR)BusInformation; Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_PNP_DEVICE_STATE: { - // - // FIXME set flags when driver fails / disabled - // + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_PNP_DEVICE_STATE (%x)\n", + PDODeviceExtension->HidPdoState); + + if (PDODeviceExtension->HidPdoState == HIDCLASS_STATE_FAILED) + { + Irp->IoStatus.Information |= PNP_DEVICE_FAILED; + } + else if (PDODeviceExtension->HidPdoState == HIDCLASS_STATE_DISABLED) + { + Irp->IoStatus.Information |= PNP_DEVICE_DISABLED; + } + else if (PDODeviceExtension->HidPdoState == HIDCLASS_STATE_REMOVED || + PDODeviceExtension->HidPdoState == HIDCLASS_STATE_DELETED) + { + Irp->IoStatus.Information |= PNP_DEVICE_REMOVED; + } + Status = STATUS_SUCCESS; break; } case IRP_MN_QUERY_DEVICE_RELATIONS: { + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_DEVICE_RELATIONS Type - %x\n", + IoStack->Parameters.QueryDeviceRelations.Type); + // // only target relations are supported // @@ -483,7 +892,10 @@ HidClassPDO_PnP( // // allocate device relations // - DeviceRelation = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_RELATIONS), HIDCLASS_TAG); + DeviceRelation = ExAllocatePoolWithTag(NonPagedPool, + sizeof(DEVICE_RELATIONS), + HIDCLASS_TAG); + if (!DeviceRelation) { // @@ -497,8 +909,8 @@ HidClassPDO_PnP( // init device relation // DeviceRelation->Count = 1; - DeviceRelation->Objects[0] = DeviceObject; - ObReferenceObject(DeviceRelation->Objects[0]); + DeviceRelation->Objects[0] = PDODeviceExtension->SelfDevice; + ObReferenceObject(PDODeviceExtension->SelfDevice); // // store result @@ -509,129 +921,167 @@ HidClassPDO_PnP( } case IRP_MN_START_DEVICE: { - // - // FIXME: support polled devices - // - ASSERT(PDODeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE); + DPRINT("[HIDCLASS]: PDO IRP_MN_START_DEVICE\n"); + Status = HidClassPdoStart(PDODeviceExtension, Irp); - // - // now register the device interface - // - Status = IoRegisterDeviceInterface(PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject, - &GUID_DEVINTERFACE_HID, - NULL, - &PDODeviceExtension->DeviceInterface); - DPRINT("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status); if (NT_SUCCESS(Status)) { - // - // enable device interface - // - Status = IoSetDeviceInterfaceState(&PDODeviceExtension->DeviceInterface, TRUE); - DPRINT("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status); + DPRINT("[HIDCLASS] FIXME interface GUID_HID_INTERFACE_NOTIFY support\n"); } - // - // done - // - Status = STATUS_SUCCESS; break; } case IRP_MN_REMOVE_DEVICE: { - /* Disable the device interface */ - if (PDODeviceExtension->DeviceInterface.Length != 0) - IoSetDeviceInterfaceState(&PDODeviceExtension->DeviceInterface, FALSE); + DPRINT("[HIDCLASS]: PDO IRP_MN_REMOVE_DEVICE\n"); + HidClassRemoveCollection(FDODeviceExtension, PDODeviceExtension, Irp); - // - // remove us from the fdo's pdo list - // - bFound = FALSE; - for (Index = 0; Index < PDODeviceExtension->FDODeviceExtension->DeviceRelations->Count; Index++) - { - if (PDODeviceExtension->FDODeviceExtension->DeviceRelations->Objects[Index] == DeviceObject) - { - // - // remove us - // - bFound = TRUE; - PDODeviceExtension->FDODeviceExtension->DeviceRelations->Objects[Index] = NULL; - break; - } - } + DPRINT("[HIDCLASS] FIXME interface GUID_HID_INTERFACE_NOTIFY support\n"); - /* Complete the IRP */ - Irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest(Irp, IO_NO_INCREMENT); + Status = STATUS_SUCCESS; - if (bFound) + if (IsNotPendingDelete && FDODeviceExtension->IsRelationsOn) { - /* Delete our device object*/ - IoDeleteDevice(DeviceObject); + break; } - return STATUS_SUCCESS; + IsDeleteDevice = TRUE; + break; } case IRP_MN_QUERY_INTERFACE: { - DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n"); - - // - // do nothing - // - Status = Irp->IoStatus.Status; + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_INTERFACE\n"); + Status = HidClassQueryInterface(PDODeviceExtension, Irp); break; } - case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: + { + DPRINT("[HIDCLASS]: PDO IRP_MN_CANCEL_STOP_DEVICE\n"); + PDODeviceExtension->HidPdoState = PDODeviceExtension->HidPdoPrevState; + Status = STATUS_SUCCESS; + break; + } case IRP_MN_QUERY_STOP_DEVICE: + { + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_STOP_DEVICE\n"); + PDODeviceExtension->HidPdoPrevState = PDODeviceExtension->HidPdoState; + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_FAILED; + Status = STATUS_SUCCESS; + break; + } case IRP_MN_CANCEL_REMOVE_DEVICE: { - // - // no/op - // -#if 0 + BOOLEAN IsStarted; + + DPRINT("[HIDCLASS]: PDO IRP_MN_CANCEL_REMOVE_DEVICE\n"); + + IsStarted = (PDODeviceExtension->HidPdoPrevState == + HIDCLASS_STATE_STARTED); + + PDODeviceExtension->HidPdoState = PDODeviceExtension->HidPdoPrevState; + + if (IsStarted) + { + HidClassSymbolicLinkOnOff(PDODeviceExtension, + PDODeviceExtension->CollectionNumber, + TRUE, + PDODeviceExtension->SelfDevice); + } + + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_QUERY_REMOVE_DEVICE: + { + DPRINT("[HIDCLASS]: PDO IRP_MN_QUERY_REMOVE_DEVICE\n"); + goto Removal; + } + case IRP_MN_SURPRISE_REMOVAL: + { + DPRINT("[HIDCLASS]: PDO IRP_MN_SURPRISE_REMOVAL\n"); +Removal: + OldState = PDODeviceExtension->HidPdoState; + PDODeviceExtension->HidPdoPrevState = OldState; + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_DISABLED; + + if (((OldState == HIDCLASS_STATE_STARTED) && + (HidClassSymbolicLinkOnOff(PDODeviceExtension, + PDODeviceExtension->CollectionNumber, + FALSE, + PDODeviceExtension->SelfDevice), + OldState = PDODeviceExtension->HidPdoPrevState, + PDODeviceExtension->HidPdoPrevState == HIDCLASS_STATE_STARTED)) + || OldState == HIDCLASS_STATE_STOPPING) + { + PHIDCLASS_COLLECTION HidCollection; + + PdoIdx = PDODeviceExtension->PdoIdx; + HidCollection = &FDODeviceExtension->HidCollections[PdoIdx]; + HidClassCompleteReadsForCollection(HidCollection); + // FIXME: CompleteAllPdoPowerDelayedIrps(); + } + + Status = STATUS_SUCCESS; + break; + } + case IRP_MN_STOP_DEVICE: + { + DPRINT("[HIDCLASS]: PDO IRP_MN_STOP_DEVICE\n"); + if (PDODeviceExtension->HidPdoPrevState != HIDCLASS_STATE_NOT_INIT) + { + HidClassSymbolicLinkOnOff(PDODeviceExtension, + PDODeviceExtension->CollectionNumber, + FALSE, + PDODeviceExtension->SelfDevice); + + // FIXME: handle PowerEvent Irp; + + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_STOPPING; + + DPRINT("[HIDCLASS] FIXME interface GUID_HID_INTERFACE_NOTIFY support\n"); + } + Status = STATUS_SUCCESS; -#else - DPRINT1("Denying removal of HID device due to IRP cancellation bugs\n"); - Status = STATUS_UNSUCCESSFUL; -#endif break; } default: { - // - // do nothing - // + DPRINT("[HIDCLASS]: PDO not handled IRP_MN_\n"); Status = Irp->IoStatus.Status; break; } } - // - // complete request - // - if (Status != STATUS_PENDING) + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + if (IsDeleteDevice) { - // - // store result - // - Irp->IoStatus.Status = Status; + if (IsNotPendingDelete) + { + PdoIdx = PDODeviceExtension->PdoIdx; + FDODeviceExtension->ClientPdoExtensions[PdoIdx] = HIDCLASS_NULL_POINTER; + } - // - // complete request - // - IoCompleteRequest(Irp, IO_NO_INCREMENT); + DPRINT("HidClassPDO_PnP: IoDeleteDevice (%x)\n", + PDODeviceExtension->SelfDevice); + + ObDereferenceObject(PDODeviceExtension->SelfDevice); + IoDeleteDevice(PDODeviceExtension->SelfDevice); } - // - // done processing - // + if (IsNotPendingDelete) + { + DPRINT("HidClassPDO_PnP: FIXME remove lock\n"); + //IoReleaseRemoveLock(&FDODeviceExtension->HidRemoveLock, 0); + } + + DPRINT("HidClassPDO_PnP: exit Status - %x\n", Status); return Status; } NTSTATUS -HidClassPDO_CreatePDO( +HidClassCreatePDOs( IN PDEVICE_OBJECT DeviceObject, OUT PDEVICE_RELATIONS *OutDeviceRelations) { @@ -639,142 +1089,218 @@ HidClassPDO_CreatePDO( NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT PDODeviceObject; PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension; - ULONG Index; + ULONG PdoIdx = 0; PDEVICE_RELATIONS DeviceRelations; - ULONG Length; + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + PHIDP_DEVICE_DESC DeviceDescription; + ULONG DescLength; + ULONG CollectionNumber; + PHIDP_COLLECTION_DESC CollectionDesc; + USHORT UsagePage; + USHORT Usage; + KIRQL OldIrql; + + DPRINT("[HIDCLASS] HidClassCreatePDOs: DeviceObject %p\n", DeviceObject); - // // get device extension - // FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); - // - // first allocate device relations - // - Length = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * FDODeviceExtension->Common.DeviceDescription.CollectionDescLength; - DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, Length, HIDCLASS_TAG); + DriverExtension = RefDriverExt(FDODeviceExtension->Common.DriverExtension->DriverObject); + + if (!DriverExtension) + { + DPRINT1("[HIDCLASS] Error: DriverExtension is NULL\n"); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + DescLength = DeviceDescription->CollectionDescLength; + + if (!DescLength) + { + DPRINT1("[HIDCLASS] Error: CollectionDescLength is 0\n"); + Status = STATUS_DEVICE_CONFIGURATION_ERROR; + DerefDriverExt(FDODeviceExtension->Common.DriverExtension->DriverObject); + return Status; + } + + /* first allocate device relations */ + if (*OutDeviceRelations == NULL || + *OutDeviceRelations == HIDCLASS_NULL_POINTER) + { + ULONG RelationsLength; + + RelationsLength = sizeof(DEVICE_RELATIONS) + + DescLength * sizeof(PDEVICE_OBJECT); + + DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, + RelationsLength, + HIDCLASS_TAG); + } + if (!DeviceRelations) { - // - // no memory - // + DPRINT1("[HIDCLASS]: Allocate DeviceRelations failed\n"); + DerefDriverExt(FDODeviceExtension->Common.DriverExtension->DriverObject); return STATUS_INSUFFICIENT_RESOURCES; } - // - // zero device relations - // - RtlZeroMemory(DeviceRelations, Length); + /* allocate ClientPdoExtensions array */ + if (!FDODeviceExtension->ClientPdoExtensions || + FDODeviceExtension->ClientPdoExtensions == HIDCLASS_NULL_POINTER) + { + PVOID clientPdoExtensions; + ULONG Length; - // - // let's create a PDO for top level collection - // - Index = 0; - while (Index < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength) + Length = DescLength * sizeof(PHIDCLASS_PDO_DEVICE_EXTENSION); + + clientPdoExtensions = ExAllocatePoolWithTag(NonPagedPool, + Length, + HIDCLASS_TAG); + + FDODeviceExtension->ClientPdoExtensions = clientPdoExtensions; + } + + if (!FDODeviceExtension->ClientPdoExtensions) { - // - // let's create the device object - // - Status = IoCreateDevice(FDODeviceExtension->Common.DriverExtension->DriverObject, + DPRINT1("[HIDCLASS]: Allocate DeviceRelations failed\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(DeviceRelations, 0); + FDODeviceExtension->DeviceRelations = HIDCLASS_NULL_POINTER; + } + + goto Exit; + } + + DeviceRelations->Count = DescLength; + + if (DescLength <= 0) + { + DPRINT1("[HIDCLASS] Error: CollectionDescLength is <= 0\n"); + DerefDriverExt(FDODeviceExtension->Common.DriverExtension->DriverObject); + return Status; + } + + /* let's create a PDOs for top level collections */ + + do + { + CollectionNumber = DeviceDescription->CollectionDesc[PdoIdx].CollectionNumber; + + /* let's create the device object */ + Status = IoCreateDevice(DriverExtension->DriverObject, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject); + if (!NT_SUCCESS(Status)) { - // - // failed to create device - // DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status); - break; + goto ErrorExit; } - // - // patch stack size - // + DPRINT("[HIDCLASS] HidClassCreatePDOs: added PDO IoCreateDevice (%p)\n", + PDODeviceObject); + + CollectionDesc = &DeviceDescription->CollectionDesc[PdoIdx]; + UsagePage = CollectionDesc->UsagePage; + Usage = CollectionDesc->Usage; + + ObReferenceObject(PDODeviceObject); + + /* patch stack size */ PDODeviceObject->StackSize = DeviceObject->StackSize + 1; - // - // get device extension - // + /* get device extension */ PDODeviceExtension = PDODeviceObject->DeviceExtension; + RtlZeroMemory(PDODeviceExtension, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION)); - // // init device extension - // - PDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension; - PDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject; - PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject; PDODeviceExtension->Common.IsFDO = FALSE; - PDODeviceExtension->FDODeviceExtension = FDODeviceExtension; + + PDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = + FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension; + + PDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = + FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject; + + PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = + FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject; + + PDODeviceExtension->Common.DriverExtension = + FDODeviceExtension->Common.DriverExtension; + + PDODeviceExtension->SelfDevice = PDODeviceObject; PDODeviceExtension->FDODeviceObject = DeviceObject; - PDODeviceExtension->Common.DriverExtension = FDODeviceExtension->Common.DriverExtension; - PDODeviceExtension->CollectionNumber = FDODeviceExtension->Common.DeviceDescription.CollectionDesc[Index].CollectionNumber; + PDODeviceExtension->PdoIdx = PdoIdx; + PDODeviceExtension->CollectionNumber = CollectionNumber; + PDODeviceExtension->HidPdoState = HIDCLASS_STATE_NOT_INIT; + + KeAcquireSpinLock(&FDODeviceExtension->HidRemoveDeviceSpinLock, &OldIrql); + PDODeviceExtension->FDODeviceExtension = FDODeviceExtension; + KeReleaseSpinLock(&FDODeviceExtension->HidRemoveDeviceSpinLock, OldIrql); + + PDODeviceExtension->IsSessionSecurity = FALSE; + + PDODeviceExtension->IsGenericHid = (UsagePage == HID_USAGE_PAGE_GENERIC) && + (Usage == HID_USAGE_GENERIC_POINTER || + Usage == HID_USAGE_GENERIC_MOUSE || + Usage == HID_USAGE_GENERIC_KEYBOARD || + Usage == HID_USAGE_GENERIC_KEYPAD); - // // copy device data - // - RtlCopyMemory(&PDODeviceExtension->Common.Attributes, &FDODeviceExtension->Common.Attributes, sizeof(HID_DEVICE_ATTRIBUTES)); - RtlCopyMemory(&PDODeviceExtension->Common.DeviceDescription, &FDODeviceExtension->Common.DeviceDescription, sizeof(HIDP_DEVICE_DESC)); - RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); + RtlCopyMemory(&PDODeviceExtension->Common.Attributes, + &FDODeviceExtension->Common.Attributes, + sizeof(HID_DEVICE_ATTRIBUTES)); - // - // set device flags - // - PDODeviceObject->Flags |= DO_MAP_IO_BUFFER; + RtlCopyMemory(&PDODeviceExtension->Common.DeviceDescription, + &FDODeviceExtension->Common.DeviceDescription, + sizeof(HIDP_DEVICE_DESC)); - // - // device is initialized - // - PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + RtlCopyMemory(&PDODeviceExtension->Capabilities, + &FDODeviceExtension->Capabilities, + sizeof(DEVICE_CAPABILITIES)); - // - // store device object in device relations - // - DeviceRelations->Objects[Index] = PDODeviceObject; - DeviceRelations->Count++; + /* store device object in device relations */ + DeviceRelations->Objects[PdoIdx] = PDODeviceObject; + FDODeviceExtension->ClientPdoExtensions[PdoIdx] = PDODeviceExtension; - // - // move to next - // - Index++; + /* set device flags */ + PDODeviceObject->Flags |= DO_POWER_PAGABLE; + + /* device is initialized */ + PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + /* move to next */ + PdoIdx++; } + while (PdoIdx < DescLength); + /* store device relations */ + *OutDeviceRelations = DeviceRelations; - // - // check if creating succeeded - // if (!NT_SUCCESS(Status)) { - // - // failed - // - for (Index = 0; Index < DeviceRelations->Count; Index++) +ErrorExit: + ExFreePoolWithTag(FDODeviceExtension->ClientPdoExtensions, 0); + FDODeviceExtension->ClientPdoExtensions = HIDCLASS_NULL_POINTER; + + if (!NT_SUCCESS(Status)) { - // - // delete device - // - IoDeleteDevice(DeviceRelations->Objects[Index]); + ExFreePoolWithTag(DeviceRelations, 0); + FDODeviceExtension->DeviceRelations = HIDCLASS_NULL_POINTER; } - - // - // free device relations - // - ExFreePoolWithTag(DeviceRelations, HIDCLASS_TAG); - return Status; } - // - // store device relations - // - *OutDeviceRelations = DeviceRelations; - - // - // done - // - return STATUS_SUCCESS; +Exit: + DerefDriverExt(FDODeviceExtension->Common.DriverExtension->DriverObject); + return Status; } diff --git a/reactos/drivers/hid/hidclass/precomp.h b/reactos/drivers/hid/hidclass/precomp.h index afaa571d7d2..c73a77e7995 100644 --- a/reactos/drivers/hid/hidclass/precomp.h +++ b/reactos/drivers/hid/hidclass/precomp.h @@ -2,27 +2,96 @@ #define _HIDCLASS_PCH_ #define _HIDPI_NO_FUNCTION_MACROS_ +#include #include #include #include #include +#include #define HIDCLASS_TAG 'CdiH' +#define HIDCLASS_NULL_POINTER (PVOID)0xFFFFFFB0 + +#define HIDCLASS_STATE_NOT_INIT 1 +#define HIDCLASS_STATE_STARTING 2 +#define HIDCLASS_STATE_STARTED 3 +#define HIDCLASS_STATE_FAILED 4 +#define HIDCLASS_STATE_STOPPING 5 +#define HIDCLASS_STATE_DISABLED 6 +#define HIDCLASS_STATE_REMOVED 7 +#define HIDCLASS_STATE_DELETED 8 + +#define HIDCLASS_MINIMUM_SHUTTLE_IRPS 2 +#define HIDCLASS_MAX_REPORT_QUEUE_SIZE 32 + +/* Shuttle state */ +#define HIDCLASS_SHUTTLE_START_READ 1 +#define HIDCLASS_SHUTTLE_END_READ 2 +#define HIDCLASS_SHUTTLE_DISABLED 3 + +/* FDO remove lock */ +#define HIDCLASS_REMOVE_LOCK_TAG 'cdiH' +#define HIDCLASS_FDO_MAX_LOCKED_MINUTES 2 +#define HIDCLASS_FDO_HIGH_WATERMARK 8192 + +typedef struct _HIDCLASS_FDO_EXTENSION *PHIDCLASS_FDO_EXTENSION; +typedef struct _HIDCLASS_PDO_DEVICE_EXTENSION *PHIDCLASS_PDO_DEVICE_EXTENSION; + +/* Work item for completion IRPs */ +typedef struct _HIDCLASS_COMPLETION_WORKITEM { + PIO_WORKITEM CompleteWorkItem; + PIRP Irp; +} HIDCLASS_COMPLETION_WORKITEM, *PHIDCLASS_COMPLETION_WORKITEM; + +/* Header for interrupt report */ +typedef struct _HIDCLASS_INT_REPORT_HEADER { + LIST_ENTRY ReportLink; + ULONG InputLength; +} HIDCLASS_INT_REPORT_HEADER, *PHIDCLASS_INT_REPORT_HEADER; + +typedef struct _HIDCLASS_SHUTTLE { + LONG ShuttleState; + PIRP ShuttleIrp; + PVOID ShuttleBuffer; + LONG CancellingShuttle; + KEVENT ShuttleEvent; + KEVENT ShuttleDoneEvent; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + KTIMER ShuttleTimer; + KDPC ShuttleTimerDpc; + LARGE_INTEGER TimerPeriod; +} HIDCLASS_SHUTTLE, *PHIDCLASS_SHUTTLE; -typedef struct -{ +typedef struct _HIDCLASS_COLLECTION { + ULONG CollectionNumber; + ULONG CollectionIdx; + ULONG NumPendingReads; + LIST_ENTRY InterruptReportList; + KSPIN_LOCK CollectSpinLock; + KSPIN_LOCK CollectCloseSpinLock; + HID_COLLECTION_INFORMATION HidCollectInfo; + PVOID CollectionData; + PVOID InputReport; + ULONG CloseFlag; + PVOID PollReport; + ULONG PollReportLength; + UNICODE_STRING SymbolicLinkName; +} HIDCLASS_COLLECTION, *PHIDCLASS_COLLECTION; + +typedef struct { PDRIVER_OBJECT DriverObject; ULONG DeviceExtensionSize; BOOLEAN DevicesArePolled; + UCHAR Reserved[3]; PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; PDRIVER_ADD_DEVICE AddDevice; PDRIVER_UNLOAD DriverUnload; - KSPIN_LOCK Lock; - + LONG RefCount; + LIST_ENTRY DriverExtLink; } HIDCLASS_DRIVER_EXTENSION, *PHIDCLASS_DRIVER_EXTENSION; -typedef struct -{ +typedef struct { + // // hid device extension // @@ -50,8 +119,8 @@ typedef struct } HIDCLASS_COMMON_DEVICE_EXTENSION, *PHIDCLASS_COMMON_DEVICE_EXTENSION; -typedef struct -{ +typedef struct _HIDCLASS_FDO_EXTENSION { + // // parts shared by fdo and pdo // @@ -76,16 +145,51 @@ typedef struct // device relations // PDEVICE_RELATIONS DeviceRelations; + /* An array of pointers to _HIDCLASS_PDO_DEVICE_EXTENSION */ + PHIDCLASS_PDO_DEVICE_EXTENSION * ClientPdoExtensions; + /* FDO PnP state */ + ULONG HidFdoState; + /* Previous FDO PnP state */ + ULONG HidFdoPrevState; + /* FDO flags */ + BOOLEAN NotAllocCollectResources; + BOOLEAN IsNotifyPresence; + BOOLEAN IsRelationsOn; + BOOLEAN IsDeviceResourcesAlloceted; + /* An array of HIDCLASS_COLLECTION structures */ + PHIDCLASS_COLLECTION HidCollections; + /* Number of shuttles */ + ULONG ShuttleCount; + /* An array of PHIDCLASS_SHUTTLE structures */ + PHIDCLASS_SHUTTLE Shuttles; + /* Maximum length of reports */ + ULONG MaxReportSize; + /* Self FDO device object */ + PDEVICE_OBJECT FDODeviceObject; + LONG OutstandingRequests; + /* SpinLocks */ + KSPIN_LOCK HidRelationSpinLock; + KSPIN_LOCK HidRemoveDeviceSpinLock; + /* Opens Counter */ + LONG OpenCount; + IO_REMOVE_LOCK HidRemoveLock; + /* Bus number for IRP_MN_QUERY_BUS_INFORMATION */ + ULONG BusNumber; } HIDCLASS_FDO_EXTENSION, *PHIDCLASS_FDO_EXTENSION; -typedef struct -{ +typedef struct _HIDCLASS_PDO_DEVICE_EXTENSION { + // // parts shared by fdo and pdo // HIDCLASS_COMMON_DEVICE_EXTENSION Common; + /* PDO device object */ + PDEVICE_OBJECT SelfDevice; + /* PDO index */ + ULONG PdoIdx; + // // device capabilities // @@ -111,10 +215,27 @@ typedef struct // PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + /* PDO PnP state */ + ULONG HidPdoState; + /* Previous PDO PnP state */ + ULONG HidPdoPrevState; + /* PDO flags */ + BOOLEAN IsGenericHid; + BOOLEAN IsSessionSecurity; + UCHAR Reserved1[2]; + /* Opens Counter */ + LONG OpenCount; + LONG OpensForRead; + LONG OpensForWrite; + LONG RestrictionsForRead; + LONG RestrictionsForWrite; + LONG RestrictionsForAnyOpen; + IO_REMOVE_LOCK ClientRemoveLock; + } HIDCLASS_PDO_DEVICE_EXTENSION, *PHIDCLASS_PDO_DEVICE_EXTENSION; -typedef struct __HIDCLASS_FILEOP_CONTEXT__ -{ +typedef struct _HIDCLASS_FILEOP_CONTEXT { + // // device extension // @@ -139,11 +260,27 @@ typedef struct __HIDCLASS_FILEOP_CONTEXT__ // stop in progress indicator // BOOLEAN StopInProgress; + BOOLEAN IsMyPrivilegeTrue; + UCHAR Reserved1[2]; // // read complete event // KEVENT IrpReadComplete; + /* Read IRP pending list */ + LIST_ENTRY InterruptReadIrpList; + /* Report list */ + LIST_ENTRY ReportList; + LIST_ENTRY InterruptReportLink; + ULONG MaxReportQueueSize; + LONG PendingReports; + LONG RetryReads; + PFILE_OBJECT FileObject; + USHORT FileAttributes; + USHORT ShareAccess; + ULONG SessionId; + ULONG DesiredAccess; + ULONG CloseCounter; } HIDCLASS_FILEOP_CONTEXT, *PHIDCLASS_FILEOP_CONTEXT; @@ -174,9 +311,47 @@ typedef struct // PIO_WORKITEM CompletionWorkItem; + /* for HACK: use instead Irp->Tail.Overlay.ListEntry (use usbport) + link with pending IRPs list + */ + LIST_ENTRY ReadIrpLink; } HIDCLASS_IRP_CONTEXT, *PHIDCLASS_IRP_CONTEXT; +/* hidclass.c */ +PHIDCLASS_DRIVER_EXTENSION +NTAPI +RefDriverExt( + IN PDRIVER_OBJECT DriverObject); + +PHIDCLASS_DRIVER_EXTENSION +NTAPI +DerefDriverExt( + IN PDRIVER_OBJECT DriverObject); + +VOID +NTAPI +HidClassCompleteReadsForFileContext( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext); + /* fdo.c */ +PVOID +NTAPI +HidClassGetSystemAddressForMdlSafe( + IN PMDL MemoryDescriptorList); + +PHIDP_COLLECTION_DESC +NTAPI +GetCollectionDesc( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR CollectionNumber); + +PHIDCLASS_COLLECTION +NTAPI +GetHidclassCollection( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN ULONG CollectionNumber); + NTSTATUS HidClassFDO_PnP( IN PDEVICE_OBJECT DeviceObject, @@ -192,9 +367,64 @@ HidClassFDO_DispatchRequestSynchronous( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); +NTSTATUS +NTAPI +HidClassSubmitInterruptRead( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN PHIDCLASS_SHUTTLE Shuttle, + IN BOOLEAN * OutIsSending); + +NTSTATUS +NTAPI +HidClassCleanUpFDO( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension); + +NTSTATUS +NTAPI +HidClassEnqueueInterruptReadIrp( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN PIRP Irp); + +PIRP +NTAPI +HidClassDequeueInterruptReadIrp( + IN PHIDCLASS_COLLECTION HidCollection, + IN PHIDCLASS_FILEOP_CONTEXT FileContext); + +PHIDCLASS_INT_REPORT_HEADER +NTAPI +HidClassDequeueInterruptReport( + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN ULONG ReadLength); + +NTSTATUS +NTAPI +HidClassCopyInputReportToUser( + IN PHIDCLASS_FILEOP_CONTEXT FileContext, + IN PVOID InputReportBuffer, + IN PULONG OutLength, + IN PVOID VAddress); + +NTSTATUS +NTAPI +HidClassAllShuttlesStart( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension); + +PHIDP_REPORT_IDS +NTAPI +GetReportIdentifier( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR Id); + +VOID +NTAPI +HidClassSetDeviceBusy( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension); + /* pdo.c */ NTSTATUS -HidClassPDO_CreatePDO( +HidClassCreatePDOs( IN PDEVICE_OBJECT DeviceObject, OUT PDEVICE_RELATIONS *OutDeviceRelations); @@ -213,4 +443,10 @@ HidClassPDO_GetReportDescription( PHIDP_DEVICE_DESC DeviceDescription, ULONG CollectionNumber); +BOOLEAN +NTAPI +HidClassAllPdoInitialized( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN BOOLEAN Type); + #endif /* _HIDCLASS_PCH_ */ diff --git a/reactos/drivers/hid/hidusb/hidusb.c b/reactos/drivers/hid/hidusb/hidusb.c index 0035c1e8ec9..c960271f31f 100644 --- a/reactos/drivers/hid/hidusb/hidusb.c +++ b/reactos/drivers/hid/hidusb/hidusb.c @@ -10,6 +10,62 @@ #include "hidusb.h" +LONG +NTAPI +Hid_DecrementPendingRequests( + IN PHID_USB_DEVICE_EXTENSION HidDeviceExtension) +{ + LONG Result; + + ASSERT(HidDeviceExtension->RequestCount >= 0); + + Result = InterlockedDecrement(&HidDeviceExtension->RequestCount); + + //DPRINT("Hid_DecrementPendingRequests: RequestCount - %x\n", + // HidDeviceExtension->RequestCount); + + if (Result < 0) + { + ASSERT(HidDeviceExtension->HidState != HIDUSB_STATE_RUNNING); + + /* set event to signaled state */ + Result = KeSetEvent(&HidDeviceExtension->Event, + IO_NO_INCREMENT, + FALSE); + + DPRINT("Hid_DecrementPendingRequests: set event to signaled state\n"); + } + + return Result; +} + +NTSTATUS +NTAPI +Hid_IncrementPendingRequests( + IN PHID_USB_DEVICE_EXTENSION HidDeviceExtension) +{ + NTSTATUS Status; + + Status = STATUS_SUCCESS; + + InterlockedIncrement(&HidDeviceExtension->RequestCount); + + //DPRINT("Hid_IncrementPendingRequests: RequestCount - %x\n", + // HidDeviceExtension->RequestCount); + + if (HidDeviceExtension->HidState != HIDUSB_STATE_STARTING && + HidDeviceExtension->HidState != HIDUSB_STATE_RUNNING) + { + DPRINT("Hid_IncrementPendingRequests: Not active! RequestCount - %x\n", + HidDeviceExtension->RequestCount); + + Hid_DecrementPendingRequests(HidDeviceExtension); + Status = STATUS_NO_SUCH_DEVICE; + } + + return Status; +} + PUSBD_PIPE_INFORMATION HidUsb_GetInputInterruptInterfaceHandle( PUSBD_INTERFACE_INFORMATION InterfaceInformation) @@ -185,6 +241,8 @@ HidUsb_AbortPipe( NTSTATUS Status; PUSBD_PIPE_INFORMATION PipeInformation; + DPRINT("HidUsb_AbortPipe: ... \n"); + // // get device extension // @@ -339,6 +397,7 @@ HidUsb_ResetWorkerRoutine( ULONG PortStatus; PHID_USB_RESET_CONTEXT ResetContext; PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; DPRINT("[HIDUSB] ResetWorkerRoutine\n"); @@ -351,57 +410,55 @@ HidUsb_ResetWorkerRoutine( // get device extension // DeviceExtension = ResetContext->DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; + + Status = Hid_IncrementPendingRequests(HidDeviceExtension); // // get port status // Status = HidUsb_GetPortStatus(ResetContext->DeviceObject, &PortStatus); DPRINT("[HIDUSB] ResetWorkerRoutine GetPortStatus %x PortStatus %x\n", Status, PortStatus); + if (NT_SUCCESS(Status)) { - if (!(PortStatus & USB_PORT_STATUS_ENABLE)) + if (!(PortStatus & USBD_PORT_CONNECTED)) { - // - // port is disabled - // - Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status); - } - else - { - // - // abort pipe - // - Status = HidUsb_AbortPipe(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetWorkerRoutine AbortPipe %x\n", Status); + /* port is not connected */ + +ResetPipe: if (NT_SUCCESS(Status)) { - // - // reset port - // - Status = HidUsb_ResetPort(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetPort %x\n", Status); - if (Status == STATUS_DEVICE_DATA_ERROR) - { - // - // invalidate device state - // - IoInvalidateDeviceState(DeviceExtension->PhysicalDeviceObject); - } + /* reset interrupt pipe */ + Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject); + DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status); + } - // - // reset interrupt pipe - // - if (NT_SUCCESS(Status)) - { - // - // reset pipe - // - Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status); - } + goto Exit; + } + + /* port is connected - abort pending requests */ + Status = HidUsb_AbortPipe(ResetContext->DeviceObject); + DPRINT1("[HIDUSB] ResetWorkerRoutine AbortPipe %x\n", Status); + + if (NT_SUCCESS(Status)) + { + /* reset parent port */ + Status = HidUsb_ResetPort(ResetContext->DeviceObject); + DPRINT1("[HIDUSB] ResetPort %x\n", Status); + + if (Status == STATUS_DEVICE_DATA_ERROR) + { + /* invalidate device state */ + HidDeviceExtension->HidState = HIDUSB_STATE_FAILED; + IoInvalidateDeviceState(DeviceExtension->PhysicalDeviceObject); } + + goto ResetPipe; } + +Exit: + Hid_DecrementPendingRequests(HidDeviceExtension); } // @@ -411,8 +468,9 @@ HidUsb_ResetWorkerRoutine( IoFreeWorkItem(ResetContext->WorkItem); IoCompleteRequest(ResetContext->Irp, IO_NO_INCREMENT); ExFreePoolWithTag(ResetContext, HIDUSB_TAG); -} + Hid_DecrementPendingRequests(HidDeviceExtension); +} NTSTATUS NTAPI @@ -421,8 +479,15 @@ HidUsb_ReadReportCompletion( IN PIRP Irp, IN PVOID Context) { + PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; PURB Urb; PHID_USB_RESET_CONTEXT ResetContext; + NTSTATUS Status = STATUS_SUCCESS; + + /* get device extension */ + DeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; // // get urb @@ -430,40 +495,49 @@ HidUsb_ReadReportCompletion( Urb = Context; ASSERT(Urb); - DPRINT("[HIDUSB] HidUsb_ReadReportCompletion %p Status %x Urb Status %x\n", Irp, Irp->IoStatus, Urb->UrbHeader.Status); + DPRINT("[HIDUSB] HidUsb_ReadReportCompletion %p Status %x Urb Status %x\n", + Irp, + Irp->IoStatus.Status, + Urb->UrbHeader.Status); - if (Irp->PendingReturned) + /* did the reading report succeed */ + if (NT_SUCCESS(Irp->IoStatus.Status)) { - // - // mark irp pending - // - IoMarkIrpPending(Irp); + /* store result length */ + Irp->IoStatus.Information = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; + goto Exit; } - // - // did the reading report succeed / cancelled - // - if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->IoStatus.Status == STATUS_CANCELLED || Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED) + /* did the reading report cancelled */ + if (Irp->IoStatus.Status == STATUS_CANCELLED) { - // - // store result length - // - Irp->IoStatus.Information = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; + DPRINT1("[HIDUSB] HidUsb_ReadReportCompletion Irp %p - STATUS_CANCELLED\n", + Irp); - // - // FIXME handle error - // - ASSERT(Urb->UrbHeader.Status == USBD_STATUS_SUCCESS); + ASSERT(!Irp->CancelRoutine); + goto Exit; + } - // - // free the urb - // - ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); + /* did the reading report no device */ + if (Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED) + { + DPRINT1("[HIDUSB] HidUsb_ReadReportCompletion Irp %p - STATUS_DEVICE_NOT_CONNECTED\n", + Irp); - // - // finish completion - // - return STATUS_CONTINUE_COMPLETION; + goto Exit; + } + + DPRINT1("[HIDUSB] Read IRP %p failed with Status %x. Need reset.\n", + Irp, + Irp->IoStatus.Status); + + /* did the not active state */ + if (!NT_SUCCESS(Hid_IncrementPendingRequests(HidDeviceExtension))) + { + DPRINT1("[HIDUSB] HidUsb_ReadReportCompletion Irp %p hid state is not active\n", + Irp); + + goto Exit; } // @@ -489,33 +563,41 @@ HidUsb_ReadReportCompletion( // IoQueueWorkItem(ResetContext->WorkItem, HidUsb_ResetWorkerRoutine, DelayedWorkQueue, ResetContext); - // - // free urb - // - ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); - - // - // defer completion - // - return STATUS_MORE_PROCESSING_REQUIRED; + Status = STATUS_MORE_PROCESSING_REQUIRED; + goto Exit; } - // - // free context - // + + /* free reset context */ + DPRINT1("[HIDUSB] HidUsb_ReadReportCompletion: IoAllocateWorkItem failed\n"); ExFreePoolWithTag(ResetContext, HIDUSB_TAG); + + Hid_DecrementPendingRequests(HidDeviceExtension); + } + else + { + DPRINT1("[HIDUSB] HidUsb_ReadReportCompletion: ExAllocatePoolWithTag failed\n"); + Hid_DecrementPendingRequests(HidDeviceExtension); } +Exit: + // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); - // - // complete request - // - return STATUS_CONTINUE_COMPLETION; -} + Hid_DecrementPendingRequests(HidDeviceExtension); + + if (Irp->PendingReturned) + { + // + // mark irp pending + // + IoMarkIrpPending(Irp); + } + return Status; +} NTSTATUS NTAPI @@ -528,6 +610,7 @@ HidUsb_ReadReport( PIO_STACK_LOCATION IoStack; PURB Urb; PUSBD_PIPE_INFORMATION PipeInformation; + NTSTATUS Status; // // get device extension @@ -609,18 +692,23 @@ HidUsb_ReadReport( IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; IoStack->Parameters.Others.Argument1 = Urb; - // // set completion routine // IoSetCompletionRoutine(Irp, HidUsb_ReadReportCompletion, Urb, TRUE, TRUE, TRUE); - // - // call driver - // - return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); -} + if (!NT_SUCCESS(Hid_IncrementPendingRequests(HidDeviceExtension))) + { + ExFreePool(Urb); + Status = STATUS_NO_SUCH_DEVICE; + } + else + { + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + } + return Status; +} NTSTATUS NTAPI @@ -945,14 +1033,27 @@ Hid_PnpCompletion( IN PIRP Irp, IN PVOID Context) { - // - // signal event - // - KeSetEvent(Context, 0, FALSE); + if (Irp->PendingReturned) + { + /* mark request as pending */ + IoMarkIrpPending(Irp); + } + + /* set event to signaled state */ + KeSetEvent((PRKEVENT)Context, EVENT_INCREMENT, FALSE); - // - // done - // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +HidDispatchUrbComplete( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + /* set event to signaled state */ + KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } @@ -1011,7 +1112,7 @@ Hid_DispatchUrb( // // set completion routine // - IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE); + IoSetCompletionRoutine(Irp, HidDispatchUrbComplete, &Event, TRUE, TRUE, TRUE); // // call driver @@ -1191,6 +1292,8 @@ Hid_SelectConfiguration( PHID_USB_DEVICE_EXTENSION HidDeviceExtension; PHID_DEVICE_EXTENSION DeviceExtension; + DPRINT("Hid_SelectConfiguration: DeviceObject - %p\n", DeviceObject); + // // get device extension // @@ -1277,7 +1380,7 @@ Hid_SelectConfiguration( } NTSTATUS -Hid_DisableConfiguration( +Hid_CloseConfiguration( IN PDEVICE_OBJECT DeviceObject) { PHID_DEVICE_EXTENSION DeviceExtension; @@ -1297,12 +1400,12 @@ Hid_DisableConfiguration( Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_SELECT_CONFIGURATION), HIDUSB_URB_TAG); + if (!Urb) { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; + /* no memory */ + HidDeviceExtension->HidState = HIDUSB_STATE_STOPPED; + return STATUS_UNSUCCESSFUL; } // @@ -1319,6 +1422,7 @@ Hid_DisableConfiguration( if (!NT_SUCCESS(Status)) { DPRINT1("[HIDUSB] Dispatching unconfigure URB failed with %lx\n", Status); + HidDeviceExtension->HidState = HIDUSB_STATE_STOPPED; } else if (!USBD_SUCCESS(Urb->UrbHeader.Status)) { @@ -1330,9 +1434,19 @@ Hid_DisableConfiguration( // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); - // - // free resources - // + return Status; +} + +NTSTATUS +NTAPI +Hid_Cleanup(PDEVICE_OBJECT DeviceObject) +{ + PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; + + DeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; + HidDeviceExtension->ConfigurationHandle = NULL; if (HidDeviceExtension->InterfaceInfo) @@ -1354,9 +1468,35 @@ Hid_DisableConfiguration( HidDeviceExtension->DeviceDescriptor = NULL; } - // - // done - // + return STATUS_SUCCESS; +} + +NTSTATUS +Hid_StopDevice( + IN PDEVICE_OBJECT DeviceObject) +{ + PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; + NTSTATUS Status; + + DeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; + + HidDeviceExtension->HidState = HIDUSB_STATE_STOPPING; + + /* abort pending requests */ + HidUsb_AbortPipe(DeviceObject); + Hid_DecrementPendingRequests(HidDeviceExtension); + + KeWaitForSingleObject(&HidDeviceExtension->Event, + Executive, + KernelMode, + 0, + NULL); + + /* select configuration with NULL pointer for ConfigurationDescriptor */ + Status = Hid_CloseConfiguration(DeviceObject); + return Status; } @@ -1503,7 +1643,36 @@ Hid_GetProtocol( } NTSTATUS -Hid_PnpStart( +NTAPI +Hid_Init(PDEVICE_OBJECT DeviceObject) +{ + ULONG OldState; + PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; + + DeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; + + OldState = HidDeviceExtension->HidState; + HidDeviceExtension->HidState = HIDUSB_STATE_STARTING; + + KeResetEvent(&HidDeviceExtension->Event); + + if (OldState == HIDUSB_STATE_STOPPING || + OldState == HIDUSB_STATE_STOPPED || + OldState == HIDUSB_STATE_REMOVED) + { + /* start after stop */ + Hid_IncrementPendingRequests(HidDeviceExtension); + } + + HidDeviceExtension->InterfaceInfo = NULL; + + return STATUS_SUCCESS; +} + +NTSTATUS +Hid_StartDevice( IN PDEVICE_OBJECT DeviceObject) { PHID_USB_DEVICE_EXTENSION HidDeviceExtension; @@ -1554,19 +1723,21 @@ Hid_PnpStart( 0); if (!NT_SUCCESS(Status)) { - // - // failed to obtain device descriptor - // - DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status); + /* failed to obtain configuration descriptor */ + DPRINT1("[HIDUSB] failed to get configuration descriptor %x\n", Status); return Status; } - // - // sanity check - // + /* sanity check */ ASSERT(DescriptorLength); + ASSERT(DescriptorLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); ASSERT(HidDeviceExtension->ConfigurationDescriptor); - ASSERT(HidDeviceExtension->ConfigurationDescriptor->bLength); + + if (HidDeviceExtension->ConfigurationDescriptor->bLength == 0) + { + DPRINT1("[HIDUSB] ConfigurationDescriptor->bLength == 0\n"); + return STATUS_DEVICE_DATA_ERROR; + } // // store full length @@ -1592,13 +1763,22 @@ Hid_PnpStart( 0); if (!NT_SUCCESS(Status)) { - // - // failed to obtain device descriptor - // - DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status); + /* failed to obtain full configuration descriptor */ + DPRINT1("[HIDUSB] failed to get full configuration descriptor %x\n", Status); return Status; } + DescriptorLength = HidDeviceExtension->ConfigurationDescriptor->bLength; + + /* sanity check */ + ASSERT(DescriptorLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + if (DescriptorLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + DPRINT1("[HIDUSB] bad ConfigurationDescriptor->bLength\n"); + DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR); + } + // // now parse the descriptors // @@ -1618,18 +1798,31 @@ Hid_PnpStart( return STATUS_UNSUCCESSFUL; } - // - // sanity check - // - ASSERT(InterfaceDescriptor->bInterfaceClass == USB_DEVICE_CLASS_HUMAN_INTERFACE); + if (InterfaceDescriptor->bInterfaceClass != USB_DEVICE_CLASS_HUMAN_INTERFACE) + { + DPRINT1("[HIDUSB] bad InterfaceDescriptor->bInterfaceClass \n"); + return STATUS_UNSUCCESSFUL; + } + + if (InterfaceDescriptor->bLength < sizeof(USB_INTERFACE_DESCRIPTOR)) + { + DPRINT1("[HIDUSB] InterfaceDescriptor->bLength is invalid"); + return STATUS_UNSUCCESSFUL; + } + + /* sanity check */ ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE); - ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR)); // // move to next descriptor // HidDescriptor = (PHID_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength); - ASSERT(HidDescriptor->bLength >= 2); + + if (HidDescriptor->bLength < 2) + { + DPRINT1("[HIDUSB] HidDescriptor->bLength is invalid"); + return STATUS_UNSUCCESSFUL; + } // // check if this is the hid descriptor @@ -1673,12 +1866,68 @@ Hid_PnpStart( // set idle // and get protocol // - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); } return Status; } +NTSTATUS +NTAPI +Hid_RemoveDevice( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + ULONG OldDeviceState; + NTSTATUS Status; + PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; + + /* get device extension */ + DeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; + + /* save current state and set HIDUSB_STATE_REMOVED */ + OldDeviceState = HidDeviceExtension->HidState; + HidDeviceExtension->HidState = HIDUSB_STATE_REMOVED; + + DPRINT("[HIDUSB] Hid_RemoveDevice: OldDeviceState - %x\n", OldDeviceState); + + if (OldDeviceState != HIDUSB_STATE_STOPPING && + OldDeviceState != HIDUSB_STATE_STOPPED) + { + Hid_DecrementPendingRequests(HidDeviceExtension); + } + + /* abort pending requests if state was "running" */ + if (OldDeviceState == HIDUSB_STATE_RUNNING) + { + HidUsb_AbortPipe(DeviceObject); + } + + KeWaitForSingleObject(&HidDeviceExtension->Event, + Executive, + KernelMode, + 0, + NULL); + + DPRINT("[HIDUSB] Hid_RemoveDevice: State - %x\n", HidDeviceExtension->HidState); + + /* select configuration with NULL pointer for ConfigurationDescriptor */ + //Hid_CloseConfiguration(DeviceObject); + + /* prepare request */ + IoSkipCurrentIrpStackLocation(Irp); + Irp->IoStatus.Status = STATUS_SUCCESS; + + /* send request to driver for lower device */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + + /* free resources */ + Hid_Cleanup(DeviceObject); + + return Status; +} NTSTATUS NTAPI @@ -1689,12 +1938,14 @@ HidPnp( NTSTATUS Status; PIO_STACK_LOCATION IoStack; PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; KEVENT Event; // // get device extension // DeviceExtension = DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; // // get current stack location @@ -1702,184 +1953,118 @@ HidPnp( IoStack = IoGetCurrentIrpStackLocation(Irp); DPRINT("[HIDUSB] Pnp %x\n", IoStack->MinorFunction); - // - // handle requests based on request type - // + /* handle request before sending to lower device */ switch (IoStack->MinorFunction) { - case IRP_MN_REMOVE_DEVICE: - { - // - // unconfigure device - // FIXME: Call this on IRP_MN_SURPRISE_REMOVAL, but don't send URBs - // FIXME: Don't call this after we've already seen a surprise removal or stop - // - Hid_DisableConfiguration(DeviceObject); - - // - // pass request onto lower driver - // - IoSkipCurrentIrpStackLocation(Irp); - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - - return Status; - } - case IRP_MN_QUERY_PNP_DEVICE_STATE: - { - // - // device can not be disabled - // - Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; + case IRP_MN_START_DEVICE: + Status = Hid_Init(DeviceObject); - // - // pass request to next request - // - IoSkipCurrentIrpStackLocation(Irp); - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + break; - // - // done - // - return Status; - } - case IRP_MN_QUERY_STOP_DEVICE: - case IRP_MN_QUERY_REMOVE_DEVICE: - { - // - // we're fine with it - // - Irp->IoStatus.Status = STATUS_SUCCESS; + case IRP_MN_STOP_DEVICE: + if (HidDeviceExtension->HidState == HIDUSB_STATE_STARTING) + { + Status = Hid_StopDevice(DeviceObject); - // - // pass request to next driver - // - IoSkipCurrentIrpStackLocation(Irp); - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + } + break; - // - // done - // - return Status; - } - case IRP_MN_STOP_DEVICE: - { - // - // unconfigure device - // - Hid_DisableConfiguration(DeviceObject); + case IRP_MN_REMOVE_DEVICE: + return Hid_RemoveDevice(DeviceObject, Irp); - // - // prepare irp - // - KeInitializeEvent(&Event, NotificationEvent, FALSE); - IoCopyCurrentIrpStackLocationToNext(Irp); - IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE); + case IRP_MN_QUERY_PNP_DEVICE_STATE: + DPRINT("[HIDUSB] IRP_MN_QUERY_PNP_DEVICE_STATE. HidState - %x\n", + HidDeviceExtension->HidState); - // - // send irp and wait for completion - // - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - if (Status == STATUS_PENDING) + if (HidDeviceExtension->HidState == HIDUSB_STATE_FAILED) { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Irp->IoStatus.Status; + DPRINT1("[HIDUSB] PNP_DEVICE_FAILED!\n"); + DPRINT1("[FIXME: PnP manager have bag (IoInvalidateDeviceState())!\n"); + /* HACK: due problem disconnecting from PC USB port CORE-9070). + W2003 not call this code in it case. + */ + //Irp->IoStatus.Information |= PNP_DEVICE_FAILED; } + break; - // - // done - // - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; - } - case IRP_MN_QUERY_CAPABILITIES: - { - // - // prepare irp - // - KeInitializeEvent(&Event, NotificationEvent, FALSE); - IoCopyCurrentIrpStackLocationToNext(Irp); - IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE); + default: + break; + } - // - // send irp and wait for completion - // - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Irp->IoStatus.Status; - } + /* prepare request */ + IoCopyCurrentIrpStackLocationToNext(Irp); + KeInitializeEvent(&Event, NotificationEvent, FALSE); - if (NT_SUCCESS(Status) && IoStack->Parameters.DeviceCapabilities.Capabilities != NULL) - { - // - // don't need to safely remove - // - IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE; - } + IoSetCompletionRoutine(Irp, + Hid_PnpCompletion, + &Event, + TRUE, + TRUE, + TRUE); - // - // done - // - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; - } - case IRP_MN_START_DEVICE: - { - // - // prepare irp - // - KeInitializeEvent(&Event, NotificationEvent, FALSE); - IoCopyCurrentIrpStackLocationToNext(Irp); - IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE); + /* send request to driver for lower device and wait for completion */ + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - // - // send irp and wait for completion - // - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Irp->IoStatus.Status; - } + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + 0, + NULL); + } - // - // did the device successfully start - // - if (!NT_SUCCESS(Status)) - { - // - // failed - // - DPRINT1("HIDUSB: IRP_MN_START_DEVICE failed with %x\n", Status); - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; - } + Status = Irp->IoStatus.Status; - // - // start device - // - Status = Hid_PnpStart(DeviceObject); + /* complete handle request */ + if (IoStack->MinorFunction != IRP_MN_START_DEVICE) + { + if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE) + { + HidDeviceExtension->HidState = HIDUSB_STATE_STOPPED; - // - // complete request - // - Irp->IoStatus.Status = Status; - DPRINT("[HIDUSB] IRP_MN_START_DEVICE Status %x\n", Status); - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + /* free resources */ + Hid_Cleanup(DeviceObject); } - default: + else if (IoStack->MinorFunction == IRP_MN_QUERY_CAPABILITIES && + NT_SUCCESS(Status)) { - // - // forward and forget request - // - IoSkipCurrentIrpStackLocation(Irp); - return IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE; } } -} + else if (!NT_SUCCESS(Status)) + { + HidDeviceExtension->HidState = HIDUSB_STATE_FAILED; + } + else + { + /* IRP_MN_START_DEVICE */ + HidDeviceExtension->HidState = HIDUSB_STATE_STARTING; + + Status = Hid_StartDevice(DeviceObject); + if (!NT_SUCCESS(Status)) + { + HidDeviceExtension->HidState = HIDUSB_STATE_FAILED; + } + } + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} NTSTATUS NTAPI HidAddDevice( @@ -1900,9 +2085,12 @@ HidAddDevice( // KeInitializeEvent(&HidDeviceExtension->Event, NotificationEvent, FALSE); - // - // done - // + /* set HidState as not initialized value */ + HidDeviceExtension->HidState = 0; + + /* default pending requests */ + HidDeviceExtension->RequestCount = 0; + return STATUS_SUCCESS; } diff --git a/reactos/drivers/hid/hidusb/hidusb.h b/reactos/drivers/hid/hidusb/hidusb.h index 92093623eea..4c5093852ef 100644 --- a/reactos/drivers/hid/hidusb/hidusb.h +++ b/reactos/drivers/hid/hidusb/hidusb.h @@ -14,6 +14,13 @@ #include +#define HIDUSB_STATE_STARTING 1 +#define HIDUSB_STATE_RUNNING 2 +#define HIDUSB_STATE_STOPPING 3 +#define HIDUSB_STATE_STOPPED 4 +#define HIDUSB_STATE_REMOVED 5 +#define HIDUSB_STATE_FAILED 6 + typedef struct { // @@ -46,6 +53,10 @@ typedef struct // PHID_DESCRIPTOR HidDescriptor; + /* current state for device */ + ULONG HidState; + /* current num pending requests */ + LONG RequestCount; } HID_USB_DEVICE_EXTENSION, *PHID_USB_DEVICE_EXTENSION; typedef struct diff --git a/reactos/drivers/hid/hidusb/hidusb.rc b/reactos/drivers/hid/hidusb/hidusb.rc index bcf07749e78..c6d53b7bf38 100644 --- a/reactos/drivers/hid/hidusb/hidusb.rc +++ b/reactos/drivers/hid/hidusb/hidusb.rc @@ -1,5 +1,5 @@ #define REACTOS_VERSION_DLL -#define REACTOS_STR_FILE_DESCRIPTION "USB HID Interface Driver" +#define REACTOS_STR_FILE_DESCRIPTION "USB Miniport Driver for Input Devices" #define REACTOS_STR_INTERNAL_NAME "hidusb" #define REACTOS_STR_ORIGINAL_FILENAME "hidusb.sys" #include diff --git a/reactos/drivers/hid/kbdhid/kbdhid.c b/reactos/drivers/hid/kbdhid/kbdhid.c index f33a99d18f7..782f06c1ffd 100644 --- a/reactos/drivers/hid/kbdhid/kbdhid.c +++ b/reactos/drivers/hid/kbdhid/kbdhid.c @@ -328,7 +328,8 @@ KbdHid_Close( DeviceExtension->StopReadReport = TRUE; /* wait until the reports have been read */ - KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); + // HACK: due problem disconnecting from PC USB port CORE-9070) + //KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); /* cancel irp */ IoCancelIrp(DeviceExtension->Irp); @@ -1027,7 +1028,7 @@ NTAPI KbdHid_Unload( IN PDRIVER_OBJECT DriverObject) { - UNIMPLEMENTED + UNIMPLEMENTED; } diff --git a/reactos/drivers/hid/mouhid/mouhid.c b/reactos/drivers/hid/mouhid/mouhid.c index 7ebb4d4b3f3..33b49eab18a 100644 --- a/reactos/drivers/hid/mouhid/mouhid.c +++ b/reactos/drivers/hid/mouhid/mouhid.c @@ -536,7 +536,8 @@ MouHid_Close( DeviceExtension->StopReadReport = TRUE; /* wait until the reports have been read */ - KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); + // HACK: due problem disconnecting from PC USB port CORE-9070) + //KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); /* cancel irp */ IoCancelIrp(DeviceExtension->Irp); diff --git a/reactos/drivers/usb/CMakeLists.txt b/reactos/drivers/usb/CMakeLists.txt index 36650c822df..60bb2156156 100644 --- a/reactos/drivers/usb/CMakeLists.txt +++ b/reactos/drivers/usb/CMakeLists.txt @@ -1,7 +1,12 @@ +add_subdirectory(usbport) add_subdirectory(usbccgp) add_subdirectory(usbd) -add_subdirectory(usbehci) -add_subdirectory(usbhub) -add_subdirectory(usbohci) +#add_subdirectory(usbehci) +add_subdirectory(usbehci_new) +#add_subdirectory(usbhub) +add_subdirectory(usbhub_new) +#add_subdirectory(usbohci) +add_subdirectory(usbohci_new) add_subdirectory(usbstor) -add_subdirectory(usbuhci) +#add_subdirectory(usbuhci) +add_subdirectory(usbuhci_new) diff --git a/reactos/drivers/usb/usbccgp/pdo.c b/reactos/drivers/usb/usbccgp/pdo.c index 6110744a9d3..37e0f85dc5a 100644 --- a/reactos/drivers/usb/usbccgp/pdo.c +++ b/reactos/drivers/usb/usbccgp/pdo.c @@ -707,6 +707,13 @@ USBCCGP_PDOSelectConfiguration( Urb = (PURB)IoStack->Parameters.Others.Argument1; ASSERT(Urb); + /* if ConfigurationDescriptor == NULL, then is closing configuration */ + if ( !Urb->UrbSelectConfiguration.ConfigurationDescriptor ) + { + DPRINT1("[USBCCGP] SelectConfiguration: closing configuration\n"); + return STATUS_SUCCESS; + } + // // is there already an configuration handle // diff --git a/reactos/drivers/usb/usbehci_new/CMakeLists.txt b/reactos/drivers/usb/usbehci_new/CMakeLists.txt new file mode 100644 index 00000000000..83dc77bec57 --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/CMakeLists.txt @@ -0,0 +1,16 @@ + +list(APPEND SOURCE + debug.c + roothub.c + usbehci.c + usbehci.h) + +add_library(usbehci SHARED + ${SOURCE} + guid.c + usbehci.rc) + +set_module_type(usbehci kernelmodedriver) +add_importlibs(usbehci usbport ntoskrnl hal usbd) +add_pch(usbehci usbehci.h SOURCE) +add_cd_file(TARGET usbehci DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/usb/usbehci_new/dbg_ehci.h b/reactos/drivers/usb/usbehci_new/dbg_ehci.h new file mode 100644 index 00000000000..6ebecf21e5e --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/dbg_ehci.h @@ -0,0 +1,44 @@ +#ifndef DBG_EHCI_H__ +#define DBG_EHCI_H__ + +#if DBG + + #ifndef NDEBUG_EHCI_TRACE + #define DPRINT_EHCI(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_EHCI __noop + #else + #define DPRINT_EHCI(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #endif + #endif + + #ifndef NDEBUG_EHCI_ROOT_HUB + #define DPRINT_RH(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_RH __noop + #else + #define DPRINT_RH(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #endif + #endif + +#else /* not DBG */ + + #if defined(_MSC_VER) + #define DPRINT_EHCI __noop + #define DPRINT_RH __noop + #else + #define DPRINT_EHCI(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #define DPRINT_RH(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #endif /* _MSC_VER */ + +#endif /* not DBG */ + +#endif /* DBG_EHCI_H__ */ diff --git a/reactos/drivers/usb/usbehci_new/debug.c b/reactos/drivers/usb/usbehci_new/debug.c new file mode 100644 index 00000000000..12f2461056f --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/debug.c @@ -0,0 +1,35 @@ +#include "usbehci.h" + +#define NDEBUG +#include + +VOID +NTAPI +EHCI_DumpHwTD(IN PEHCI_HCD_TD TD) +{ + if (!TD) + { + return; + } + + DPRINT(": TD - %p\n", TD); + DPRINT(": TD->PhysicalAddress - %p\n", TD->PhysicalAddress); + DPRINT(": TD->HwTD.NextTD - %p\n", TD->HwTD.NextTD); + DPRINT(": TD->HwTD.AlternateNextTD - %p\n", TD->HwTD.AlternateNextTD); + DPRINT(": TD->HwTD.Token.AsULONG - %p\n", TD->HwTD.Token.AsULONG); +} + +VOID +NTAPI +EHCI_DumpHwQH(IN PEHCI_HCD_QH QH) +{ + if (!QH) + { + return; + } + + DPRINT(": QH->sqh.HwQH.CurrentTD - %p\n", QH->sqh.HwQH.CurrentTD); + DPRINT(": QH->sqh.HwQH.NextTD - %p\n", QH->sqh.HwQH.NextTD); + DPRINT(": QH->sqh.HwQH.AlternateNextTD - %p\n", QH->sqh.HwQH.AlternateNextTD); + DPRINT(": QH->sqh.HwQH.Token.AsULONG - %p\n", QH->sqh.HwQH.Token.AsULONG); +} diff --git a/reactos/drivers/usb/usbehci_new/guid.c b/reactos/drivers/usb/usbehci_new/guid.c new file mode 100644 index 00000000000..50a60369ff3 --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/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/usbehci_new/hardware.h b/reactos/drivers/usb/usbehci_new/hardware.h new file mode 100644 index 00000000000..f790d861ff3 --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/hardware.h @@ -0,0 +1,321 @@ +/* EHCI hardware registers */ + +#define EHCI_USBCMD 0 +#define EHCI_USBSTS 1 +#define EHCI_USBINTR 2 +#define EHCI_FRINDEX 3 +#define EHCI_CTRLDSSEGMENT 4 +#define EHCI_PERIODICLISTBASE 5 +#define EHCI_ASYNCLISTBASE 6 +#define EHCI_CONFIGFLAG 16 +#define EHCI_PORTSC 17 + +typedef union _EHCI_HC_STRUCTURAL_PARAMS { + struct { + ULONG PortCount : 4; + ULONG PortPowerControl : 1; + ULONG Reserved1 : 2; + ULONG PortRouteRules : 1; + ULONG PortsPerCompanion : 4; + ULONG CompanionControllers : 4; + ULONG PortIndicators : 1; + ULONG Reserved2 : 3; + ULONG DebugPortNumber : 4; //Optional + ULONG Reserved3 : 8; + }; + ULONG AsULONG; +} EHCI_HC_STRUCTURAL_PARAMS; + +typedef union _EHCI_HC_CAPABILITY_PARAMS { + struct { + ULONG Addressing64bitCapability : 1; + ULONG IsProgrammableFrameList : 1; + ULONG IsScheduleParkSupport : 1; + ULONG Reserved1 : 1; + ULONG IsoSchedulingThreshold : 4; + ULONG ExtCapabilitiesPointer : 8; // (EECP) + ULONG Reserved2 : 16; + }; + ULONG AsULONG; +} EHCI_HC_CAPABILITY_PARAMS; + +typedef union _EHCI_USB_COMMAND { + struct { + ULONG Run : 1; + ULONG Reset : 1; + ULONG FrameListSize : 2; + ULONG PeriodicEnable : 1; + ULONG AsynchronousEnable : 1; + ULONG InterruptAdvanceDoorbell : 1; + ULONG LightResetHC : 1; // optional + ULONG AsynchronousParkModeCount : 2; // optional + ULONG Reserved1 : 1; + ULONG AsynchronousParkModeEnable : 1; // optional + ULONG Reserved2 : 4; + ULONG InterruptThreshold : 8; + ULONG Reserved3 : 8; + }; + ULONG AsULONG; +} EHCI_USB_COMMAND; + +typedef union _EHCI_USB_STATUS { + struct { + ULONG Interrupt : 1; + ULONG ErrorInterrupt : 1; + ULONG PortChangeDetect : 1; + ULONG FrameListRollover : 1; + ULONG HostSystemError : 1; + ULONG InterruptOnAsyncAdvance : 1; + ULONG Reserved1 : 6; + ULONG HCHalted : 1; + ULONG Reclamation : 1; + ULONG PeriodicStatus : 1; + ULONG AsynchronousStatus : 1; + ULONG Reserved2 : 16; + }; + ULONG AsULONG; +} EHCI_USB_STATUS; + +typedef union _EHCI_INTERRUPT_ENABLE { + struct { + ULONG Interrupt : 1; + ULONG ErrorInterrupt : 1; + ULONG PortChangeInterrupt : 1; + ULONG FrameListRollover : 1; + ULONG HostSystemError : 1; + ULONG InterruptOnAsyncAdvance : 1; + ULONG Reserved : 26; + }; + ULONG AsULONG; +} EHCI_INTERRUPT_ENABLE; + +typedef union _EHCI_PORT_STATUS_CONTROL { + struct { + ULONG CurrentConnectStatus : 1; + ULONG ConnectStatusChange : 1; + ULONG PortEnabledDisabled : 1; + ULONG PortEnableDisableChange : 1; + ULONG OverCurrentActive : 1; + ULONG OverCurrentChange : 1; + ULONG ForcePortResume : 1; + ULONG Suspend : 1; + ULONG PortReset : 1; + ULONG Reserved1 : 1; + ULONG LineStatus : 2; + ULONG PortPower : 1; + ULONG PortOwner : 1; + ULONG PortIndicatorControl : 2; + ULONG PortTestControl : 4; + ULONG WakeOnConnectEnable : 1; + ULONG WakeOnDisconnectEnable : 1; + ULONG WakeOnOverCurrentEnable : 1; + ULONG Reserved2 : 9; + }; + ULONG AsULONG; +} EHCI_PORT_STATUS_CONTROL; + +/* Link Pointer */ + +#define EHCI_LINK_TYPE_iTD 0 // isochronous transfer descriptor +#define EHCI_LINK_TYPE_QH 1 // queue head +#define EHCI_LINK_TYPE_siTD 2 // split transaction isochronous transfer +#define EHCI_LINK_TYPE_FSTN 3 // frame span traversal node + +typedef union _EHCI_LINK_POINTER { + struct { + ULONG Terminate : 1; + ULONG Type : 2; + ULONG Reserved : 2; + ULONG Adress : 27; + }; + ULONG AsULONG; +} EHCI_LINK_POINTER; + +/* Isochronous (High-Speed) Transfer Descriptor (iTD) */ + +typedef union _EHCI_TRANSACTION_CONTROL { + struct { + ULONG xOffset : 12; + ULONG PageSelect : 3; + ULONG InterruptOnComplete : 1; + ULONG xLength : 12; + ULONG Status : 4; + }; + ULONG AsULONG; +} EHCI_TRANSACTION_CONTROL; + +typedef union _EHCI_TRANSACTION_BUFFER { + struct { + ULONG DeviceAddress : 7; + ULONG Reserved1 : 1; + ULONG EndpointNumber : 4; + ULONG DataBuffer0 : 20; + }; + struct { + ULONG MaximumPacketSize : 11; + ULONG Direction : 1; + ULONG DataBuffer1 : 20; + }; + struct { + ULONG Multi : 2; + ULONG Reserved2 : 10; + ULONG DataBuffer2 : 20; + }; + struct { + ULONG Reserved3 : 12; + ULONG DataBuffer : 20; + }; + ULONG AsULONG; +} EHCI_TRANSACTION_BUFFER; + +typedef struct _EHCI_ISOCHRONOUS_TD { // must be aligned on a 32-byte boundary + EHCI_LINK_POINTER NextLink; + EHCI_TRANSACTION_CONTROL Transaction[8]; + EHCI_TRANSACTION_BUFFER Buffer[7]; + ULONG_PTR ExtendedBuffer[7]; +} EHCI_ISOCHRONOUS_TD, *PEHCI_ISOCHRONOUS_TD; + +C_ASSERT(sizeof(EHCI_ISOCHRONOUS_TD) == 92); + +/* Split Transaction Isochronous Transfer Descriptor (siTD) */ + +typedef union _EHCI_FS_ENDPOINT_PARAMS { + struct { + ULONG DeviceAddress : 7; + ULONG Reserved1 : 1; + ULONG EndpointNumber : 4; + ULONG Reserved2 : 4; + ULONG HubAddress : 7; + ULONG Reserved3 : 1; + ULONG PortNumber : 7; + ULONG Direction : 1; + }; + ULONG AsULONG; +} EHCI_FS_ENDPOINT_PARAMS; + +typedef union _EHCI_MICROFRAME_CONTROL { + struct { + ULONG StartMask : 8; + ULONG CompletionMask : 8; + ULONG Reserved : 16; + }; + ULONG AsULONG; +} EHCI_MICROFRAME_CONTROL; + +typedef union _EHCI_SPLIT_TRANSFER_STATE { + struct { + ULONG Status : 8; + ULONG ProgressMask : 8; + ULONG TotalBytes : 10; + ULONG Reserved : 4; + ULONG PageSelect : 1; + ULONG InterruptOnComplete : 1; + }; + ULONG AsULONG; +} EHCI_SPLIT_TRANSFER_STATE; + +typedef union _EHCI_SPLIT_BUFFER_POINTER { + struct { + ULONG CurrentOffset : 12; + ULONG DataBuffer0 : 20; + }; + struct { + ULONG TransactionCount : 3; + ULONG TransactionPosition : 2; + ULONG Reserved : 7; + ULONG DataBuffer1 : 20; + }; + ULONG AsULONG; +} EHCI_SPLIT_BUFFER_POINTER; + +typedef struct _EHCI_SPLIT_ISOCHRONOUS_TD { // must be aligned on a 32-byte boundary + EHCI_LINK_POINTER NextLink; + EHCI_FS_ENDPOINT_PARAMS EndpointCharacteristics; + EHCI_MICROFRAME_CONTROL MicroFrameControl; + EHCI_SPLIT_TRANSFER_STATE TransferState; + EHCI_SPLIT_BUFFER_POINTER Buffer[2]; + ULONG_PTR BackPointer; +} EHCI_SPLIT_ISOCHRONOUS_TD, *PEHCI_SPLIT_ISOCHRONOUS_TD; + +C_ASSERT(sizeof(EHCI_SPLIT_ISOCHRONOUS_TD) == 28); + +/* Queue Element Transfer Descriptor (qTD) */ + +#define EHCI_TOKEN_STATUS_ACTIVE (1 << 7) +#define EHCI_TOKEN_STATUS_HALTED (1 << 6) +#define EHCI_TOKEN_STATUS_DATA_BUFFER_ERROR (1 << 5) +#define EHCI_TOKEN_STATUS_BABBLE_DETECTED (1 << 4) +#define EHCI_TOKEN_STATUS_TRANSACTION_ERROR (1 << 3) +#define EHCI_TOKEN_STATUS_MISSED_MICROFRAME (1 << 2) +#define EHCI_TOKEN_STATUS_SPLIT_STATE (1 << 1) +#define EHCI_TOKEN_STATUS_PING_STATE (1 << 0) + +typedef union _EHCI_TD_TOKEN { + struct { + ULONG Status : 8; + ULONG PIDCode : 2; + ULONG ErrorCounter : 2; + ULONG CurrentPage : 3; + ULONG InterruptOnComplete : 1; + ULONG TransferBytes : 15; + ULONG DataToggle : 1; + }; + ULONG AsULONG; +} EHCI_TD_TOKEN, *PEHCI_TD_TOKEN; + +typedef struct _EHCI_QUEUE_TD { // must be aligned on 32-byte boundaries + ULONG_PTR NextTD; + ULONG_PTR AlternateNextTD; + EHCI_TD_TOKEN Token; + ULONG_PTR Buffer[5]; + ULONG_PTR ExtendedBuffer[5]; +} EHCI_QUEUE_TD, *PEHCI_QUEUE_TD; + +C_ASSERT(sizeof(EHCI_QUEUE_TD) == 52); + +/* Queue Head */ + +#define EHCI_QH_FLAG_IN_SCHEDULE 0x01 +#define EHCI_QH_FLAG_STATIC 0x04 +#define EHCI_QH_FLAG_UPDATING 0x10 +#define EHCI_QH_FLAG_NUKED 0x20 + +typedef union _EHCI_QH_EP_PARAMS { + struct { + ULONG DeviceAddress : 7; + ULONG InactivateOnNextTransaction : 1; + ULONG EndpointNumber : 4; + ULONG EndpointSpeed : 2; + ULONG DataToggleControl : 1; + ULONG HeadReclamationListFlag : 1; + ULONG MaximumPacketLength : 11; // corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize). + ULONG ControlEndpointFlag : 1; + ULONG NakCountReload : 4; + }; + ULONG AsULONG; +} EHCI_QH_EP_PARAMS; + +typedef union _EHCI_QH_EP_CAPS { + struct { + ULONG InterruptMask : 8; + ULONG SplitCompletionMask : 8; + ULONG HubAddr : 7; + ULONG PortNumber : 7; + ULONG PipeMultiplier : 2; + }; + ULONG AsULONG; +} EHCI_QH_EP_CAPS; + +typedef struct _EHCI_QUEUE_HEAD { // must be aligned on 32-byte boundaries + EHCI_LINK_POINTER HorizontalLink; + EHCI_QH_EP_PARAMS EndpointParams; + EHCI_QH_EP_CAPS EndpointCaps; + ULONG_PTR CurrentTD; + ULONG_PTR NextTD; + ULONG_PTR AlternateNextTD; + EHCI_TD_TOKEN Token; + ULONG_PTR Buffer[5]; + ULONG_PTR ExtendedBuffer[5]; +} EHCI_QUEUE_HEAD, *PEHCI_QUEUE_HEAD; + +C_ASSERT(sizeof(EHCI_QUEUE_HEAD) == 68); diff --git a/reactos/drivers/usb/usbehci_new/roothub.c b/reactos/drivers/usb/usbehci_new/roothub.c new file mode 100644 index 00000000000..1053fc334fa --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/roothub.c @@ -0,0 +1,607 @@ +#include "usbehci.h" + +//#define NDEBUG +#include + +#define NDEBUG_EHCI_ROOT_HUB +#include "dbg_ehci.h" + +VOID +NTAPI +EHCI_RH_GetRootHubData(IN PVOID ehciExtension, + IN PVOID rootHubData) +{ + PEHCI_EXTENSION EhciExtension; + PUSBPORT_ROOT_HUB_DATA RootHubData; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + DPRINT_RH("EHCI_RH_GetRootHubData: EhciExtension - %p, rootHubData - %p\n", + EhciExtension, + rootHubData); + + RootHubData = (PUSBPORT_ROOT_HUB_DATA)rootHubData; + + RootHubData->NumberOfPorts = EhciExtension->NumberOfPorts; + + /* Logical Power Switching Mode */ + if (EhciExtension->PortPowerControl == 1) + { + /* Individual port power switching */ + RootHubData->HubCharacteristics = (RootHubData->HubCharacteristics & ~2) | 1; + } + else + { + /* Ganged power switching (all ports power at once) */ + RootHubData->HubCharacteristics &= ~3; + } + + /* + Identifies a Compound Device: Hub is not part of a compound device. + Over-current Protection Mode: Global Over-current Protection. + */ + RootHubData->HubCharacteristics &= 3; + + RootHubData->PowerOnToPowerGood = 2; + RootHubData->HubControlCurrent = 0; +} + +MPSTATUS +NTAPI +EHCI_RH_GetStatus(IN PVOID ehciExtension, + IN PUSHORT Status) +{ + DPRINT_RH("EHCI_RH_GetStatus: ... \n"); + *Status = 1; + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_GetPortStatus(IN PVOID ehciExtension, + IN USHORT Port, + IN PULONG PortStatus) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + USB20_PORT_STATUS status; + ULONG PortMaskBits; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (PortSC.CurrentConnectStatus) + { + DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, PortSC.AsULONG - %p\n", + Port, + PortSC.AsULONG); + } + + *PortStatus = 0; + + if (PortSC.LineStatus == 1 && // K-state Low-speed device + PortSC.PortOwner != 1 && // Companion HC not owns and not controls this port + (PortSC.PortEnabledDisabled | PortSC.Suspend) && // Enable or Suspend + PortSC.CurrentConnectStatus == 1) // Device is present + { + DPRINT("EHCI_RH_GetPortStatus: LowSpeed device detected\n"); + PortSC.PortOwner = 1; // release ownership + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + return 0; + } + + status.AsULONG = 0; + + status.ConnectStatus = PortSC.CurrentConnectStatus; + status.EnableStatus = PortSC.PortEnabledDisabled; + status.OverCurrent = PortSC.OverCurrentActive; + status.ResetStatus = PortSC.PortReset; + status.PowerStatus = PortSC.PortPower; + status.SuspendStatus = PortSC.Suspend; + // PortSC.PortOwner ?? + status.EnableStatusChange = PortSC.PortEnableDisableChange; + status.OverCurrentChange = PortSC.OverCurrentChange; + + PortMaskBits = 1 << (Port - 1); + + if (status.ConnectStatus) + { + status.LsDeviceAttached = 0; + } + + status.HsDeviceAttached = 1; + + if (PortSC.ConnectStatusChange) + { + EhciExtension->ConnectPortBits |= PortMaskBits; + } + + if (EhciExtension->FinishResetPortBits & PortMaskBits) + { + status.ResetStatusChange = 1; + } + + if (EhciExtension->ConnectPortBits & PortMaskBits) + { + status.ConnectStatusChange = 1; + } + + if (EhciExtension->SuspendPortBits & PortMaskBits) + { + status.SuspendStatusChange = 1; + } + + *PortStatus = status.AsULONG; + + if (status.ConnectStatus) + { + DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, status.AsULONG - %p\n", + Port, + status.AsULONG); + } + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_GetHubStatus(IN PVOID ehciExtension, + IN PULONG HubStatus) +{ + DPRINT_RH("EHCI_RH_GetHubStatus: ... \n"); + *HubStatus = 0; + return 0; +} + +VOID +NTAPI +EHCI_RH_FinishReset(IN PVOID ehciExtension, + IN PUSHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_FinishReset: *Port - %x\n", *Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (*Port - 1); + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (PortSC.AsULONG != -1) + { + if (!PortSC.CurrentConnectStatus) + { + DPRINT("EHCI_RH_FinishReset: PortSC.AsULONG - %p\n", PortSC.AsULONG); + } + + if (PortSC.PortEnabledDisabled || + !PortSC.CurrentConnectStatus || + PortSC.ConnectStatusChange) + { + EhciExtension->FinishResetPortBits |= (1 << (*Port - 1)); + RegPacket.UsbPortInvalidateRootHub(EhciExtension); + } + else + { + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + PortSC.PortOwner = 1; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + EhciExtension->FinishResetPortBits |= (1 << (*Port - 1)); + } + + EhciExtension->ResetPortBits &= ~(1 << (*Port - 1)); + } +} + +ULONG +NTAPI +EHCI_RH_PortResetComplete(IN PVOID ehciExtension, + IN PUSHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + ULONG ix; + + DPRINT("EHCI_RH_PortResetComplete: *Port - %x\n", *Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (*Port - 1); + +START: + + ix = 0; + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortReset = 0; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + do + { + KeStallExecutionProcessor(20); + + ix += 20; + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (ix > 500) + { + goto START; + } + } + while (PortSC.PortReset && (PortSC.AsULONG != -1)); + + return RegPacket.UsbPortRequestAsyncCallback(EhciExtension, + 50, // TimerValue + Port, + sizeof(Port), + (ULONG)EHCI_RH_FinishReset); +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortReset(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_SetFeaturePortReset: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + EhciExtension->ResetPortBits |= 1 << (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnabledDisabled = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortReset = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + RegPacket.UsbPortRequestAsyncCallback(EhciExtension, + 50, // TimerValue + &Port, + sizeof(Port), + (ULONG_PTR)EHCI_RH_PortResetComplete); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortPower(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_RH("EHCI_RH_SetFeaturePortPower: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortPower = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortEnable(IN PVOID ehciExtension, + IN USHORT Port) +{ + DPRINT_RH("EHCI_RH_SetFeaturePortEnable: Not supported\n"); + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortSuspend(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_SetFeaturePortSuspend: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.Suspend = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + KeStallExecutionProcessor(125); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortEnable(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortEnable: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnabledDisabled = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortPower(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortPower: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + PortSC.PortPower = 0; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return 0; +} + +VOID +NTAPI +EHCI_RH_PortResumeComplete(IN PULONG ehciExtension, + IN PUSHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_PortResumeComplete: *Port - %x\n", *Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (*Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.ForcePortResume = 0; + PortSC.Suspend = 0; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + READ_REGISTER_ULONG(PortStatusReg); + + EhciExtension->SuspendPortBits |= 1 << (*Port - 1); +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortSuspend(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortSuspend: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + EhciExtension->ResetPortBits |= 1 << (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + PortSC.ForcePortResume = 1; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + RegPacket.UsbPortRequestAsyncCallback(EhciExtension, + 50, // TimerValue + &Port, + sizeof(Port), + (ULONG)EHCI_RH_PortResumeComplete); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortEnableChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortEnableChange: Port - %p\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortEnableDisableChange = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortConnectChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_RH("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (PortSC.ConnectStatusChange) + { + PortSC.ConnectStatusChange = 1; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + } + + EhciExtension->ConnectPortBits &= ~(1 << (Port - 1)); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortResetChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + + DPRINT("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + EhciExtension->FinishResetPortBits &= ~(1 << (Port - 1)); + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortSuspendChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + + DPRINT("EHCI_RH_ClearFeaturePortSuspendChange: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + EhciExtension->SuspendPortBits &= ~(1 << (Port - 1)); + return 0; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortOvercurrentChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_RH("EHCI_RH_ClearFeaturePortOvercurrentChange: Port - %x\n", Port); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + PortStatusReg = (EhciExtension->OperationalRegs + EHCI_PORTSC) + (Port - 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return 0; +} + +VOID +NTAPI +EHCI_RH_DisableIrq(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG IntrStsReg; + EHCI_INTERRUPT_ENABLE IntrSts; + + DPRINT_RH("EHCI_RH_DisableIrq: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + IntrStsReg = EhciExtension->OperationalRegs + EHCI_USBINTR; + IntrSts.AsULONG = READ_REGISTER_ULONG(IntrStsReg); + + EhciExtension->InterruptMask.PortChangeInterrupt = 0; + IntrSts.PortChangeInterrupt = 0; + + if (IntrSts.Interrupt) + { + WRITE_REGISTER_ULONG(IntrStsReg, IntrSts.AsULONG); + } +} + +VOID +NTAPI +EHCI_RH_EnableIrq(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG IntrStsReg; + EHCI_INTERRUPT_ENABLE IntrSts; + + DPRINT_RH("EHCI_RH_EnableIrq: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + IntrStsReg = EhciExtension->OperationalRegs + EHCI_USBINTR; + IntrSts.AsULONG = READ_REGISTER_ULONG(IntrStsReg); + + EhciExtension->InterruptMask.PortChangeInterrupt = 1; + IntrSts.PortChangeInterrupt = 1; + + if (IntrSts.Interrupt) + { + WRITE_REGISTER_ULONG(IntrStsReg, IntrSts.AsULONG); + } +} diff --git a/reactos/drivers/usb/usbehci_new/usbehci.c b/reactos/drivers/usb/usbehci_new/usbehci.c new file mode 100644 index 00000000000..9d6eb9fa088 --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/usbehci.c @@ -0,0 +1,3467 @@ +#include "usbehci.h" + +//#define NDEBUG +#include + +#define NDEBUG_EHCI_TRACE +#include "dbg_ehci.h" + +USBPORT_REGISTRATION_PACKET RegPacket; + +PEHCI_HCD_TD +NTAPI +EHCI_AllocTd(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_HCD_TD TD; + ULONG ix = 0; + + DPRINT_EHCI("EHCI_AllocTd: ... \n"); + + if (EhciEndpoint->MaxTDs == 0) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return NULL; + } + + TD = EhciEndpoint->FirstTD; + + while (TD->TdFlags & EHCI_HCD_TD_FLAG_ALLOCATED) + { + ++ix; + TD += 1; + + if (ix >= EhciEndpoint->MaxTDs) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return NULL; + } + } + + TD->TdFlags |= EHCI_HCD_TD_FLAG_ALLOCATED; + + --EhciEndpoint->RemainTDs; + + return TD; +} + +PEHCI_HCD_QH +NTAPI +EHCI_InitializeQH(PEHCI_EXTENSION EhciExtension, + PEHCI_ENDPOINT EhciEndpoint, + PEHCI_HCD_QH QH, + PEHCI_HCD_QH QhPA) +{ + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG DeviceSpeed; + + DPRINT_EHCI("EHCI_InitializeQH: EhciEndpoint - %p, QH - %p, QhPA - %p\n", + EhciEndpoint, + QH, + QhPA); + + EndpointProperties = &EhciEndpoint->EndpointProperties; + + RtlZeroMemory(QH, sizeof(EHCI_HCD_QH)); + + ASSERT(((ULONG_PTR)QhPA & 0x1F) == 0); // link flags + + QH->sqh.PhysicalAddress = QhPA; + //QH->EhciEndpoint = EhciEndpoint; + + QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress & 0x7F; + QH->sqh.HwQH.EndpointParams.EndpointNumber = EndpointProperties->EndpointAddress & 0x0F; + + DeviceSpeed = EndpointProperties->DeviceSpeed; + + switch (DeviceSpeed) + { + case UsbLowSpeed: + QH->sqh.HwQH.EndpointParams.EndpointSpeed = 1; + break; + + case UsbFullSpeed: + QH->sqh.HwQH.EndpointParams.EndpointSpeed = 0; + break; + + case UsbHighSpeed: + QH->sqh.HwQH.EndpointParams.EndpointSpeed = 2; + break; + + default: + ASSERT(FALSE); + break; + } + + QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize & 0x7FF; + + QH->sqh.HwQH.EndpointCaps.PipeMultiplier = 1; + + if (DeviceSpeed == UsbHighSpeed) + { + QH->sqh.HwQH.EndpointCaps.HubAddr = 0; + QH->sqh.HwQH.EndpointCaps.PortNumber = 0; + } + else + { + QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr & 0x7F; + QH->sqh.HwQH.EndpointCaps.PortNumber = EndpointProperties->PortNumber & 0x7F; + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + QH->sqh.HwQH.EndpointParams.ControlEndpointFlag = 1; + } + } + + QH->sqh.HwQH.NextTD = 1; + QH->sqh.HwQH.AlternateNextTD = 1; + QH->sqh.HwQH.Token.Status &= (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE | + EHCI_TOKEN_STATUS_HALTED); + + return QH; +} + +MPSTATUS +NTAPI +EHCI_OpenBulkOrControlEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint, + IN BOOLEAN IsControl) +{ + PEHCI_HCD_QH QH; + PEHCI_HCD_QH QhPA; + PEHCI_HCD_TD TdVA; + PEHCI_HCD_TD TdPA; + PEHCI_HCD_TD TD; + ULONG TdCount; + ULONG ix; + + DPRINT("EHCI_OpenBulkOrControlEndpoint: EhciEndpoint - %p, IsControl - %x\n", + EhciEndpoint, + IsControl); + + InitializeListHead(&EhciEndpoint->ListTDs); + + EhciEndpoint->DummyTdVA = (PEHCI_HCD_TD)EndpointProperties->BufferVA; + EhciEndpoint->DummyTdPA = (PEHCI_HCD_TD)EndpointProperties->BufferPA; + + RtlZeroMemory(EhciEndpoint->DummyTdVA, sizeof(EHCI_HCD_TD)); + + QH = (PEHCI_HCD_QH)(EhciEndpoint->DummyTdVA + 1); + QhPA = (PEHCI_HCD_QH)(EhciEndpoint->DummyTdPA + 1); + + EhciEndpoint->FirstTD = (PEHCI_HCD_TD)(QH + 1); + + TdCount = (EndpointProperties->BufferLength - + (sizeof(EHCI_HCD_TD) + sizeof(EHCI_HCD_QH))) / + sizeof(EHCI_HCD_TD); + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + EhciEndpoint->EndpointStatus |= 4; + } + + EhciEndpoint->MaxTDs = TdCount; + EhciEndpoint->RemainTDs = TdCount; + + if (TdCount) + { + TdVA = EhciEndpoint->FirstTD; + TdPA = (PEHCI_HCD_TD)(QhPA + 1); + + ix = 0; + + do + { + DPRINT_EHCI("EHCI_OpenBulkOrControlEndpoint: TdVA - %p, TdPA - %p\n", + TdVA, + TdPA); + + RtlZeroMemory(TdVA, sizeof(EHCI_HCD_TD)); + + ASSERT(((ULONG_PTR)TdPA & 0x1F) == 0); // link flags + + TdVA->PhysicalAddress = TdPA; + TdVA->EhciEndpoint = EhciEndpoint; + TdVA->EhciTransfer = NULL; + + TdPA += 1; + TdVA += 1; + + ix++; + } + while (ix < TdCount); + } + + EhciEndpoint->QH = EHCI_InitializeQH(EhciExtension, + EhciEndpoint, + QH, + QhPA); + + if (IsControl) + { + QH->sqh.HwQH.EndpointParams.DataToggleControl = 1; + EhciEndpoint->HcdHeadP = NULL; + } + else + { + QH->sqh.HwQH.EndpointParams.DataToggleControl = 0; + } + + TD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!TD) + { + return 2; + } + + TD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY; + TD->HwTD.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + + TD->HwTD.NextTD = 1; + TD->HwTD.AlternateNextTD = 1; + + TD->NextHcdTD = NULL; + TD->AltNextHcdTD = NULL; + + EhciEndpoint->HcdTailP = TD; + EhciEndpoint->HcdHeadP = TD; + + QH->sqh.HwQH.CurrentTD = (ULONG_PTR)TD->PhysicalAddress; + QH->sqh.HwQH.NextTD = 1; + QH->sqh.HwQH.AlternateNextTD = 1; + + QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + QH->sqh.HwQH.Token.TransferBytes = 0; + + return 0; +} + +MPSTATUS +NTAPI +EHCI_OpenInterruptEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_OpenInterruptEndpoint: UNIMPLEMENTED. FIXME\n"); + return 6; +} + +MPSTATUS +NTAPI +EHCI_OpenHsIsoEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_OpenHsIsoEndpoint: UNIMPLEMENTED. FIXME\n"); + return 6; +} + +MPSTATUS +NTAPI +EHCI_OpenIsoEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_OpenIsoEndpoint: UNIMPLEMENTED. FIXME\n"); + return 6; +} + +MPSTATUS +NTAPI +EHCI_OpenEndpoint(IN PVOID ehciExtension, + IN PVOID endpointParameters, + IN PVOID ehciEndpoint) +{ + PEHCI_EXTENSION EhciExtension; + PEHCI_ENDPOINT EhciEndpoint; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG TransferType; + ULONG Result; + + DPRINT_EHCI("EHCI_OpenEndpoint: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + EndpointProperties = (PUSBPORT_ENDPOINT_PROPERTIES)endpointParameters; + + RtlCopyMemory(&EhciEndpoint->EndpointProperties, + endpointParameters, + sizeof(USBPORT_ENDPOINT_PROPERTIES)); + + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + Result = EHCI_OpenHsIsoEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint); + } + else + { + Result = EHCI_OpenIsoEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint); + } + + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + Result = EHCI_OpenBulkOrControlEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint, + TRUE); + break; + + case USBPORT_TRANSFER_TYPE_BULK: + Result = EHCI_OpenBulkOrControlEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint, + FALSE); + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + Result = EHCI_OpenInterruptEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint); + break; + + default: + Result = 6; + break; + } + + return Result; +} + +MPSTATUS +NTAPI +EHCI_ReopenEndpoint(IN PVOID ehciExtension, + IN PVOID endpointParameters, + IN PVOID ehciEndpoint) +{ + PEHCI_ENDPOINT EhciEndpoint; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG TransferType; + PEHCI_HCD_QH QH; + ULONG Result; + + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + EndpointProperties = (PUSBPORT_ENDPOINT_PROPERTIES)endpointParameters; + + TransferType = EndpointProperties->TransferType; + + DPRINT("EHCI_ReopenEndpoint: EhciEndpoint - %p, TransferType - %x\n", + EhciEndpoint, + TransferType); + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + DPRINT1("EHCI_ReopenEndpoint: HS Iso. UNIMPLEMENTED. FIXME\n"); + Result = 6; + } + else + { + DPRINT1("EHCI_ReopenEndpoint: Iso. UNIMPLEMENTED. FIXME\n"); + Result = 6; + } + + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + case USBPORT_TRANSFER_TYPE_BULK: + case USBPORT_TRANSFER_TYPE_INTERRUPT: + RtlCopyMemory(&EhciEndpoint->EndpointProperties, + endpointParameters, + sizeof(USBPORT_ENDPOINT_PROPERTIES)); + + QH = EhciEndpoint->QH; + + QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress & 0x7F; + QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize & 0x7FF; + + QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr & 0x7F; + + break; + + default: + DPRINT1("EHCI_ReopenEndpoint: Unknown TransferType\n"); + Result = 0; + break; + } + + return Result; +} + +VOID +NTAPI +EHCI_QueryEndpointRequirements(IN PVOID ehciExtension, + IN PVOID endpointParameters, + IN PULONG EndpointRequirements) +{ + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG TransferType; + + DPRINT_EHCI("EHCI_QueryEndpointRequirements: ... \n"); + + EndpointProperties = (PUSBPORT_ENDPOINT_PROPERTIES)endpointParameters; + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + DPRINT("EHCI_QueryEndpointRequirements: IsoTransfer\n"); + + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + *EndpointRequirements = 0x40000; + *(PULONG)(EndpointRequirements + 1) = 0x180000; + } + else + { + *EndpointRequirements = 0x1000; + *(PULONG)(EndpointRequirements + 1) = 0x40000; + } + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + DPRINT("EHCI_QueryEndpointRequirements: ControlTransfer\n"); + *EndpointRequirements = sizeof(EHCI_HCD_QH) + (1 + 6) * sizeof(EHCI_HCD_TD); + *((PULONG)EndpointRequirements + 1) = 0x10000; + break; + + case USBPORT_TRANSFER_TYPE_BULK: + DPRINT("EHCI_QueryEndpointRequirements: BulkTransfer\n"); + *EndpointRequirements = sizeof(EHCI_HCD_QH) + (1 + 209) * sizeof(EHCI_HCD_TD); + *((PULONG)EndpointRequirements + 1) = 0x400000; + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + DPRINT("EHCI_QueryEndpointRequirements: InterruptTransfer\n"); + *EndpointRequirements = sizeof(EHCI_HCD_QH) + (1 + 4) * sizeof(EHCI_HCD_TD); + *((PULONG)EndpointRequirements + 1) = 0x1000; + break; + + default: + DPRINT1("EHCI_QueryEndpointRequirements: Unknown TransferType - %x\n", + TransferType); + DbgBreakPoint(); + break; + } +} + +VOID +NTAPI +EHCI_CloseEndpoint(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN BOOLEAN IsDoDisablePeriodic) +{ + DPRINT1("EHCI_CloseEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +PEHCI_STATIC_QH +NTAPI +EHCI_GetQhForFrame(IN PEHCI_EXTENSION EhciExtension, + IN ULONG FrameIdx) +{ + static UCHAR Balance[32] = { + 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, + 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; + + //DPRINT_EHCI("EHCI_GetQhForFrame: FrameIdx - %x, Balance[FrameIdx] - %x\n", + // FrameIdx, + // Balance[FrameIdx & 0x1F]); + + return EhciExtension->PeriodicHead[Balance[FrameIdx & 0x1F]]; +} + +PEHCI_HCD_QH +NTAPI +EHCI_GetDummyQhForFrame(IN PEHCI_EXTENSION EhciExtension, + IN ULONG Idx) +{ + return (PEHCI_HCD_QH)(EhciExtension->DummyQHListVA + Idx * sizeof(EHCI_HCD_QH)); +} + +VOID +NTAPI +EHCI_AlignHwStructure(IN PEHCI_EXTENSION EhciExtension, + IN PULONG PhysicalAddress, + IN PULONG VirtualAddress, + IN ULONG Alignment) +{ + ULONG PAddress; + PVOID NewPAddress; + ULONG VAddress; + + //DPRINT_EHCI("EHCI_AlignHwStructure: *PhysicalAddress - %p, *VirtualAddress - %p, Alignment - %x\n", + // *PhysicalAddress, + // *VirtualAddress, + // Alignment); + + PAddress = *PhysicalAddress; + VAddress = *VirtualAddress; + + NewPAddress = PAGE_ALIGN(*PhysicalAddress + Alignment - 1); + + if (NewPAddress != PAGE_ALIGN(*PhysicalAddress)) + { + VAddress += (ULONG)NewPAddress - PAddress; + PAddress = (ULONG)PAGE_ALIGN(*PhysicalAddress + Alignment - 1); + + DPRINT("EHCI_AlignHwStructure: VAddress - %p, PAddress - %p\n", + VAddress, + PAddress); + } + + *VirtualAddress = VAddress; + *PhysicalAddress = PAddress; +} + +VOID +NTAPI +EHCI_AddDummyQHs(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_STATIC_QH * FrameHeader; + PEHCI_STATIC_QH StaticQH; + PEHCI_HCD_QH DummyQhVA; + PEHCI_HCD_QH DummyQhPA; + EHCI_LINK_POINTER PrevPA; + EHCI_QH_EP_PARAMS EndpointParams; + ULONG ix = 0; + + DPRINT_EHCI("EHCI_AddDummyQHs: ... \n"); + + FrameHeader = &EhciExtension->HcResourcesVA->PeriodicFrameList[0]; + + DummyQhVA = (PEHCI_HCD_QH)EhciExtension->DummyQHListVA; + DummyQhPA = (PEHCI_HCD_QH)EhciExtension->DummyQHListPA; + + while (TRUE) + { + ASSERT(EHCI_GetDummyQhForFrame(EhciExtension, ix) == DummyQhVA); + + RtlZeroMemory(DummyQhVA, sizeof(EHCI_HCD_QH)); + + DummyQhVA->sqh.HwQH.CurrentTD = 0; + DummyQhVA->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + + PrevPA.AsULONG = (ULONG)DummyQhVA->sqh.PhysicalAddress; + PrevPA.Type = 1; + + DummyQhVA->sqh.PhysicalAddress = DummyQhPA; + + DummyQhVA += 1; + DummyQhPA += 1; + + DummyQhVA->sqh.HwQH.HorizontalLink.AsULONG = (ULONG)(*FrameHeader); + + EndpointParams = DummyQhVA->sqh.HwQH.EndpointParams; + EndpointParams.DeviceAddress = 0; + EndpointParams.EndpointNumber = 0; + EndpointParams.EndpointSpeed = 0; + EndpointParams.MaximumPacketLength = 64; + + DummyQhVA->sqh.HwQH.EndpointParams = EndpointParams; + + DummyQhVA->sqh.HwQH.EndpointCaps.AsULONG = 0; + DummyQhVA->sqh.HwQH.EndpointCaps.InterruptMask = 0; + DummyQhVA->sqh.HwQH.EndpointCaps.SplitCompletionMask = 0; + DummyQhVA->sqh.HwQH.EndpointCaps.PipeMultiplier = 1; + + DummyQhVA->sqh.HwQH.AlternateNextTD = 1; + DummyQhVA->sqh.HwQH.NextTD = 1; + + StaticQH = EHCI_GetQhForFrame(EhciExtension, ix); + DummyQhVA->sqh.StaticQH = StaticQH; + + *FrameHeader = (PEHCI_STATIC_QH)PrevPA.AsULONG; + + FrameHeader += 1; + ++ix; + + if (ix >= 1024) + { + break; + } + } +} + +VOID +NTAPI +EHCI_InitializeInterruptSchedule(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_STATIC_QH StaticQH; + ULONG ix; + static UCHAR LinkTable[64] = { + 255, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, + 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, + 30, 30, 0}; + + DPRINT_EHCI("EHCI_InitializeInterruptSchedule: ... \n"); + + for (ix = 0; ix < 63; ix++) + { + StaticQH = EhciExtension->PeriodicHead[ix]; + + StaticQH->HwQH.EndpointParams.HeadReclamationListFlag = 0; + StaticQH->HwQH.NextTD |= 1; + StaticQH->HwQH.Token.Status |= (UCHAR)EHCI_TOKEN_STATUS_HALTED; + } + + for (ix = 1; ix < 63; ix++) + { + StaticQH = EhciExtension->PeriodicHead[ix]; + + StaticQH->PrevHead = NULL; + StaticQH->NextHead = (PEHCI_HCD_QH)EhciExtension->PeriodicHead[LinkTable[ix]]; + + StaticQH->HwQH.HorizontalLink.AsULONG = + (ULONG)EhciExtension->PeriodicHead[LinkTable[ix]]->PhysicalAddress; + + StaticQH->HwQH.HorizontalLink.Type = EHCI_LINK_TYPE_QH; + StaticQH->HwQH.EndpointCaps.AsULONG = -1; + + StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC; + + if ((ix + 1) <= 6) + { + StaticQH->QhFlags |= 8; + } + } + + EhciExtension->PeriodicHead[0]->HwQH.HorizontalLink.Terminate = 1; + EhciExtension->PeriodicHead[0]->QhFlags |= (EHCI_QH_FLAG_STATIC | 8); +} + +MPSTATUS +NTAPI +EHCI_InitializeSchedule(IN PEHCI_EXTENSION EhciExtension, + IN PVOID resourcesStartVA, + IN PVOID resourcesStartPA) +{ + PULONG OperationalRegs; + PEHCI_HC_RESOURCES HcResourcesVA; + PEHCI_HC_RESOURCES HcResourcesPA; + PEHCI_STATIC_QH AsyncHead; + PEHCI_STATIC_QH AsyncHeadPA; + PEHCI_STATIC_QH PeriodicHead; + PEHCI_STATIC_QH PeriodicHeadPA; + PEHCI_STATIC_QH StaticQH; + EHCI_LINK_POINTER NextLink; + EHCI_LINK_POINTER StaticHeadPA; + ULONG Frame; + ULONG ix; + + DPRINT_EHCI("EHCI_InitializeSchedule: BaseVA - %p, BasePA - %p\n", + resourcesStartVA, + resourcesStartPA); + + OperationalRegs = EhciExtension->OperationalRegs; + + HcResourcesVA = (PEHCI_HC_RESOURCES)resourcesStartVA; + HcResourcesPA = (PEHCI_HC_RESOURCES)resourcesStartPA; + + EhciExtension->HcResourcesVA = HcResourcesVA; + EhciExtension->HcResourcesPA = HcResourcesPA; + + /* Asynchronous Schedule */ + + AsyncHead = &HcResourcesVA->AsyncHead; + AsyncHeadPA = &HcResourcesPA->AsyncHead; + + RtlZeroMemory(AsyncHead, sizeof(EHCI_STATIC_QH)); + + NextLink.AsULONG = (ULONG)AsyncHeadPA; + NextLink.Type = EHCI_LINK_TYPE_QH; + + AsyncHead->HwQH.HorizontalLink = NextLink; + AsyncHead->HwQH.EndpointParams.HeadReclamationListFlag = 1; + AsyncHead->HwQH.EndpointCaps.PipeMultiplier = 1; + AsyncHead->HwQH.NextTD |= 1; + AsyncHead->HwQH.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_HALTED; + + AsyncHead->PhysicalAddress = (PEHCI_HCD_QH)AsyncHeadPA; + AsyncHead->PrevHead = AsyncHead->NextHead = (PEHCI_HCD_QH)AsyncHead; + + EhciExtension->AsyncHead = AsyncHead; + + /* Periodic Schedule */ + + PeriodicHead = &HcResourcesVA->PeriodicHead[0]; + PeriodicHeadPA = &HcResourcesPA->PeriodicHead[0]; + + ix = 0; + + for (ix = 0; ix < 64; ix++) + { + EHCI_AlignHwStructure(EhciExtension, + (PULONG)&PeriodicHeadPA, + (PULONG)&PeriodicHead, + 80); + + EhciExtension->PeriodicHead[ix] = PeriodicHead; + EhciExtension->PeriodicHead[ix]->PhysicalAddress = (PEHCI_HCD_QH)PeriodicHeadPA; + + PeriodicHead += 1; + PeriodicHeadPA += 1; + } + + EHCI_InitializeInterruptSchedule(EhciExtension); + + for (Frame = 0; Frame < 1024; Frame++) + { + StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame); + + StaticHeadPA.AsULONG = (ULONG_PTR)StaticQH->PhysicalAddress; + StaticHeadPA.Type = EHCI_LINK_TYPE_QH; + + //DPRINT_EHCI("EHCI_InitializeSchedule: StaticHeadPA[%x] - %p\n", + // Frame, + // StaticHeadPA); + + HcResourcesVA->PeriodicFrameList[Frame] = (PEHCI_STATIC_QH)StaticHeadPA.AsULONG; + } + + EhciExtension->DummyQHListVA = (ULONG_PTR)&HcResourcesVA->DummyQH; + EhciExtension->DummyQHListPA = (ULONG_PTR)&HcResourcesPA->DummyQH; + + EHCI_AddDummyQHs(EhciExtension); + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_PERIODICLISTBASE, + (ULONG_PTR)EhciExtension->HcResourcesPA); + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_ASYNCLISTBASE, + NextLink.AsULONG); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_InitializeHardware(IN PEHCI_EXTENSION EhciExtension) +{ + PULONG BaseIoAdress; + PULONG OperationalRegs; + EHCI_USB_COMMAND Command; + LARGE_INTEGER CurrentTime = {{0, 0}}; + LARGE_INTEGER LastTime = {{0, 0}}; + EHCI_HC_STRUCTURAL_PARAMS StructuralParams; + + DPRINT_EHCI("EHCI_InitializeHardware: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + BaseIoAdress = EhciExtension->BaseIoAdress; + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.Reset = 1; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + + KeQuerySystemTime(&CurrentTime); + CurrentTime.QuadPart += 100 * 10000; // 100 msec + + DPRINT_EHCI("EHCI_InitializeHardware: Start reset ... \n"); + + while (TRUE) + { + KeQuerySystemTime(&LastTime); + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + + if (Command.Reset != 1) + { + break; + } + + if (LastTime.QuadPart >= CurrentTime.QuadPart) + { + if (Command.Reset == 1) + { + DPRINT1("EHCI_InitializeHardware: Reset failed!\n"); + return 7; + } + + break; + } + } + + DPRINT("EHCI_InitializeHardware: Reset - OK\n"); + + StructuralParams.AsULONG = READ_REGISTER_ULONG(BaseIoAdress + 1); // HCSPARAMS register + + EhciExtension->NumberOfPorts = StructuralParams.PortCount; + EhciExtension->PortPowerControl = StructuralParams.PortPowerControl; + + DPRINT("EHCI_InitializeHardware: StructuralParams - %p\n", StructuralParams.AsULONG); + DPRINT("EHCI_InitializeHardware: PortPowerControl - %x\n", EhciExtension->PortPowerControl); + DPRINT("EHCI_InitializeHardware: N_PORTS - %x\n", EhciExtension->NumberOfPorts); + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_PERIODICLISTBASE, 0); + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_ASYNCLISTBASE, 0); + + EhciExtension->InterruptMask.AsULONG = 0; + EhciExtension->InterruptMask.Interrupt = 1; + EhciExtension->InterruptMask.ErrorInterrupt = 1; + EhciExtension->InterruptMask.PortChangeInterrupt = 0; + EhciExtension->InterruptMask.FrameListRollover = 1; + EhciExtension->InterruptMask.HostSystemError = 1; + EhciExtension->InterruptMask.InterruptOnAsyncAdvance = 1; + + return 0; +} + +MPSTATUS +NTAPI +EHCI_TakeControlHC(IN PEHCI_EXTENSION EhciExtension) +{ + DPRINT1("EHCI_TakeControlHC: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +EHCI_GetRegistryParameters(IN PEHCI_EXTENSION EhciExtension) +{ + DPRINT1("EHCI_GetRegistryParameters: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +EHCI_StartController(IN PVOID ehciExtension, + IN PUSBPORT_RESOURCES Resources) +{ + PEHCI_EXTENSION EhciExtension; + PULONG BaseIoAdress; + PULONG OperationalRegs; + MPSTATUS MPStatus; + EHCI_USB_COMMAND Command; + UCHAR CapabilityRegLength; + UCHAR Fladj; + + DPRINT_EHCI("EHCI_StartController: ... \n"); + + if ((Resources->TypesResources & 6) != 6) // (Interrupt | Memory) + { + DPRINT1("EHCI_StartController: Resources->TypesResources - %x\n", + Resources->TypesResources); + + return 4; + } + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + BaseIoAdress = (PULONG)Resources->ResourceBase; + EhciExtension->BaseIoAdress = BaseIoAdress; + + CapabilityRegLength = (UCHAR)READ_REGISTER_ULONG(BaseIoAdress); + OperationalRegs = (PULONG)((ULONG)BaseIoAdress + CapabilityRegLength); + EhciExtension->OperationalRegs = OperationalRegs; + + DPRINT("EHCI_StartController: BaseIoAdress - %p\n", BaseIoAdress); + DPRINT("EHCI_StartController: OperationalRegs - %p\n", OperationalRegs); + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + 1, + &Fladj, + 0x61, + 1); + + EhciExtension->FrameLengthAdjustment = Fladj; + + EHCI_GetRegistryParameters(EhciExtension); + + MPStatus = EHCI_TakeControlHC(EhciExtension); + + if (MPStatus) + { + DPRINT1("EHCI_StartController: Unsuccessful TakeControlHC()\n"); + return MPStatus; + } + + MPStatus = EHCI_InitializeHardware(EhciExtension); + + if (MPStatus) + { + DPRINT1("EHCI_StartController: Unsuccessful InitializeHardware()\n"); + return MPStatus; + } + + MPStatus = EHCI_InitializeSchedule(EhciExtension, + Resources->StartVA, + Resources->StartPA); + + if (MPStatus) + { + DPRINT1("EHCI_StartController: Unsuccessful InitializeSchedule()\n"); + return MPStatus; + } + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + 1, + &Fladj, + 0x61, + 1); + + if (Fladj != EhciExtension->FrameLengthAdjustment) + { + Fladj = EhciExtension->FrameLengthAdjustment; + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + 0, // write + &Fladj, + 0x61, + 1); + } + + /* Port routing control logic default-routes all ports to this HC */ + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_CONFIGFLAG, 1); + EhciExtension->PortRoutingControl = 1; + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.InterruptThreshold = 1; // one micro-frame + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.Run = 1; // execution of the schedule + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + + EhciExtension->IsStarted = 1; + + if (Resources->Reserved1) + { + DPRINT1("EHCI_StartController: FIXME\n"); + DbgBreakPoint(); + } + + return MPStatus; +} + +VOID +NTAPI +EHCI_StopController(IN PVOID ehciExtension, + IN BOOLEAN IsDoDisableInterrupts) +{ + DPRINT1("EHCI_StopController: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_SuspendController(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG OperationalRegs; + EHCI_USB_COMMAND Command; + EHCI_USB_STATUS Status; + EHCI_INTERRUPT_ENABLE IntrEn; + ULONG ix; + + DPRINT("EHCI_SuspendController: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + OperationalRegs = EhciExtension->OperationalRegs; + + EhciExtension->BakupPeriodiclistbase = READ_REGISTER_ULONG(OperationalRegs + + EHCI_PERIODICLISTBASE); + + EhciExtension->BakupAsynclistaddr = READ_REGISTER_ULONG(OperationalRegs + + EHCI_ASYNCLISTBASE); + + EhciExtension->BakupCtrlDSSegment = READ_REGISTER_ULONG(OperationalRegs + + EHCI_CTRLDSSEGMENT); + + EhciExtension->BakupUSBCmd = READ_REGISTER_ULONG(OperationalRegs + + EHCI_USBCMD); + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.InterruptAdvanceDoorbell = 0; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.Run = 0; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + + KeStallExecutionProcessor(125); + + Status.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + + Status.HCHalted = 0; + Status.Reclamation = 0; + Status.PeriodicStatus = 0; + Status.AsynchronousStatus = 0; + + if (Status.AsULONG) + { + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS, Status.AsULONG); + } + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBINTR, 0); + + ix = 0; + + do + { + Status.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + + if (Status.HCHalted) + { + break; + } + + RegPacket.UsbPortWait(EhciExtension, 1); + + ++ix; + } + while (ix < 10); + + if (!Status.HCHalted) + { + DbgBreakPoint(); + } + + IntrEn.AsULONG = READ_REGISTER_ULONG((PULONG)(OperationalRegs + EHCI_USBINTR)); + IntrEn.PortChangeInterrupt = 1; + WRITE_REGISTER_ULONG((PULONG)(OperationalRegs + EHCI_USBINTR), IntrEn.AsULONG); + + EhciExtension->Flags |= 1; +} + +MPSTATUS +NTAPI +EHCI_ResumeController(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG OperationalRegs; + ULONG RoutingControl; + EHCI_USB_COMMAND Command; + + DPRINT("EHCI_ResumeController: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + OperationalRegs = EhciExtension->OperationalRegs; + + RoutingControl = EhciExtension->PortRoutingControl; + + if (!(RoutingControl & 1)) + { + EhciExtension->PortRoutingControl = RoutingControl | 1; + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_CONFIGFLAG, + RoutingControl | 1); + + return 7; + } + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_CTRLDSSEGMENT, + EhciExtension->BakupCtrlDSSegment); + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_PERIODICLISTBASE, + EhciExtension->BakupPeriodiclistbase); + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_ASYNCLISTBASE, + EhciExtension->BakupAsynclistaddr); + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + + Command.AsULONG = Command.AsULONG ^ EhciExtension->BakupUSBCmd; + + Command.Reset = 0; + Command.FrameListSize = 0; + Command.InterruptAdvanceDoorbell = 0; + Command.LightResetHC = 0; + Command.AsynchronousParkModeCount = 0; + Command.AsynchronousParkModeEnable = 0; + + Command.Run = 1; + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, + Command.AsULONG); + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBINTR, + EhciExtension->InterruptMask.AsULONG); + + EhciExtension->Flags &= ~1; + + return 0; +} + +BOOLEAN +NTAPI +EHCI_HardwarePresent(IN PEHCI_EXTENSION EhciExtension, + IN BOOLEAN IsInvalidateController) +{ + if (READ_REGISTER_ULONG(EhciExtension->OperationalRegs) != -1) + { + return TRUE; + } + + DPRINT1("EHCI_HardwarePresent: IsInvalidateController - %x\n", + IsInvalidateController); + + if (IsInvalidateController) + { + RegPacket.UsbPortInvalidateController(EhciExtension, 2); + } + + return FALSE; +} + +BOOLEAN +NTAPI +EHCI_InterruptService(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG OperationalRegs; + BOOLEAN Result = FALSE; + ULONG IntrSts; + ULONG IntrEn; + EHCI_INTERRUPT_ENABLE iStatus; + ULONG FrameIndex; + ULONG Command; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + OperationalRegs = EhciExtension->OperationalRegs; + + DPRINT_EHCI("EHCI_InterruptService: ... \n"); + + Result = EHCI_HardwarePresent(EhciExtension, FALSE); + + if (!Result) + { + return FALSE; + } + + IntrEn = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBINTR); + IntrSts = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + + iStatus.AsULONG = (IntrEn & IntrSts) & 0x3F; + + if (!iStatus.AsULONG) + { + return FALSE; + } + + EhciExtension->InterruptStatus = iStatus; + + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS, + (IntrEn & IntrSts) & 0x3F); + + if (iStatus.HostSystemError) + { + ++EhciExtension->HcSystemErrors; + + if (EhciExtension->HcSystemErrors < 0x100) + { + //attempting reset + Command = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + WRITE_REGISTER_ULONG((PULONG)OperationalRegs, Command | 1); + } + } + + FrameIndex = (READ_REGISTER_ULONG(OperationalRegs + EHCI_FRINDEX) >> 3) & 0x7FF; + + if ((FrameIndex ^ EhciExtension->FrameIndex) & 0x400) + { + EhciExtension->FrameHighPart = EhciExtension->FrameHighPart + 0x800 - + ((FrameIndex ^ EhciExtension->FrameHighPart) & 0x400); + } + + EhciExtension->FrameIndex = FrameIndex; + + return TRUE; +} + +VOID +NTAPI +EHCI_InterruptDpc(IN PVOID ehciExtension, + IN BOOLEAN IsDoEnableInterrupts) +{ + PEHCI_EXTENSION EhciExtension; + PULONG OperationalRegs; + EHCI_INTERRUPT_ENABLE iStatus; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + OperationalRegs = EhciExtension->OperationalRegs; + + DPRINT_EHCI("EHCI_InterruptDpc: ... \n"); + + iStatus = EhciExtension->InterruptStatus; + EhciExtension->InterruptStatus.AsULONG = 0; + + if ((UCHAR)iStatus.AsULONG & + (UCHAR)EhciExtension->InterruptMask.AsULONG & + 0x23) + { + RegPacket.UsbPortInvalidateEndpoint(EhciExtension, 0); + } + + if ((UCHAR)iStatus.AsULONG & + (UCHAR)EhciExtension->InterruptMask.AsULONG & + 0x04) + { + RegPacket.UsbPortInvalidateRootHub(EhciExtension); + } + + if (IsDoEnableInterrupts) + { + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBINTR, + EhciExtension->InterruptMask.AsULONG); + } +} + +ULONG +NTAPI +EHCI_MapAsyncTransferToTd(IN PEHCI_EXTENSION EhciExtension, + IN ULONG MaxPacketSize, + IN ULONG TransferedLen, + IN PULONG DataToggle, + IN PEHCI_TRANSFER EhciTransfer, + IN PEHCI_HCD_TD TD, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + PUSBPORT_SCATTER_GATHER_ELEMENT SgElement; + ULONG SgIdx; + ULONG LengthThisTD; + ULONG ix; + ULONG SgRemain; + ULONG DiffLength; + ULONG NumPackets; + + DPRINT_EHCI("EHCI_MapAsyncTransferToTd: EhciTransfer - %p, TD - %p, TransferedLen - %x, MaxPacketSize - %x, DataToggle - %x\n", + EhciTransfer, + TD, + TransferedLen, + MaxPacketSize, + DataToggle); + + TransferParameters = EhciTransfer->TransferParameters; + + SgIdx = 0; + + if (SgList->SgElementCount) + { + SgElement = &SgList->SgElement[0]; + + do + { + if (TransferedLen >= SgElement->SgOffset && + TransferedLen < SgElement->SgOffset + SgElement->SgTransferLength) + { + break; + } + + ++SgIdx; + SgElement += 1; + } + while (SgIdx < SgList->SgElementCount); + } + + SgRemain = SgList->SgElementCount - SgIdx; + + if (SgRemain > 5) + { + TD->HwTD.Buffer[0] = SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart - + SgList->SgElement[SgIdx].SgOffset + + TransferedLen; + + LengthThisTD = 5 * 0x1000 - (TD->HwTD.Buffer[0] & 0xFFF); + + for (ix = 1; ix <= 4; ix++) + { + TD->HwTD.Buffer[ix] = SgList->SgElement[SgIdx + ix].SgPhysicalAddress.LowPart; + } + + NumPackets = LengthThisTD / MaxPacketSize; + DiffLength = LengthThisTD - MaxPacketSize * (LengthThisTD / MaxPacketSize); + + if (LengthThisTD != MaxPacketSize * (LengthThisTD / MaxPacketSize)) + { + LengthThisTD -= DiffLength; + } + + if (DataToggle && (NumPackets & 1)) + { + *DataToggle = *DataToggle == 0; + } + } + else + { + LengthThisTD = TransferParameters->TransferBufferLength - TransferedLen; + + TD->HwTD.Buffer[0] = TransferedLen + + SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart - + SgList->SgElement[SgIdx].SgOffset; + + for (ix = 1; ix < 5; ix++) + { + if ((SgIdx + ix) >= SgList->SgElementCount) + { + break; + } + + TD->HwTD.Buffer[ix] = SgList->SgElement[SgIdx + ix].SgPhysicalAddress.LowPart; + } + } + + TD->HwTD.Token.TransferBytes = LengthThisTD; + TD->LengthThisTD = LengthThisTD; + + return LengthThisTD + TransferedLen; +} + +VOID +NTAPI +EHCI_EnableAsyncList(IN PEHCI_EXTENSION EhciExtension) +{ + PULONG OperationalRegs; + EHCI_USB_COMMAND UsbCmd; + + DPRINT_EHCI("EHCI_EnableAsyncList: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + UsbCmd.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + UsbCmd.AsynchronousEnable = 1; + WRITE_REGISTER_ULONG((OperationalRegs + EHCI_USBCMD), UsbCmd.AsULONG); +} + +VOID +NTAPI +EHCI_DisableAsyncList(IN PEHCI_EXTENSION EhciExtension) +{ + PULONG OperationalRegs; + EHCI_USB_COMMAND UsbCmd; + + DPRINT_EHCI("EHCI_DisableAsyncList: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + UsbCmd.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + UsbCmd.AsynchronousEnable = 0; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, UsbCmd.AsULONG); +} + +VOID +NTAPI +EHCI_EnablePeriodicList(IN PEHCI_EXTENSION EhciExtension) +{ + PULONG OperationalRegs; + EHCI_USB_COMMAND Command; + + DPRINT_EHCI("EHCI_EnablePeriodicList: ... \n"); + + OperationalRegs = (PULONG)EhciExtension->OperationalRegs; + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.PeriodicEnable = 1; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); +} + +VOID +NTAPI +EHCI_DisablePeriodicList(IN PEHCI_EXTENSION EhciExtension) +{ + PULONG OperationalRegs; + EHCI_USB_COMMAND Command; + + DPRINT_EHCI("EHCI_DisablePeriodicList: ... \n"); + + if (EhciExtension->Flags & 0x20) + { + OperationalRegs = (PULONG)EhciExtension->OperationalRegs; + + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Command.PeriodicEnable = 0; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + } +} + +VOID +NTAPI +EHCI_FlushAsyncCache(IN PEHCI_EXTENSION EhciExtension) +{ + PULONG OperationalRegs; + EHCI_USB_COMMAND Command; + EHCI_USB_STATUS Status; + LARGE_INTEGER CurrentTime = {{0, 0}}; + LARGE_INTEGER FirstTime = {{0, 0}}; + EHCI_USB_COMMAND Cmd; + + DPRINT_EHCI("EHCI_FlushAsyncCache: EhciExtension - %p\n", EhciExtension); + + OperationalRegs = EhciExtension->OperationalRegs; + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + Status.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + + if (!Status.AsynchronousStatus && !Command.AsynchronousEnable) + { + return; + } + + if (Status.AsynchronousStatus && !Command.AsynchronousEnable) + { + KeQuerySystemTime(&FirstTime); + FirstTime.QuadPart += 100 * 10000; //100 ms + + do + { + Status.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + KeQuerySystemTime(&CurrentTime); + + if (CurrentTime.QuadPart > FirstTime.QuadPart) + { + RegPacket.UsbPortBugCheck(EhciExtension); + } + } + while (Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run); + + return; + } + + if (!Status.AsynchronousStatus && Command.AsynchronousEnable) + { + KeQuerySystemTime(&FirstTime); + FirstTime.QuadPart += 100 * 10000; //100 ms + + do + { + Status.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + KeQuerySystemTime(&CurrentTime); + } + while (!Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run); + } + + Command.InterruptAdvanceDoorbell = 1; + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD, Command.AsULONG); + + KeQuerySystemTime(&FirstTime); + FirstTime.QuadPart += 100 * 10000; //100 ms + + Cmd.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + + if (Cmd.InterruptAdvanceDoorbell) + { + while (Cmd.Run) + { + if (Cmd.AsULONG == -1) + { + break; + } + + KeStallExecutionProcessor(1); + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + KeQuerySystemTime(&CurrentTime); + + if (!Command.InterruptAdvanceDoorbell) + { + break; + } + + Cmd = Command; + } + } + + /* InterruptOnAsyncAdvance */ + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS, 0x20); +} + +VOID +NTAPI +EHCI_LockQH(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QueueHead, + IN ULONG TransferType) +{ + PEHCI_HCD_QH PrevQH; + ULONG QhPA; + ULONG FrameIndexReg; + PULONG OperationalRegs; + ULONG Command; + + DPRINT_EHCI("EHCI_LockQH: QueueHead - %p, TransferType - %x\n", + QueueHead, + TransferType); + + OperationalRegs = EhciExtension->OperationalRegs; + + ASSERT((QueueHead->sqh.QhFlags & EHCI_QH_FLAG_UPDATING) == 0); + ASSERT(EhciExtension->LockQH == NULL); + + PrevQH = QueueHead->sqh.PrevHead; + QueueHead->sqh.QhFlags |= EHCI_QH_FLAG_UPDATING; + + ASSERT(PrevQH); + + EhciExtension->PrevQH = PrevQH; + EhciExtension->NextQH = QueueHead->sqh.NextHead; + EhciExtension->LockQH = QueueHead; + + if (QueueHead->sqh.NextHead) + { + QhPA = ((ULONG_PTR)QueueHead->sqh.NextHead->sqh.PhysicalAddress & ~0x1C) | 2; + } + else + { + QhPA = 1; + } + + PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA; + + FrameIndexReg = READ_REGISTER_ULONG(OperationalRegs + EHCI_FRINDEX); + + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + do + { + Command = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + } + while (READ_REGISTER_ULONG(OperationalRegs + EHCI_FRINDEX) == + FrameIndexReg && (Command != -1) && (Command & 1)); + } + else + { + EHCI_FlushAsyncCache(EhciExtension); + } +} + +VOID +NTAPI +EHCI_UnlockQH(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QueueHead) +{ + DPRINT_EHCI("EHCI_UnlockQH: QueueHead - %p\n", QueueHead); + + ASSERT((QueueHead->sqh.QhFlags & EHCI_QH_FLAG_UPDATING) != 0); + ASSERT(EhciExtension->LockQH != 0); + ASSERT(EhciExtension->LockQH == QueueHead); + + QueueHead->sqh.QhFlags &= ~EHCI_QH_FLAG_UPDATING; + + EhciExtension->LockQH = NULL; + + EhciExtension->PrevQH->sqh.HwQH.HorizontalLink.AsULONG = + ((ULONG_PTR)QueueHead->sqh.PhysicalAddress & ~0x1C) | 2; +} + +VOID +NTAPI +EHCI_LinkTransferToQueue(PEHCI_EXTENSION EhciExtension, + PEHCI_ENDPOINT EhciEndpoint, + PEHCI_HCD_TD NextTD) +{ + PEHCI_HCD_QH QH; + PEHCI_HCD_TD TD; + PEHCI_TRANSFER Transfer; + PEHCI_HCD_TD LinkTD; + BOOLEAN IsPresent; + ULONG ix; + + DPRINT_EHCI("EHCI_LinkTransferToQueue: EhciEndpoint - %p, NextTD - %p\n", + EhciEndpoint, + NextTD); + + ASSERT(EhciEndpoint->HcdHeadP != NULL); + IsPresent = EHCI_HardwarePresent(EhciExtension, 0); + + QH = EhciEndpoint->QH; + TD = EhciEndpoint->HcdHeadP; + + if (TD == EhciEndpoint->HcdTailP) + { + if (IsPresent) + { + EHCI_LockQH(EhciExtension, + QH, + EhciEndpoint->EndpointProperties.TransferType); + } + + QH->sqh.HwQH.CurrentTD = (ULONG_PTR)EhciEndpoint->DummyTdPA; + QH->sqh.HwQH.NextTD = (ULONG_PTR)NextTD->PhysicalAddress; + QH->sqh.HwQH.AlternateNextTD = NextTD->HwTD.AlternateNextTD; + + QH->sqh.HwQH.Token.Status = (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE | + EHCI_TOKEN_STATUS_HALTED); + + QH->sqh.HwQH.Token.TransferBytes = 0; + + if (IsPresent) + { + EHCI_UnlockQH(EhciExtension, QH); + } + + EhciEndpoint->HcdHeadP = NextTD; + } + else + { + DbgBreakPoint(); + + DPRINT("EHCI_LinkTransferToQueue: TD - %p, DummyTd - %p\n", + EhciEndpoint->HcdHeadP, + EhciEndpoint->HcdTailP); + + LinkTD = EhciEndpoint->HcdHeadP; + + if (TD != EhciEndpoint->HcdTailP) + { + while (TRUE) + { + LinkTD = TD; + TD = TD->NextHcdTD; + + if (TD == EhciEndpoint->HcdTailP) + { + break; + } + } + } + + ASSERT(LinkTD != EhciEndpoint->HcdTailP); + + Transfer = LinkTD->EhciTransfer; + + ix = 0; + + if (EhciEndpoint->MaxTDs) + { + TD = EhciEndpoint->FirstTD; + + do + { + if (TD->EhciTransfer == Transfer) + { + TD->HwTD.AlternateNextTD = (ULONG_PTR)NextTD->PhysicalAddress; + TD->AltNextHcdTD = NextTD; + + } + + ++ix; + TD += 1; + } + while (ix < EhciEndpoint->MaxTDs); + } + + LinkTD->HwTD.NextTD = (ULONG_PTR)NextTD->PhysicalAddress; + LinkTD->NextHcdTD = NextTD; + + if (QH->sqh.HwQH.CurrentTD == (ULONG_PTR)LinkTD->PhysicalAddress) + { + QH->sqh.HwQH.NextTD = (ULONG_PTR)NextTD->PhysicalAddress; + QH->sqh.HwQH.AlternateNextTD = 1; + } + } +} + +MPSTATUS +NTAPI +EHCI_ControlTransfer(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PEHCI_TRANSFER EhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PEHCI_HCD_TD FirstTD; + PEHCI_HCD_TD LastTD; + PEHCI_HCD_TD TD; + PEHCI_HCD_TD PrevTD; + PEHCI_HCD_TD LinkTD; + ULONG TransferedLen = 0; + EHCI_TD_TOKEN Token; + ULONG DataToggle = 1; + + DPRINT_EHCI("EHCI_ControlTransfer: EhciEndpoint - %p, EhciTransfer - %p\n", + EhciEndpoint, + EhciTransfer); + + if (EhciEndpoint->RemainTDs < 6) + { + return 1; + } + + ++EhciExtension->PendingTransfers; + ++EhciEndpoint->PendingTDs; + + EhciTransfer->TransferOnAsyncList = 1; + + FirstTD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!FirstTD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return 1; + } + + ++EhciTransfer->PendingTDs; + + FirstTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + FirstTD->EhciTransfer = EhciTransfer; + + FirstTD->HwTD.Buffer[0] = 0; + FirstTD->HwTD.Buffer[1] = 0; + FirstTD->HwTD.Buffer[2] = 0; + FirstTD->HwTD.Buffer[3] = 0; + FirstTD->HwTD.Buffer[4] = 0; + + FirstTD->NextHcdTD = NULL; + + FirstTD->HwTD.NextTD = 1; + FirstTD->HwTD.AlternateNextTD = 1; + FirstTD->HwTD.Buffer[0] = (ULONG_PTR)&FirstTD->PhysicalAddress->SetupPacket; + + FirstTD->HwTD.Token.ErrorCounter = 3; + FirstTD->HwTD.Token.PIDCode = 2; + FirstTD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + FirstTD->HwTD.Token.TransferBytes = 0x8; + + RtlCopyMemory(&FirstTD->SetupPacket, + &TransferParameters->SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + LastTD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!LastTD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return 1; + } + + ++EhciTransfer->PendingTDs; + + LastTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + LastTD->EhciTransfer = EhciTransfer; + + LastTD->HwTD.Buffer[0] = 0; + LastTD->HwTD.Buffer[1] = 0; + LastTD->HwTD.Buffer[2] = 0; + LastTD->HwTD.Buffer[3] = 0; + LastTD->HwTD.Buffer[4] = 0; + + LastTD->NextHcdTD = NULL; + LastTD->HwTD.NextTD = 1; + LastTD->HwTD.AlternateNextTD = 1; + LastTD->HwTD.Token.ErrorCounter = 3; + + FirstTD->HwTD.AlternateNextTD = (ULONG_PTR)LastTD->PhysicalAddress; + FirstTD->AltNextHcdTD = LastTD; + + PrevTD = FirstTD; + LinkTD = FirstTD; + + if (TransferParameters->TransferBufferLength > 0) + { + while (TRUE) + { + TD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!TD) + { + break; + } + + LinkTD = TD; + + ++EhciTransfer->PendingTDs; + + TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + TD->EhciTransfer = EhciTransfer; + + TD->HwTD.Buffer[0] = 0; + TD->HwTD.Buffer[1] = 0; + TD->HwTD.Buffer[2] = 0; + TD->HwTD.Buffer[3] = 0; + TD->HwTD.Buffer[4] = 0; + + TD->NextHcdTD = NULL; + + TD->HwTD.NextTD = 1; + TD->HwTD.AlternateNextTD = 1; + TD->HwTD.Token.ErrorCounter = 3; + + PrevTD->HwTD.NextTD = (ULONG_PTR)TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.Token.PIDCode = 1; + } + else + { + TD->HwTD.Token.PIDCode = 0; + } + + TD->HwTD.Token.DataToggle = DataToggle; + TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + + if (DataToggle) + { + TD->HwTD.Token.DataToggle = 1; + } + else + { + TD->HwTD.Token.DataToggle = 0; + } + + TD->HwTD.AlternateNextTD = (ULONG_PTR)LastTD->PhysicalAddress; + TD->AltNextHcdTD = LastTD; + + TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension, + EhciEndpoint->EndpointProperties.MaxPacketSize, + TransferedLen, + &DataToggle, + EhciTransfer, + TD, + SgList); + + PrevTD = TD; + + if (TransferedLen >= TransferParameters->TransferBufferLength) + { + goto End; + } + } + + RegPacket.UsbPortBugCheck(EhciExtension); + return 1; + } + +End: + + LinkTD->HwTD.NextTD = (ULONG_PTR)LastTD->PhysicalAddress; + LinkTD->NextHcdTD = LastTD; + + LastTD->HwTD.Buffer[0] = 0; + LastTD->LengthThisTD = 0; + + Token = LastTD->HwTD.Token; + Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + Token.InterruptOnComplete = 1; + Token.DataToggle = 1; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + Token.PIDCode = 0; + } + else + { + Token.PIDCode = 1; + } + + LastTD->HwTD.Token = Token; + + LastTD->HwTD.NextTD = (ULONG_PTR)EhciEndpoint->HcdTailP->PhysicalAddress; + LastTD->NextHcdTD = EhciEndpoint->HcdTailP; + + EHCI_EnableAsyncList(EhciExtension); + EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD); + + ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL); // dummyTD - > NextHcdTD + ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL); // dummyTD - > AltNextHcdTD + + //EHCI_DPrintHwTD(FirstTD); + //EHCI_DPrintHwTD(FirstTD->NextHcdTD); + //EHCI_DPrintHwTD(LastTD); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_BulkTransfer(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PEHCI_TRANSFER EhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PEHCI_HCD_TD PrevTD; + PEHCI_HCD_TD FirstTD; + PEHCI_HCD_TD TD; + ULONG TransferedLen; + + DPRINT_EHCI("EHCI_BulkTransfer: EhciEndpoint - %p, EhciTransfer - %p\n", + EhciEndpoint, + EhciTransfer); + + if (((TransferParameters->TransferBufferLength >> 14) + 1) > EhciEndpoint->RemainTDs) + { + DPRINT1("EHCI_BulkTransfer: return 1\n"); + return 1; + } + + ++EhciExtension->PendingTransfers; + ++EhciEndpoint->PendingTDs; + + EhciTransfer->TransferOnAsyncList = 1; + + TransferedLen = 0; + PrevTD = NULL; + + if (TransferParameters->TransferBufferLength) + { + do + { + TD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!TD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return 1; + } + + ++EhciTransfer->PendingTDs; + + TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + TD->EhciTransfer = EhciTransfer; + + TD->HwTD.Buffer[0] = 0; + TD->HwTD.Buffer[1] = 0; + TD->HwTD.Buffer[2] = 0; + TD->HwTD.Buffer[3] = 0; + TD->HwTD.Buffer[4] = 0; + + TD->NextHcdTD = NULL; + TD->HwTD.NextTD = 1; + TD->HwTD.AlternateNextTD = 1; + TD->HwTD.Token.ErrorCounter = 3; + + if (EhciTransfer->PendingTDs == 1) + { + FirstTD = TD; + } + else + { + PrevTD->HwTD.NextTD = (ULONG_PTR)TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + } + + TD->HwTD.AlternateNextTD = (ULONG_PTR)EhciEndpoint->HcdTailP->PhysicalAddress; + TD->AltNextHcdTD = EhciEndpoint->HcdTailP; + + TD->HwTD.Token.InterruptOnComplete = 1; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.Token.PIDCode = 1; + } + else + { + TD->HwTD.Token.PIDCode = 0; + } + + TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + TD->HwTD.Token.DataToggle = 1; + + TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension, + EhciEndpoint->EndpointProperties.MaxPacketSize, + TransferedLen, + 0, + EhciTransfer, + TD, + SgList); + + PrevTD = TD; + } + while (TransferedLen < TransferParameters->TransferBufferLength); + } + else + { + TD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!TD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return 1; + } + + ++EhciTransfer->PendingTDs; + + TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + TD->EhciTransfer = EhciTransfer; + + TD->HwTD.Buffer[0] = 0; + TD->HwTD.Buffer[1] = 0; + TD->HwTD.Buffer[2] = 0; + TD->HwTD.Buffer[3] = 0; + TD->HwTD.Buffer[4] = 0; + + TD->HwTD.NextTD = 1; + TD->HwTD.AlternateNextTD = 1; + TD->HwTD.Token.ErrorCounter = 3; + TD->NextHcdTD = NULL; + + ASSERT(EhciTransfer->PendingTDs == 1); + + FirstTD = TD; + + TD->HwTD.AlternateNextTD = (ULONG_PTR)EhciEndpoint->HcdTailP->PhysicalAddress; + TD->AltNextHcdTD = EhciEndpoint->HcdTailP; + + TD->HwTD.Token.InterruptOnComplete = 1; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.Token.PIDCode = 1; + } + else + { + TD->HwTD.Token.PIDCode = 0; + } + + TD->HwTD.Buffer[0] = (ULONG_PTR)TD->PhysicalAddress; + + TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + TD->HwTD.Token.DataToggle = 1; + + TD->LengthThisTD = 0; + } + + TD->HwTD.NextTD = (ULONG_PTR)EhciEndpoint->HcdTailP->PhysicalAddress; + TD->NextHcdTD = EhciEndpoint->HcdTailP; + + EHCI_EnableAsyncList(EhciExtension); + EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD); + + ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == 0); + ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == 0); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_InterruptTransfer(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PEHCI_TRANSFER EhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PEHCI_HCD_TD TD; + PEHCI_HCD_TD FirstTD; + PEHCI_HCD_TD PrevTD; + ULONG TransferedLen; + + DPRINT_EHCI("EHCI_InterruptTransfer: EhciEndpoint - %p, EhciTransfer - %p\n", + EhciEndpoint, + EhciTransfer); + + if (!EhciEndpoint->RemainTDs) + { + DbgBreakPoint(); + return 1; + } + + ++EhciEndpoint->PendingTDs; + + TransferedLen = 0; + PrevTD = NULL; + + if (TransferParameters->TransferBufferLength) + { + do + { + TD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + if (!TD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return 1; + } + + ++EhciTransfer->PendingTDs; + + TD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + TD->EhciTransfer = EhciTransfer; + + TD->HwTD.Buffer[0] = 0; + TD->HwTD.Buffer[1] = 0; + TD->HwTD.Buffer[2] = 0; + TD->HwTD.Buffer[3] = 0; + TD->HwTD.Buffer[4] = 0; + + TD->HwTD.NextTD = 1; + TD->HwTD.AlternateNextTD = 1; + TD->HwTD.Token.ErrorCounter = 3; + TD->NextHcdTD = NULL; + + if (EhciTransfer->PendingTDs == 1) + { + FirstTD = TD; + } + else if (PrevTD) + { + PrevTD->HwTD.NextTD = (ULONG_PTR)TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + } + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.Token.PIDCode = 1; + } + else + { + TD->HwTD.Token.PIDCode = 0; + } + + TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + TD->HwTD.Token.DataToggle = 1; + + TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension, + EhciEndpoint->EndpointProperties.MaxPacketSize, + TransferedLen, + NULL, + EhciTransfer, + TD, + SgList); + + PrevTD = TD; + } + while (TransferedLen < TransferParameters->TransferBufferLength); + } + else + { + DbgBreakPoint(); + } + + TD->HwTD.Token.InterruptOnComplete = 1; + + TD->HwTD.NextTD = (ULONG_PTR)EhciEndpoint->HcdTailP->PhysicalAddress; + TD->NextHcdTD = EhciEndpoint->HcdTailP; + + EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD); + + ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL); + ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL); + + EHCI_EnablePeriodicList(EhciExtension); + + return 0; +} + +MPSTATUS +NTAPI +EHCI_SubmitTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PVOID transferParameters, + IN PVOID ehciTransfer, + IN PVOID sgList) +{ + PEHCI_EXTENSION EhciExtension; + PEHCI_ENDPOINT EhciEndpoint; + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + PEHCI_TRANSFER EhciTransfer; + PUSBPORT_SCATTER_GATHER_LIST SgList; + MPSTATUS MPStatus; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + TransferParameters = (PUSBPORT_TRANSFER_PARAMETERS)transferParameters; + EhciTransfer = (PEHCI_TRANSFER)ehciTransfer; + SgList = (PUSBPORT_SCATTER_GATHER_LIST)sgList; + + DPRINT_EHCI("EHCI_SubmitTransfer: EhciEndpoint - %p, EhciTransfer - %p\n", + EhciEndpoint, + EhciTransfer); + + RtlZeroMemory(EhciTransfer, sizeof(EHCI_TRANSFER)); + + EhciTransfer->TransferParameters = TransferParameters; + EhciTransfer->USBDStatus = USBD_STATUS_SUCCESS; + EhciTransfer->EhciEndpoint = EhciEndpoint; + + switch (EhciEndpoint->EndpointProperties.TransferType) + { + case USBPORT_TRANSFER_TYPE_CONTROL: + MPStatus = EHCI_ControlTransfer(EhciExtension, + EhciEndpoint, + TransferParameters, + EhciTransfer, + SgList); + break; + + case USBPORT_TRANSFER_TYPE_BULK: + MPStatus = EHCI_BulkTransfer(EhciExtension, + EhciEndpoint, + TransferParameters, + EhciTransfer, + SgList); + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + MPStatus = EHCI_InterruptTransfer(EhciExtension, + EhciEndpoint, + TransferParameters, + EhciTransfer, + SgList); + break; + + default: + DbgBreakPoint(); + MPStatus = 2;//?or? + break; + } + + return MPStatus; +} + +MPSTATUS +NTAPI +EHCI_SubmitIsoTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PVOID transferParameters, + IN PVOID ehciTransfer, + IN PVOID isoParameters) +{ + DPRINT1("EHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +EHCI_AbortIsoTransfer(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN PEHCI_TRANSFER EhciTransfer) +{ + DPRINT1("EHCI_AbortIsoTransfer: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_AbortAsyncTransfer(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN PEHCI_TRANSFER EhciTransfer) +{ + PEHCI_HCD_QH QH; + PEHCI_HCD_TD TD; + ULONG TransferLength; + PEHCI_HCD_TD CurrentTD; + PEHCI_TRANSFER CurrentTransfer; + PEHCI_HCD_TD FirstTD; + PEHCI_HCD_TD LastTD; + PEHCI_HCD_TD NextTD; + + DPRINT("EHCI_AbortAsyncTransfer: ... \n"); + + QH = EhciEndpoint->QH; + TD = EhciEndpoint->HcdHeadP; + + --EhciEndpoint->PendingTDs; + + if (TD->EhciTransfer == EhciTransfer) + { + TransferLength = 0; + + if (TD != EhciEndpoint->HcdTailP) + { + do + { + if (TD->EhciTransfer != EhciTransfer) + { + break; + } + + TransferLength += TD->LengthThisTD - TD->HwTD.Token.TransferBytes; + + TD = TD->NextHcdTD; + + TD->TdFlags = 0; + TD->HwTD.NextTD = 0; + TD->HwTD.AlternateNextTD = 0; + + ++EhciEndpoint->RemainTDs; + + TD->EhciTransfer = NULL; + } + while (TD != EhciEndpoint->HcdTailP); + + if (TransferLength) + { + EhciTransfer->TransferLen += TransferLength; + } + } + + QH->sqh.HwQH.CurrentTD = (ULONG)EhciEndpoint->DummyTdPA; + QH->sqh.HwQH.NextTD = (ULONG)TD->PhysicalAddress; + QH->sqh.HwQH.AlternateNextTD = TD->HwTD.AlternateNextTD; + + QH->sqh.HwQH.Token.TransferBytes = 0; + QH->sqh.HwQH.Token.Status = (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE | + EHCI_TOKEN_STATUS_HALTED); + + EhciEndpoint->HcdHeadP = TD; + } + else + { + CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress((PVOID)QH->sqh.HwQH.CurrentTD, + EhciExtension, + EhciEndpoint); + + CurrentTransfer = CurrentTD->EhciTransfer; + + TD = EhciEndpoint->HcdHeadP; + + while (TD && TD->EhciTransfer != EhciTransfer) + { + TD = TD->NextHcdTD; + } + + FirstTD = TD; + + do + { + if (TD->EhciTransfer != EhciTransfer) + { + break; + } + + TD->TdFlags = 0; + TD->HwTD.NextTD = 0; + TD->HwTD.AlternateNextTD = 0; + + ++EhciEndpoint->RemainTDs; + + TD->EhciTransfer = NULL; + + TD = TD->NextHcdTD; + } + while (TD); + + LastTD = TD; + NextTD = (PEHCI_HCD_TD)LastTD->PhysicalAddress->HwTD.NextTD; + + FirstTD->HwTD.NextTD = (ULONG)LastTD->PhysicalAddress; + FirstTD->HwTD.AlternateNextTD = (ULONG)LastTD->PhysicalAddress; + + FirstTD->NextHcdTD = LastTD; + FirstTD->AltNextHcdTD = LastTD; + + if (CurrentTransfer == EhciTransfer) + { + QH->sqh.HwQH.CurrentTD = (ULONG)EhciEndpoint->DummyTdPA; + + QH->sqh.HwQH.Token.Status = (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + QH->sqh.HwQH.Token.TransferBytes = 0; + + QH->sqh.HwQH.NextTD = (ULONG)NextTD; + QH->sqh.HwQH.AlternateNextTD = 1; + + return; + } + + if (FirstTD->EhciTransfer == CurrentTransfer) + { + if (QH->sqh.HwQH.NextTD == (ULONG)FirstTD->PhysicalAddress) + { + QH->sqh.HwQH.NextTD = (ULONG)NextTD; + } + + if (QH->sqh.HwQH.AlternateNextTD == (ULONG)FirstTD->PhysicalAddress) + { + QH->sqh.HwQH.AlternateNextTD = (ULONG)NextTD; + } + + for (TD = EhciEndpoint->HcdHeadP; + TD; + TD = TD->NextHcdTD) + { + if (TD->EhciTransfer == CurrentTransfer) + { + TD->HwTD.AlternateNextTD = (ULONG)NextTD; + TD->AltNextHcdTD = LastTD; + } + } + } + } +} + +VOID +NTAPI +EHCI_AbortTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PVOID ehciTransfer, + IN PULONG CompletedLength) +{ + PEHCI_EXTENSION EhciExtension; + PEHCI_ENDPOINT EhciEndpoint; + PEHCI_TRANSFER EhciTransfer; + ULONG TransferType; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + EhciTransfer = (PEHCI_TRANSFER)ehciTransfer; + + DPRINT_EHCI("EHCI_AbortTransfer: EhciTransfer - %p, CompletedLength - %x\n", + EhciTransfer, + CompletedLength); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + EHCI_AbortIsoTransfer(EhciExtension, EhciEndpoint, EhciTransfer); + } + else + { + EHCI_AbortAsyncTransfer(EhciExtension, EhciEndpoint, EhciTransfer); + } +} + +ULONG +NTAPI +EHCI_GetEndpointState(IN PVOID ehciExtension, + IN PVOID ehciEndpoint) +{ + DPRINT1("EHCI_GetEndpointState: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +EHCI_RemoveQhFromPeriodicList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_RemoveQhFromPeriodicList: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_RemoveQhFromAsyncList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QH) +{ + PEHCI_HCD_QH NextHead; + PEHCI_HCD_QH PrevHead; + PEHCI_STATIC_QH AsyncHead; + ULONG AsyncHeadPA; + + DPRINT_EHCI("EHCI_RemoveQhFromAsyncList: QH - %p\n", QH); + + if (QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) + { + NextHead = QH->sqh.NextHead; + PrevHead = QH->sqh.PrevHead; + + AsyncHead = EhciExtension->AsyncHead; + AsyncHeadPA = ((ULONG_PTR)AsyncHead->PhysicalAddress & ~0x1C) | 2; + + PrevHead->sqh.HwQH.HorizontalLink.AsULONG = + ((ULONG_PTR)NextHead->sqh.PhysicalAddress & ~0x1C) | 2; + + PrevHead->sqh.NextHead = NextHead; + NextHead->sqh.PrevHead = PrevHead; + + EHCI_FlushAsyncCache(EhciExtension); + + if (READ_REGISTER_ULONG(EhciExtension->OperationalRegs + EHCI_ASYNCLISTBASE) == + (ULONG_PTR)QH->sqh.PhysicalAddress) + { + WRITE_REGISTER_ULONG((EhciExtension->OperationalRegs + EHCI_ASYNCLISTBASE), + AsyncHeadPA); + } + + QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE; + } +} + +VOID +NTAPI +EHCI_InsertQhInPeriodicList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_InsertQhInPeriodicList: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_InsertQhInAsyncList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QH) +{ + PEHCI_STATIC_QH AsyncHead; + PEHCI_HCD_QH NextHead; + + DPRINT_EHCI("EHCI_InsertQhInAsyncList: QH - %p\n", QH); + + ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) == 0); + ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_NUKED) == 0); + + AsyncHead = EhciExtension->AsyncHead; + NextHead = AsyncHead->NextHead; + + QH->sqh.HwQH.HorizontalLink = AsyncHead->HwQH.HorizontalLink; + QH->sqh.QhFlags |= EHCI_QH_FLAG_IN_SCHEDULE; + QH->sqh.NextHead = NextHead; + QH->sqh.PrevHead = (PEHCI_HCD_QH)AsyncHead; + + NextHead->sqh.PrevHead = QH; + + AsyncHead->HwQH.HorizontalLink.AsULONG = ((ULONG_PTR)QH->sqh.PhysicalAddress & ~0x1C) | 2; + AsyncHead->NextHead = QH; +} + +VOID +NTAPI +EHCI_SetIsoEndpointState(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN ULONG EndpointState) +{ + DPRINT1("EHCI_SetIsoEndpointState: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_SetAsyncEndpointState(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN ULONG EndpointState) +{ + PEHCI_HCD_QH QH; + ULONG TransferType; + + DPRINT_EHCI("EHCI_SetAsyncEndpointState: EhciEndpoint - %p, EndpointState - %p\n", + EhciEndpoint, + EndpointState); + + QH = EhciEndpoint->QH; + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + switch (EndpointState) + { + case USBPORT_ENDPOINT_PAUSED: + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + EHCI_RemoveQhFromPeriodicList(EhciExtension, EhciEndpoint); + } + else + { + EHCI_RemoveQhFromAsyncList(EhciExtension, EhciEndpoint->QH); + } + + break; + + case USBPORT_ENDPOINT_ACTIVE: + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + EHCI_InsertQhInPeriodicList(EhciExtension, EhciEndpoint); + } + else + { + EHCI_InsertQhInAsyncList(EhciExtension, EhciEndpoint->QH); + } + + break; + + case USBPORT_ENDPOINT_CLOSED: + QH->sqh.QhFlags |= 2; + + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + EHCI_RemoveQhFromPeriodicList(EhciExtension, EhciEndpoint); + } + else + { + EHCI_RemoveQhFromAsyncList(EhciExtension, EhciEndpoint->QH); + } + + break; + + default: + DbgBreakPoint(); + break; + } + + EhciEndpoint->EndpointState = EndpointState; +} + +VOID +NTAPI +EHCI_SetEndpointState(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN ULONG EndpointState) +{ + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + + DPRINT_EHCI("EHCI_SetEndpointState: ... \n"); + + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + EHCI_SetAsyncEndpointState((PEHCI_EXTENSION)ehciExtension, + EhciEndpoint, + EndpointState); + } + else if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + EHCI_SetIsoEndpointState((PEHCI_EXTENSION)ehciExtension, + EhciEndpoint, + EndpointState); + } + else + { + RegPacket.UsbPortBugCheck(ehciExtension); + } +} + +VOID +NTAPI +EHCI_InterruptNextSOF(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + + DPRINT_EHCI("EHCI_InterruptNextSOF: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + RegPacket.UsbPortInvalidateController(EhciExtension, 3); +} + +USBD_STATUS +NTAPI +EHCI_GetErrorFromTD(IN PEHCI_HCD_TD TD) +{ + EHCI_TD_TOKEN Token; + + DPRINT_EHCI("EHCI_GetErrorFromTD: ... \n"); + + ASSERT(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_HALTED); + + Token = TD->HwTD.Token; + + if (Token.Status & EHCI_TOKEN_STATUS_TRANSACTION_ERROR) + { + DPRINT("EHCI_GetErrorFromTD: TD - %p, TRANSACTION_ERROR\n", TD); + return USBD_STATUS_XACT_ERROR; + } + + if (Token.Status & EHCI_TOKEN_STATUS_BABBLE_DETECTED) + { + DPRINT("EHCI_GetErrorFromTD: TD - %p, BABBLE_DETECTED\n", TD); + return USBD_STATUS_BABBLE_DETECTED; + } + + if (Token.Status & EHCI_TOKEN_STATUS_DATA_BUFFER_ERROR) + { + DPRINT("EHCI_GetErrorFromTD: TD - %p, DATA_BUFFER_ERROR\n", TD); + return USBD_STATUS_DATA_BUFFER_ERROR; + } + + if (Token.Status & EHCI_TOKEN_STATUS_MISSED_MICROFRAME) + { + DPRINT("EHCI_GetErrorFromTD: TD - %p, MISSED_MICROFRAME\n", TD); + return USBD_STATUS_XACT_ERROR; + } + + DPRINT("EHCI_GetErrorFromTD: TD - %p, STALL_PID\n", TD); + return USBD_STATUS_STALL_PID; +} + +VOID +NTAPI +EHCI_ProcessDoneAsyncTd(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_TD TD) +{ + PEHCI_TRANSFER EhciTransfer; + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + ULONG TransferType; + PEHCI_ENDPOINT EhciEndpoint; + ULONG LengthTransfered; + USBD_STATUS USBDStatus; + PULONG OperationalRegs; + EHCI_USB_COMMAND Command; + + DPRINT_EHCI("EHCI_ProcessDoneAsyncTd: TD - %p\n", TD); + + EhciTransfer = TD->EhciTransfer; + + TransferParameters = EhciTransfer->TransferParameters; + --EhciTransfer->PendingTDs; + + EhciEndpoint = EhciTransfer->EhciEndpoint; + + if (TD->TdFlags & 0x10) + { + goto Next; + } + + if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_HALTED) + { + USBDStatus = EHCI_GetErrorFromTD(TD); + } + else + { + USBDStatus = USBD_STATUS_SUCCESS; + } + + LengthTransfered = TD->LengthThisTD - TD->HwTD.Token.TransferBytes; + + if (TD->HwTD.Token.PIDCode != 2) + { + EhciTransfer->TransferLen += LengthTransfered; + } + + if (USBDStatus != USBD_STATUS_SUCCESS) + { + EhciTransfer->USBDStatus = USBDStatus; + goto Next; + } + +Next: + + TD->HwTD.NextTD = 0; + TD->HwTD.AlternateNextTD = 0; + + TD->TdFlags = 0; + TD->EhciTransfer = NULL; + + ++EhciEndpoint->RemainTDs; + + if (EhciTransfer->PendingTDs == 0) + { + --EhciEndpoint->PendingTDs; + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + TransferType == USBPORT_TRANSFER_TYPE_BULK) + { + --EhciExtension->PendingTransfers; + + if (EhciExtension->PendingTransfers == 0) + { + OperationalRegs = EhciExtension->OperationalRegs; + Command.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBCMD); + + if (!Command.InterruptAdvanceDoorbell && + (EhciExtension->Flags & 20)) + { + EHCI_DisableAsyncList(EhciExtension); + } + } + } + + RegPacket.UsbPortCompleteTransfer(EhciExtension, + EhciEndpoint, + TransferParameters, + EhciTransfer->USBDStatus, + EhciTransfer->TransferLen); + } +} + +VOID +NTAPI +EHCI_PollActiveAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_HCD_QH QH; + PEHCI_HCD_TD TD; + PEHCI_HCD_TD CurrentTD; + ULONG CurrentTDPhys; + BOOLEAN IsSheduled; + + DPRINT_EHCI("EHCI_PollActiveAsyncEndpoint: ... \n"); + + QH = EhciEndpoint->QH; + + CurrentTDPhys = QH->sqh.HwQH.CurrentTD & ~0x1F; + ASSERT(CurrentTDPhys != 0); + + CurrentTD = (PEHCI_HCD_TD)RegPacket.UsbPortGetMappedVirtualAddress((PVOID)CurrentTDPhys, + EhciExtension, + EhciEndpoint); + + if (CurrentTD == EhciEndpoint->DummyTdVA) + { + return; + } + + IsSheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE; + + if (!EHCI_HardwarePresent(EhciExtension, 0)) + { + IsSheduled = 0; + } + + TD = EhciEndpoint->HcdHeadP; + + if (TD == CurrentTD) + { + if (TD == EhciEndpoint->HcdTailP || + TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) + { + goto Next; + } + + if (TD->NextHcdTD && + TD->HwTD.NextTD != (ULONG_PTR)TD->NextHcdTD->PhysicalAddress) + { + TD->HwTD.NextTD = (ULONG_PTR)TD->NextHcdTD->PhysicalAddress; + } + + if (TD->AltNextHcdTD && + TD->HwTD.AlternateNextTD != (ULONG_PTR)TD->AltNextHcdTD->PhysicalAddress) + { + TD->HwTD.AlternateNextTD = (ULONG_PTR)TD->AltNextHcdTD->PhysicalAddress; + } + + if (QH->sqh.HwQH.CurrentTD == (ULONG_PTR)TD->PhysicalAddress && + !(TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) && + (QH->sqh.HwQH.NextTD != TD->HwTD.NextTD || + QH->sqh.HwQH.AlternateNextTD != TD->HwTD.AlternateNextTD)) + { + QH->sqh.HwQH.NextTD = TD->HwTD.NextTD; + QH->sqh.HwQH.AlternateNextTD = TD->HwTD.AlternateNextTD; + } + + EHCI_InterruptNextSOF((PVOID)EhciExtension); + } + else + { + do + { + ASSERT((TD->TdFlags & EHCI_HCD_TD_FLAG_DUMMY) == 0); + + TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE; + + if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) + { + TD->TdFlags |= 0x10; + } + + InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink); + TD = TD->NextHcdTD; + } + while (TD != CurrentTD); + } + +Next: + + if (CurrentTD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) + { + ASSERT(TD != NULL); + EhciEndpoint->HcdHeadP = TD; + return; + } + + if ((CurrentTD->NextHcdTD != EhciEndpoint->HcdTailP) && + (CurrentTD->AltNextHcdTD != EhciEndpoint->HcdTailP || + CurrentTD->HwTD.Token.TransferBytes == 0)) + { + ASSERT(TD != NULL); + EhciEndpoint->HcdHeadP = TD; + return; + } + + if (IsSheduled) + { + EHCI_LockQH(EhciExtension, + QH, + EhciEndpoint->EndpointProperties.TransferType); + } + + QH->sqh.HwQH.CurrentTD = (ULONG_PTR)EhciEndpoint->DummyTdPA; + + CurrentTD->TdFlags |= EHCI_HCD_TD_FLAG_DONE; + InsertTailList(&EhciEndpoint->ListTDs, &CurrentTD->DoneLink); + + if (CurrentTD->HwTD.Token.TransferBytes && + CurrentTD->AltNextHcdTD == EhciEndpoint->HcdTailP) + { + TD = CurrentTD->NextHcdTD; + + if (TD != EhciEndpoint->HcdTailP) + { + do + { + TD->TdFlags |= 0x10; + InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink); + TD = TD->NextHcdTD; + } + while (TD != EhciEndpoint->HcdTailP); + } + } + + QH->sqh.HwQH.CurrentTD = (ULONG_PTR)EhciEndpoint->HcdTailP->PhysicalAddress; + QH->sqh.HwQH.NextTD = 1; + QH->sqh.HwQH.AlternateNextTD = 1; + QH->sqh.HwQH.Token.TransferBytes = 0; + + EhciEndpoint->HcdHeadP = EhciEndpoint->HcdTailP; + + if (IsSheduled) + { + EHCI_UnlockQH(EhciExtension, QH); + } +} + +VOID +NTAPI +EHCI_PollHaltedAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_HCD_QH QH; + PEHCI_HCD_TD CurrentTD; + ULONG CurrentTdPA; + PEHCI_HCD_TD TD; + PEHCI_TRANSFER Transfer; + BOOLEAN IsSheduled; + + DPRINT("EHCI_PollHaltedAsyncEndpoint: EhciEndpoint - %p\n", EhciEndpoint); + + QH = EhciEndpoint->QH; + EHCI_DumpHwQH(QH); + + CurrentTdPA = QH->sqh.HwQH.CurrentTD & ~0x1F; + ASSERT(CurrentTdPA != 0); + + IsSheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE; + + if (!EHCI_HardwarePresent(EhciExtension, 0)) + { + IsSheduled = 0; + } + + CurrentTD = (PEHCI_HCD_TD)RegPacket.UsbPortGetMappedVirtualAddress((PVOID)CurrentTdPA, + EhciExtension, + EhciEndpoint); + + DPRINT("EHCI_PollHaltedAsyncEndpoint: CurrentTD - %p\n", CurrentTD); + + if (CurrentTD == EhciEndpoint->DummyTdVA) + { + return; + } + + ASSERT(EhciEndpoint->HcdTailP != CurrentTD); + + if (IsSheduled) + { + EHCI_LockQH(EhciExtension, + QH, + EhciEndpoint->EndpointProperties.TransferType); + } + + TD = EhciEndpoint->HcdHeadP; + + if (TD != CurrentTD) + { + do + { + DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD); + + ASSERT((TD->TdFlags & EHCI_HCD_TD_FLAG_DUMMY) == 0); + + if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) + { + TD->TdFlags |= 0x10; + } + + TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE; + + InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink); + + TD = TD->NextHcdTD; + } + while (TD != CurrentTD); + } + + TD = CurrentTD; + + Transfer = CurrentTD->EhciTransfer; + + do + { + DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD); + + if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) + { + TD->TdFlags |= 0x10; + } + + TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE; + + InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink); + + TD = TD->NextHcdTD; + } + while (TD->EhciTransfer == Transfer); + + EhciEndpoint->HcdHeadP = TD; + + QH->sqh.HwQH.CurrentTD = (ULONG)EhciEndpoint->DummyTdVA; + QH->sqh.HwQH.NextTD = (ULONG)TD->PhysicalAddress; + QH->sqh.HwQH.AlternateNextTD = 1; + QH->sqh.HwQH.Token.TransferBytes = 0; + + if (IsSheduled) + { + EHCI_UnlockQH(EhciExtension, QH); + } + + if (EhciEndpoint->EndpointStatus & 4) + { + EhciEndpoint->EndpointStatus &= ~1; + QH->sqh.HwQH.Token.ErrorCounter = 0; + QH->sqh.HwQH.Token.Status &= (UCHAR)~(EHCI_TOKEN_STATUS_ACTIVE | + EHCI_TOKEN_STATUS_HALTED); + + } +} + +VOID +NTAPI +EHCI_PollAsyncEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_HCD_QH QH; + PLIST_ENTRY DoneList; + PEHCI_HCD_TD TD; + + //DPRINT_EHCI("EHCI_PollAsyncEndpoint: EhciEndpoint - %p\n", EhciEndpoint); + + if (!EhciEndpoint->PendingTDs) + { + return; + } + + QH = EhciEndpoint->QH; + + if (QH->sqh.QhFlags & 2) + { + return; + } + + if (QH->sqh.HwQH.Token.Status & EHCI_TOKEN_STATUS_ACTIVE || + !(QH->sqh.HwQH.Token.Status & EHCI_TOKEN_STATUS_HALTED)) + { + EHCI_PollActiveAsyncEndpoint(EhciExtension, EhciEndpoint); + } + else + { + EhciEndpoint->EndpointStatus |= 1; + EHCI_PollHaltedAsyncEndpoint(EhciExtension, EhciEndpoint); + } + + DoneList = &EhciEndpoint->ListTDs; + + while (!IsListEmpty(DoneList)) + { + TD = CONTAINING_RECORD(DoneList->Flink, + EHCI_HCD_TD, + DoneLink); + + RemoveHeadList(DoneList); + + ASSERT((TD->TdFlags & (EHCI_HCD_TD_FLAG_PROCESSED | + EHCI_HCD_TD_FLAG_DONE)) != 0); + + EHCI_ProcessDoneAsyncTd(EhciExtension, TD); + } +} + +VOID +NTAPI +EHCI_PollIsoEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_PollIsoEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_PollEndpoint(IN PVOID ehciExtension, + IN PVOID ehciEndpoint) +{ + PEHCI_EXTENSION EhciExtension; + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + + //DPRINT_EHCI("EHCI_PollEndpoint: EhciEndpoint - %p\n", EhciEndpoint); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + EHCI_PollIsoEndpoint(EhciExtension, EhciEndpoint); + } + else + { + EHCI_PollAsyncEndpoint(EhciExtension, EhciEndpoint); + } +} + +VOID +NTAPI +EHCI_CheckController(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + //DPRINT_EHCI("EHCI_CheckController: ... \n"); + + if (EhciExtension->IsStarted) + { + EHCI_HardwarePresent(EhciExtension, TRUE); + } +} + +ULONG +NTAPI +EHCI_Get32BitFrameNumber(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + ULONG FrameIdx; + ULONG FrameIndex; + ULONG FrameNumber; + + //DPRINT_EHCI("EHCI_Get32BitFrameNumber: EhciExtension - %p\n", EhciExtension); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + FrameIdx = EhciExtension->FrameIndex; + FrameIndex = READ_REGISTER_ULONG(EhciExtension->OperationalRegs + EHCI_FRINDEX); + + FrameNumber = (((USHORT)FrameIdx ^ ((FrameIndex >> 3) & 0x7FF)) & 0x400) + + (FrameIndex | ((FrameIndex >> 3) & 0x3FF)); + + return FrameNumber; +} + +VOID +NTAPI +EHCI_EnableInterrupts(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + DPRINT("EHCI_EnableInterrupts: EhciExtension->InterruptMask - %x\n", + EhciExtension->InterruptMask.AsULONG); + + WRITE_REGISTER_ULONG(EhciExtension->OperationalRegs + EHCI_USBINTR, + EhciExtension->InterruptMask.AsULONG); +} + +VOID +NTAPI +EHCI_DisableInterrupts(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = (PEHCI_EXTENSION)ehciExtension; + + DPRINT("EHCI_DisableInterrupts: UNIMPLEMENTED. FIXME\n"); + + WRITE_REGISTER_ULONG(EhciExtension->OperationalRegs + EHCI_USBINTR, + 0); +} + +VOID +NTAPI +EHCI_PollController(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG OperationalRegs; + ULONG Port; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_EHCI("EHCI_PollController: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + OperationalRegs = EhciExtension->OperationalRegs; + + if (!(EhciExtension->Flags & 1)) + { + RegPacket.UsbPortInvalidateRootHub(EhciExtension); + return; + } + + if (EhciExtension->NumberOfPorts) + { + for (Port = 0; Port < EhciExtension->NumberOfPorts; ++Port) + { + PortSC.AsULONG = READ_REGISTER_ULONG((OperationalRegs + EHCI_PORTSC) + Port); + + if (PortSC.ConnectStatusChange) + { + RegPacket.UsbPortInvalidateRootHub(EhciExtension); + } + } + } +} + +VOID +NTAPI +EHCI_SetEndpointDataToggle(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN ULONG DataToggle) +{ + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + + DPRINT_EHCI("EHCI_SetEndpointDataToggle: EhciEndpoint - %p, DataToggle - %x\n", + EhciEndpoint, + DataToggle); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + EhciEndpoint->QH->sqh.HwQH.Token.DataToggle = DataToggle; + } +} + +ULONG +NTAPI +EHCI_GetEndpointStatus(IN PVOID ehciExtension, + IN PVOID ehciEndpoint) +{ + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + ULONG Status = 0; + + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + + DPRINT_EHCI("EHCI_GetEndpointStatus: EhciEndpoint - %p\n", EhciEndpoint); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + return Status; + } + + if (EhciEndpoint->EndpointStatus & 1) + { + Status = 1; + } + + return Status; +} + +VOID +NTAPI +EHCI_SetEndpointStatus(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN ULONG EndpointStatus) +{ + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + PEHCI_HCD_QH QH; + + EhciEndpoint = (PEHCI_ENDPOINT)ehciEndpoint; + + DPRINT("EHCI_SetEndpointStatus: EhciEndpoint - %p, EndpointStatus - %x\n", + EhciEndpoint, + EndpointStatus); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType != USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + + if (EndpointStatus == 0) + { + EhciEndpoint->EndpointStatus &= ~1; + + QH = EhciEndpoint->QH; + QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_HALTED; + + return; + } + + if (EndpointStatus == 1) + { + DbgBreakPoint(); + } + } +} + +VOID +NTAPI +EHCI_ResetController(IN PVOID ehciExtension) +{ + DPRINT1("EHCI_ResetController: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +EHCI_StartSendOnePacket(IN PVOID ehciExtension, + IN PVOID PacketParameters, + IN PVOID Data, + IN PULONG pDataLength, + IN PVOID BufferVA, + IN PVOID BufferPA, + IN ULONG BufferLength, + IN USBD_STATUS * pUSBDStatus) +{ + DPRINT1("EHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +EHCI_EndSendOnePacket(IN PVOID ehciExtension, + IN PVOID PacketParameters, + IN PVOID Data, + IN PULONG pDataLength, + IN PVOID BufferVA, + IN PVOID BufferPA, + IN ULONG BufferLength, + IN USBD_STATUS * pUSBDStatus) +{ + DPRINT1("EHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +EHCI_PassThru(IN PVOID ehciExtension, + IN PVOID passThruParameters, + IN ULONG ParameterLength, + IN PVOID pParameters) +{ + DPRINT1("EHCI_PassThru: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +EHCI_RebalanceEndpoint(IN PVOID ohciExtension, + IN PVOID endpointParameters, + IN PVOID ohciEndpoint) +{ + DPRINT1("EHCI_RebalanceEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_FlushInterrupts(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension; + PULONG OperationalRegs; + EHCI_USB_STATUS Status; + + DPRINT("EHCI_FlushInterrupts: ... \n"); + + EhciExtension = (PEHCI_EXTENSION)ehciExtension; + OperationalRegs = EhciExtension->OperationalRegs; + + Status.AsULONG = READ_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS); + WRITE_REGISTER_ULONG(OperationalRegs + EHCI_USBSTS, Status.AsULONG); +} + +MPSTATUS +NTAPI +EHCI_RH_ChirpRootPort(IN PVOID ehciExtension, + IN USHORT Port) +{ + DPRINT1("EHCI_RH_ChirpRootPort: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +EHCI_TakePortControl(IN PVOID ohciExtension) +{ + DPRINT1("EHCI_TakePortControl: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_Unload() +{ + DPRINT1("EHCI_Unload: UNIMPLEMENTED. FIXME\n"); +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + DPRINT("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n", + DriverObject, + RegistryPath); + + if (USBPORT_GetHciMn() != 0x10000001) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET)); + + RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_EHCI; + + RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT | + USB_MINIPORT_FLAGS_MEMORY_IO | + USB_MINIPORT_FLAGS_USB2 | + USB_MINIPORT_FLAGS_POLLING | + USB_MINIPORT_FLAGS_WAKE_SUPPORT; + + RegPacket.MiniPortBusBandwidth = 400000; + + RegPacket.MiniPortExtensionSize = sizeof(EHCI_EXTENSION); + RegPacket.MiniPortEndpointSize = sizeof(EHCI_ENDPOINT); + RegPacket.MiniPortTransferSize = sizeof(EHCI_TRANSFER); + RegPacket.MiniPortResourcesSize = sizeof(EHCI_HC_RESOURCES); + + RegPacket.OpenEndpoint = EHCI_OpenEndpoint; + RegPacket.ReopenEndpoint = EHCI_ReopenEndpoint; + RegPacket.QueryEndpointRequirements = EHCI_QueryEndpointRequirements; + RegPacket.CloseEndpoint = EHCI_CloseEndpoint; + RegPacket.StartController = EHCI_StartController; + RegPacket.StopController = EHCI_StopController; + RegPacket.SuspendController = EHCI_SuspendController; + RegPacket.ResumeController = EHCI_ResumeController; + RegPacket.InterruptService = EHCI_InterruptService; + RegPacket.InterruptDpc = EHCI_InterruptDpc; + RegPacket.SubmitTransfer = EHCI_SubmitTransfer; + RegPacket.SubmitIsoTransfer = EHCI_SubmitIsoTransfer; + RegPacket.AbortTransfer = EHCI_AbortTransfer; + RegPacket.GetEndpointState = EHCI_GetEndpointState; + RegPacket.SetEndpointState = EHCI_SetEndpointState; + RegPacket.PollEndpoint = EHCI_PollEndpoint; + RegPacket.CheckController = EHCI_CheckController; + RegPacket.Get32BitFrameNumber = EHCI_Get32BitFrameNumber; + RegPacket.InterruptNextSOF = EHCI_InterruptNextSOF; + RegPacket.EnableInterrupts = EHCI_EnableInterrupts; + RegPacket.DisableInterrupts = EHCI_DisableInterrupts; + RegPacket.PollController = EHCI_PollController; + RegPacket.SetEndpointDataToggle = EHCI_SetEndpointDataToggle; + RegPacket.GetEndpointStatus = EHCI_GetEndpointStatus; + RegPacket.SetEndpointStatus = EHCI_SetEndpointStatus; + RegPacket.RH_GetRootHubData = EHCI_RH_GetRootHubData; + RegPacket.RH_GetStatus = EHCI_RH_GetStatus; + RegPacket.RH_GetPortStatus = EHCI_RH_GetPortStatus; + RegPacket.RH_GetHubStatus = EHCI_RH_GetHubStatus; + RegPacket.RH_SetFeaturePortReset = EHCI_RH_SetFeaturePortReset; + RegPacket.RH_SetFeaturePortPower = EHCI_RH_SetFeaturePortPower; + RegPacket.RH_SetFeaturePortEnable = EHCI_RH_SetFeaturePortEnable; + RegPacket.RH_SetFeaturePortSuspend = EHCI_RH_SetFeaturePortSuspend; + RegPacket.RH_ClearFeaturePortEnable = EHCI_RH_ClearFeaturePortEnable; + RegPacket.RH_ClearFeaturePortPower = EHCI_RH_ClearFeaturePortPower; + RegPacket.RH_ClearFeaturePortSuspend = EHCI_RH_ClearFeaturePortSuspend; + RegPacket.RH_ClearFeaturePortEnableChange = EHCI_RH_ClearFeaturePortEnableChange; + RegPacket.RH_ClearFeaturePortConnectChange = EHCI_RH_ClearFeaturePortConnectChange; + RegPacket.RH_ClearFeaturePortResetChange = EHCI_RH_ClearFeaturePortResetChange; + RegPacket.RH_ClearFeaturePortSuspendChange = EHCI_RH_ClearFeaturePortSuspendChange; + RegPacket.RH_ClearFeaturePortOvercurrentChange = EHCI_RH_ClearFeaturePortOvercurrentChange; + RegPacket.RH_DisableIrq = EHCI_RH_DisableIrq; + RegPacket.RH_EnableIrq = EHCI_RH_EnableIrq; + RegPacket.StartSendOnePacket = EHCI_StartSendOnePacket; + RegPacket.EndSendOnePacket = EHCI_EndSendOnePacket; + RegPacket.PassThru = EHCI_PassThru; + RegPacket.RebalanceEndpoint = EHCI_RebalanceEndpoint; + RegPacket.FlushInterrupts = EHCI_FlushInterrupts; + RegPacket.RH_ChirpRootPort = EHCI_RH_ChirpRootPort; + RegPacket.TakePortControl = EHCI_TakePortControl; + + DriverObject->DriverUnload = (PDRIVER_UNLOAD)EHCI_Unload; + + return USBPORT_RegisterUSBPortDriver(DriverObject, 200, &RegPacket); +} diff --git a/reactos/drivers/usb/usbehci_new/usbehci.h b/reactos/drivers/usb/usbehci_new/usbehci.h new file mode 100644 index 00000000000..6ad6e39a8b2 --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/usbehci.h @@ -0,0 +1,303 @@ +#ifndef USBEHCI_H__ +#define USBEHCI_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "..\usbmport.h" +#include "hardware.h" + +extern USBPORT_REGISTRATION_PACKET RegPacket; + +#define EHCI_HCD_TD_FLAG_ALLOCATED 0x01 +#define EHCI_HCD_TD_FLAG_PROCESSED 0x02 +#define EHCI_HCD_TD_FLAG_DONE 0x08 +#define EHCI_HCD_TD_FLAG_DUMMY 0x20 + +typedef union _USB20_PORT_STATUS { + struct { + ULONG ConnectStatus : 1; // Current Connect Status + ULONG EnableStatus : 1; // Port Enabled/Disabled + ULONG SuspendStatus : 1; + ULONG OverCurrent : 1; + ULONG ResetStatus : 1; + ULONG Reserved1 : 3; + ULONG PowerStatus : 1; + ULONG LsDeviceAttached : 1; // Low-Speed Device Attached + ULONG HsDeviceAttached : 1; // High-speed Device Attached + ULONG TestMode : 1; // Port Test Mode + ULONG IndicatorControl : 1; // Port Indicator Control + ULONG Reserved2 : 3; + ULONG ConnectStatusChange : 1; + ULONG EnableStatusChange : 1; + ULONG SuspendStatusChange : 1; + ULONG OverCurrentChange : 1; + ULONG ResetStatusChange : 1; + ULONG Reserved3 : 3; + ULONG PowerStatusChange : 1; + ULONG LsDeviceAttachedChange : 1; + ULONG HsDeviceAttachedChange : 1; + ULONG TestModeChange : 1; + ULONG IndicatorControlChange : 1; + ULONG Reserved4 : 3; + }; + ULONG AsULONG; +} USB20_PORT_STATUS; + +struct _EHCI_HCD_QH; +struct _EHCI_ENDPOINT; +struct _EHCI_TRANSFER; + +typedef struct _EHCI_HCD_TD { + //Hardware + EHCI_QUEUE_TD HwTD; + //Software + struct _EHCI_HCD_TD * PhysicalAddress; + ULONG TdFlags; + struct _EHCI_ENDPOINT * EhciEndpoint; + struct _EHCI_TRANSFER * EhciTransfer; + struct _EHCI_HCD_TD * NextHcdTD; + struct _EHCI_HCD_TD * AltNextHcdTD; + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + ULONG LengthThisTD; + LIST_ENTRY DoneLink; + ULONG Pad[40]; +} EHCI_HCD_TD, *PEHCI_HCD_TD; + +C_ASSERT(sizeof(EHCI_HCD_TD) == 0x100); + +typedef struct _EHCI_STATIC_QH { + //Hardware + EHCI_QUEUE_HEAD HwQH; + //Software + ULONG QhFlags; + struct _EHCI_HCD_QH * PhysicalAddress; + struct _EHCI_HCD_QH * PrevHead; + struct _EHCI_HCD_QH * NextHead; + struct _EHCI_STATIC_QH * StaticQH; + ULONG Pad[18]; +} EHCI_STATIC_QH, *PEHCI_STATIC_QH; + +C_ASSERT(sizeof(EHCI_STATIC_QH) == 0xA0); + +typedef struct _EHCI_HCD_QH { + struct _EHCI_STATIC_QH sqh; + ULONG Pad[24]; +} EHCI_HCD_QH, *PEHCI_HCD_QH; + +C_ASSERT(sizeof(EHCI_HCD_QH) == 0x100); + +typedef struct _EHCI_ENDPOINT { + ULONG Reserved; + ULONG EndpointStatus; + ULONG EndpointState; + USBPORT_ENDPOINT_PROPERTIES EndpointProperties; + PEHCI_HCD_TD DummyTdVA; // DmaBufferVA + PEHCI_HCD_TD DummyTdPA; // DmaBufferPA + PEHCI_HCD_TD FirstTD; + ULONG MaxTDs; + ULONG PendingTDs; + ULONG RemainTDs; + PEHCI_HCD_QH QH; + PEHCI_HCD_TD HcdHeadP; + PEHCI_HCD_TD HcdTailP; + LIST_ENTRY ListTDs; +} EHCI_ENDPOINT, *PEHCI_ENDPOINT; + +typedef struct _EHCI_TRANSFER { + ULONG Reserved; + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + ULONG USBDStatus; + ULONG TransferLen; + PEHCI_ENDPOINT EhciEndpoint; + ULONG PendingTDs; + ULONG TransferOnAsyncList; +} EHCI_TRANSFER, *PEHCI_TRANSFER; + +typedef struct _EHCI_HC_RESOURCES { + PEHCI_STATIC_QH PeriodicFrameList[1024]; // 4K-page aligned array + EHCI_STATIC_QH AsyncHead; + EHCI_STATIC_QH PeriodicHead[64]; + UCHAR Padded[0x160]; + EHCI_HCD_QH DummyQH[1024]; +} EHCI_HC_RESOURCES, *PEHCI_HC_RESOURCES; + +typedef struct _EHCI_EXTENSION { + ULONG Reserved; + ULONG Flags; + PULONG BaseIoAdress; + PULONG OperationalRegs; + UCHAR FrameLengthAdjustment; + BOOLEAN IsStarted; + USHORT HcSystemErrors; + ULONG PortRoutingControl; + USHORT NumberOfPorts; // HCSPARAMS => N_PORTS + USHORT PortPowerControl; // HCSPARAMS => Port Power Control (PPC) + EHCI_INTERRUPT_ENABLE InterruptMask; + EHCI_INTERRUPT_ENABLE InterruptStatus; + /* Shedule */ + PEHCI_HC_RESOURCES HcResourcesVA; + PEHCI_HC_RESOURCES HcResourcesPA; + PEHCI_STATIC_QH AsyncHead; + PEHCI_STATIC_QH PeriodicHead[64]; + ULONG_PTR DummyQHListVA; + ULONG_PTR DummyQHListPA; + ULONG FrameIndex; + ULONG FrameHighPart; + /* Root Hub Bits */ + ULONG ConnectPortBits; + ULONG SuspendPortBits; + ULONG ResetPortBits; + ULONG FinishResetPortBits; + /* Transfers */ + ULONG PendingTransfers; + /* Lock Queue */ + PEHCI_HCD_QH PrevQH; + PEHCI_HCD_QH LockQH; + PEHCI_HCD_QH NextQH; + /* Registers Copy Bakup */ + ULONG BakupPeriodiclistbase; // PERIODICLISTBASE + ULONG BakupAsynclistaddr; // ASYNCLISTADDR + ULONG BakupCtrlDSSegment; // CTRLDSSEGMENT + ULONG BakupUSBCmd; // USBCMD +} EHCI_EXTENSION, *PEHCI_EXTENSION; + +/* debug.c */ + +VOID +NTAPI +EHCI_DumpHwTD( + IN PEHCI_HCD_TD TD); + +VOID +NTAPI +EHCI_DumpHwQH( + IN PEHCI_HCD_QH QH); + +/* roothub.c */ + +VOID +NTAPI +EHCI_RH_GetRootHubData( + IN PVOID ohciExtension, + IN PVOID rootHubData); + +MPSTATUS +NTAPI +EHCI_RH_GetStatus( + IN PVOID ohciExtension, + IN PUSHORT Status); + +MPSTATUS +NTAPI +EHCI_RH_GetPortStatus( + IN PVOID ohciExtension, + IN USHORT Port, + IN PULONG PortStatus); + +MPSTATUS +NTAPI +EHCI_RH_GetHubStatus( + IN PVOID ohciExtension, + IN PULONG HubStatus); + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortReset( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortPower( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortEnable( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortSuspend( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortEnable( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortPower( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortSuspend( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortEnableChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortConnectChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortResetChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortSuspendChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortOvercurrentChange( + IN PVOID ohciExtension, + IN USHORT Port); + +VOID +NTAPI +EHCI_RH_DisableIrq( + IN PVOID ohciExtension); + +VOID +NTAPI +EHCI_RH_EnableIrq( + IN PVOID ohciExtension); + +/* usbehci.c */ + +NTSTATUS +NTAPI +USBPORT_GetHciMn(); + +NTSTATUS +NTAPI +USBPORT_RegisterUSBPortDriver( + IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PVOID RegistrationPacket); + +#endif /* USBEHCI_H__ */ diff --git a/reactos/drivers/usb/usbehci_new/usbehci.rc b/reactos/drivers/usb/usbehci_new/usbehci.rc new file mode 100644 index 00000000000..8a54ddc41be --- /dev/null +++ b/reactos/drivers/usb/usbehci_new/usbehci.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB EHCI miniport driver" +#define REACTOS_STR_INTERNAL_NAME "usbehci" +#define REACTOS_STR_ORIGINAL_FILENAME "usbehci.sys" +#include diff --git a/reactos/drivers/usb/usbhub/fdo.c b/reactos/drivers/usb/usbhub/fdo.c index 13b2081a63e..ec8857903d0 100644 --- a/reactos/drivers/usb/usbhub/fdo.c +++ b/reactos/drivers/usb/usbhub/fdo.c @@ -12,7 +12,7 @@ #include -#define NDEBUG +//#define NDEBUG #include NTSTATUS @@ -1611,6 +1611,10 @@ USBHUB_FdoStartDevice( IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO, &HubDeviceExtension->RootHubPhysicalDeviceObject, &HubDeviceExtension->RootHubFunctionalDeviceObject); + + DPRINT("USBHUB_FdoStartDevice: SubmitRequestToRootHub(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO) Status - %x\n", + Status); + if (!NT_SUCCESS(Status)) { // failed to obtain hub pdo @@ -1639,6 +1643,10 @@ USBHUB_FdoStartDevice( Status = SubmitRequestToRootHub(RootHubDeviceObject, IOCTL_INTERNAL_USB_GET_HUB_COUNT, &HubDeviceExtension->NumberOfHubs, NULL); + + DPRINT("USBHUB_FdoStartDevice: SubmitRequestToRootHub(IOCTL_INTERNAL_USB_GET_HUB_COUNT) Status - %x\n", + Status); + if (!NT_SUCCESS(Status)) { // failed to get number of hubs @@ -1653,6 +1661,9 @@ USBHUB_FdoStartDevice( USB_BUSIF_HUB_VERSION_5, (PVOID)&HubDeviceExtension->HubInterface); + DPRINT("USBHUB_FdoStartDevice: QueryInterface(USB_BUS_INTERFACE_HUB_GUID) Status - %x\n", + Status); + if (!NT_SUCCESS(Status)) { // failed to get root hub interface @@ -1669,6 +1680,9 @@ USBHUB_FdoStartDevice( USB_BUSIF_USBDI_VERSION_2, (PVOID)&HubDeviceExtension->UsbDInterface); + DPRINT("USBHUB_FdoStartDevice: QueryInterface(USB_BUS_INTERFACE_USBDI_GUID) Status - %x\n", + Status); + if (!NT_SUCCESS(Status)) { // failed to get usbdi interface @@ -1682,6 +1696,9 @@ USBHUB_FdoStartDevice( &HubDeviceExtension->RootHubHandle, NULL); + DPRINT("USBHUB_FdoStartDevice: SubmitRequestToRootHub(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE) Status - %x\n", + Status); + if (!NT_SUCCESS(Status)) { // failed diff --git a/reactos/drivers/usb/usbhub_new/CMakeLists.txt b/reactos/drivers/usb/usbhub_new/CMakeLists.txt new file mode 100644 index 00000000000..a1355dfa500 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_definitions(-DDEBUG_MODE) +include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include) + +list(APPEND SOURCE + debug.c + ioctl.c + pnp.c + power.c + usbhub.c + usbhub.h) + +add_library(usbhub SHARED + ${SOURCE} + guid.c + usbhub.rc) + +target_link_libraries(usbhub ${PSEH_LIB}) +set_module_type(usbhub kernelmodedriver) +add_importlibs(usbhub ntoskrnl hal wmilib usbd) +add_pch(usbhub usbhub.h SOURCE) +add_cd_file(TARGET usbhub DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/usb/usbhub_new/dbg_uhub.h b/reactos/drivers/usb/usbhub_new/dbg_uhub.h new file mode 100644 index 00000000000..8c91c0111b8 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/dbg_uhub.h @@ -0,0 +1,5 @@ +#ifndef DBG_UHUB_H__ +#define DBG_UHUB_H__ + + +#endif /* DBG_UHUB_H__ */ diff --git a/reactos/drivers/usb/usbhub_new/debug.c b/reactos/drivers/usb/usbhub_new/debug.c new file mode 100644 index 00000000000..bfe4b467145 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/debug.c @@ -0,0 +1,135 @@ +#include "usbhub.h" + +//#define NDEBUG +#include + +VOID +NTAPI +USBPORT_DumpingDeviceDescriptor(IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) +{ + if (!DeviceDescriptor) + { + return; + } + + DPRINT("Dumping Device Descriptor - %p\n", DeviceDescriptor); + DPRINT("bLength - %x\n", DeviceDescriptor->bLength); + DPRINT("bDescriptorType - %x\n", DeviceDescriptor->bDescriptorType); + DPRINT("bcdUSB - %x\n", DeviceDescriptor->bcdUSB); + DPRINT("bDeviceClass - %x\n", DeviceDescriptor->bDeviceClass); + DPRINT("bDeviceSubClass - %x\n", DeviceDescriptor->bDeviceSubClass); + DPRINT("bDeviceProtocol - %x\n", DeviceDescriptor->bDeviceProtocol); + DPRINT("bMaxPacketSize0 - %x\n", DeviceDescriptor->bMaxPacketSize0); + DPRINT("idVendor - %x\n", DeviceDescriptor->idVendor); + DPRINT("idProduct - %x\n", DeviceDescriptor->idProduct); + DPRINT("bcdDevice - %x\n", DeviceDescriptor->bcdDevice); + DPRINT("iManufacturer - %x\n", DeviceDescriptor->iManufacturer); + DPRINT("iProduct - %x\n", DeviceDescriptor->iProduct); + DPRINT("iSerialNumber - %x\n", DeviceDescriptor->iSerialNumber); + DPRINT("bNumConfigurations - %x\n", DeviceDescriptor->bNumConfigurations); +} + +VOID +NTAPI +USBPORT_DumpingConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor) +{ + PUSB_COMMON_DESCRIPTOR Descriptor; + PUSB_CONFIGURATION_DESCRIPTOR cDescriptor; + PUSB_INTERFACE_DESCRIPTOR iDescriptor; + PUSB_ENDPOINT_DESCRIPTOR eDescriptor; + + if (!ConfigDescriptor) + { + return; + } + + Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigDescriptor; + + do + { + if (((ULONG)Descriptor) >= ((ULONG)ConfigDescriptor + + ConfigDescriptor->wTotalLength)) + { + break; + } + + if (Descriptor->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE) + { + cDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Descriptor; + + DPRINT("Dumping cDescriptor - %p\n", cDescriptor); + DPRINT("bLength - %x\n", cDescriptor->bLength); + DPRINT("bDescriptorType - %x\n", cDescriptor->bDescriptorType); + DPRINT("wTotalLength - %x\n", cDescriptor->wTotalLength); + DPRINT("bNumInterfaces - %x\n", cDescriptor->bNumInterfaces); + DPRINT("bConfigurationValue - %x\n", cDescriptor->bConfigurationValue); + DPRINT("iConfiguration - %x\n", cDescriptor->iConfiguration); + DPRINT("bmAttributes - %x\n", cDescriptor->bmAttributes); + DPRINT("MaxPower - %x\n", cDescriptor->MaxPower); + } + else if (Descriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) + { + iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor; + + DPRINT("Dumping iDescriptor - %p\n", iDescriptor); + DPRINT("bLength - %x\n", iDescriptor->bLength); + DPRINT("bDescriptorType - %x\n", iDescriptor->bDescriptorType); + DPRINT("bInterfaceNumber - %x\n", iDescriptor->bInterfaceNumber); + DPRINT("bAlternateSetting - %x\n", iDescriptor->bAlternateSetting); + DPRINT("bNumEndpoints - %x\n", iDescriptor->bNumEndpoints); + DPRINT("bInterfaceClass - %x\n", iDescriptor->bInterfaceClass); + DPRINT("bInterfaceSubClass - %x\n", iDescriptor->bInterfaceSubClass); + DPRINT("bInterfaceProtocol - %x\n", iDescriptor->bInterfaceProtocol); + DPRINT("iInterface - %x\n", iDescriptor->iInterface); + } + else if (Descriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) + { + eDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Descriptor; + + DPRINT("Dumping Descriptor - %p\n", eDescriptor); + DPRINT("bLength - %x\n", eDescriptor->bLength); + DPRINT("bDescriptorType - %x\n", eDescriptor->bDescriptorType); + DPRINT("bEndpointAddress - %x\n", eDescriptor->bEndpointAddress); + DPRINT("bmAttributes - %x\n", eDescriptor->bmAttributes); + DPRINT("wMaxPacketSize - %x\n", eDescriptor->wMaxPacketSize); + DPRINT("bInterval - %x\n", eDescriptor->bInterval); + } + else + { + DPRINT("bDescriptorType - %x\n", Descriptor->bDescriptorType); + } + + if (!Descriptor->bLength) + { + break; + } + + Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG)Descriptor + + Descriptor->bLength); + + } while (TRUE); +} + +VOID +NTAPI +USBPORT_DumpingIDs(IN PVOID Id) +{ + PWSTR Ptr; + ULONG Length; + ULONG TotalLength = 0; + + Ptr = (PWSTR)Id; + DPRINT("USBPORT_DumpingIDs:\n"); + + 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/usbhub_new/guid.c b/reactos/drivers/usb/usbhub_new/guid.c new file mode 100644 index 00000000000..50a60369ff3 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/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/usbhub_new/ioctl.c b/reactos/drivers/usb/usbhub_new/ioctl.c new file mode 100644 index 00000000000..11ee81b5dd5 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/ioctl.c @@ -0,0 +1,1448 @@ +#include "usbhub.h" + +//#define NDEBUG +#include + +NTSTATUS +NTAPI +USBH_SelectConfigOrInterfaceComplete(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSBHUB_FDO_EXTENSION HubExtension; + PVOID TimeoutContext; // PUSBHUB_BANDWIDTH_TIMEOUT_CONTEXT + PUSBHUB_PORT_DATA PortData = NULL; + NTSTATUS Status; + KIRQL OldIrql; + + DPRINT("USBH_SelectConfigOrInterfaceComplete ... \n"); + + PortData; + + if (Irp->PendingReturned) + { + IoMarkIrpPending(Irp); + } + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)Context; + HubExtension = PortExtension->HubExtension; + + if (HubExtension) + { + PortData = &HubExtension->PortData[PortExtension->PortNumber - 1]; + } + + Status = Irp->IoStatus.Status; + + if (Irp->IoStatus.Status == STATUS_SUCCESS) + { + KeAcquireSpinLock(&PortExtension->PortTimeoutSpinLock, &OldIrql); + + TimeoutContext = PortExtension->BndwTimeoutContext; + + if (TimeoutContext) + { + DPRINT1("USBH_SelectConfigOrInterfaceComplete: TimeoutContext != NULL. FIXME. \n"); + DbgBreakPoint(); + } + + KeReleaseSpinLock(&PortExtension->PortTimeoutSpinLock, OldIrql); + + PortExtension->PortPdoFlags &= ~(USBHUB_PDO_FLAG_PORT_RESTORE_FAIL | + USBHUB_PDO_FLAG_ALLOC_BNDW_FAILED); + + if (PortData && PortData->ConnectionStatus != DeviceHubNestedTooDeeply) + { + PortData->ConnectionStatus = DeviceConnected; + } + } + else + { + DPRINT1("USBH_SelectConfigOrInterfaceComplete: Status != STATUS_SUCCESS. FIXME. \n"); + DbgBreakPoint(); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoUrbFilter(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; + PUSBHUB_FDO_EXTENSION HubExtension; + //PDEVICE_OBJECT DeviceObject; + PIO_STACK_LOCATION IoStack; + PURB Urb; + USHORT Function; + ULONG MaxPower; + USBD_STATUS UrbStatus; + BOOLEAN IsValidConfig; + + HubExtension = PortExtension->HubExtension; + //DeviceObject = PortExtension->Common.SelfDevice; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Urb = (PURB)IoStack->Parameters.Others.Argument1; + + //DPRINT("USBH_PdoUrbFilter: Device - %p, Irp - %p, Urb - %p\n", + // DeviceObject, + // Irp, + // Urb); + + if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_PORT_RESTORE_FAIL | + USBHUB_PDO_FLAG_PORT_RESSETING)) + { + Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER; + USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + Function = Urb->UrbHeader.Function; + + if (Function == URB_FUNCTION_SELECT_CONFIGURATION) + { + ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor; + + if (ConfigDescriptor) + { + IsValidConfig = TRUE; + + if (ConfigDescriptor->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) + { + IsValidConfig = FALSE; + UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR; + } + + if (ConfigDescriptor->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + IsValidConfig = FALSE; + UrbStatus = USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR; + } + + if (!IsValidConfig) + { + Urb->UrbHeader.Status = UrbStatus; + USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + MaxPower = 2 * ConfigDescriptor->MaxPower; + PortExtension->MaxPower = MaxPower; + + if (HubExtension->MaxPower < MaxPower) + { + DPRINT1("USBH_PdoUrbFilter: USBH_InvalidatePortDeviceState() UNIMPLEMENTED. FIXME. \n"); + + DbgBreakPoint(); + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INSUFFICIENT_PWR; + //USBH_InvalidatePortDeviceState() + USBH_CompleteIrp(Irp, STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + } + } + + if (Function == URB_FUNCTION_SELECT_CONFIGURATION || + Function == URB_FUNCTION_SELECT_INTERFACE) + { + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBH_SelectConfigOrInterfaceComplete, + PortExtension, + TRUE, + TRUE, + TRUE); + + return IoCallDriver(HubExtension->RootHubPdo2, Irp); + } + + if (Function == URB_FUNCTION_ABORT_PIPE || + Function == URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL || + Function == URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL || + Function == URB_FUNCTION_GET_FRAME_LENGTH || + Function == URB_FUNCTION_SET_FRAME_LENGTH || + Function == URB_FUNCTION_GET_CURRENT_FRAME_NUMBER) + { + return USBH_PassIrp(HubExtension->RootHubPdo2, Irp); + } + + if (Function == URB_FUNCTION_CONTROL_TRANSFER || + Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER || + Function == URB_FUNCTION_ISOCH_TRANSFER) + { + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING) + { + Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER; + USBH_CompleteIrp(Irp, STATUS_DELETE_PENDING); + return STATUS_DELETE_PENDING; + } + + return USBH_PassIrp(HubExtension->RootHubPdo2, Irp); + } + + if (Function != URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR) + { + return USBH_PassIrp(HubExtension->RootHubPdo2, Irp); + } + else + { + DPRINT1("USBH_PdoUrbFilter: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR UNIMPLEMENTED. FIXME. \n"); + //DbgBreakPoint(); + + USBH_CompleteIrp(Irp, STATUS_NOT_IMPLEMENTED); + return STATUS_NOT_IMPLEMENTED; + } +} + +NTSTATUS +NTAPI +USBH_PdoIoctlSubmitUrb(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PUSBHUB_FDO_EXTENSION HubExtension; + PURB Urb; + NTSTATUS Status; + + //DPRINT("USBH_PdoIoctlSubmitUrb ... \n"); + + HubExtension = (PUSBHUB_FDO_EXTENSION)PortExtension->HubExtension; + IoStack = Irp->Tail.Overlay.CurrentStackLocation; + + Urb = (PURB)IoStack->Parameters.Others.Argument1; + + if (PortExtension->DeviceHandle == NULL) + { + Urb->UrbHeader.UsbdDeviceHandle = (PVOID)-1; + Status = USBH_PassIrp(HubExtension->RootHubPdo2, Irp); + } + else + { + Urb->UrbHeader.UsbdDeviceHandle = PortExtension->DeviceHandle; + Status = USBH_PdoUrbFilter(PortExtension, Irp); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoIoctlGetPortStatus(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_PORT_DATA PortData; + PIO_STACK_LOCATION IoStack; + PULONG PortStatus; + NTSTATUS Status; + + DPRINT("USBH_PdoIoctlGetPortStatus ... \n"); + + HubExtension = PortExtension->HubExtension; + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->HubSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + PortData = &HubExtension->PortData[PortExtension->PortNumber - 1]; + + Status = USBH_SyncGetPortStatus(HubExtension, + PortExtension->PortNumber, + &PortData->PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + IoStack = Irp->Tail.Overlay.CurrentStackLocation; + PortStatus = IoStack->Parameters.Others.Argument1; + + *PortStatus = 0; + + if (PortExtension->Common.SelfDevice == PortData->DeviceObject) + { + if (PortData->PortStatus.UsbPortStatus.EnableStatus) + { + *PortStatus |= USBD_PORT_ENABLED; + } + + if (PortData->PortStatus.UsbPortStatus.ConnectStatus) + { + *PortStatus |= USBD_PORT_CONNECTED; + } + } + + KeReleaseSemaphore(&HubExtension->HubSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + USBH_CompleteIrp(Irp, Status); + + return Status; +} + +VOID +NTAPI +USBH_ResetPortWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + PUSBHUB_RESET_PORT_CONTEXT WorkItemReset; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSB_DEVICE_HANDLE DeviceHandle; + NTSTATUS Status; + USHORT Port; + + DPRINT("USBH_ResetPortWorker ... \n"); + + WorkItemReset = (PUSBHUB_RESET_PORT_CONTEXT)Context; + + PortExtension = WorkItemReset->PortExtension; + + if (!HubExtension) + { + Status = STATUS_UNSUCCESSFUL; + goto Exit; + } + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->HubSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + Port = PortExtension->PortNumber; + + if (PortExtension->Common.SelfDevice == HubExtension->PortData[Port-1].DeviceObject && + (DeviceHandle = PortExtension->DeviceHandle) != 0) + { + USBD_RemoveDeviceEx(HubExtension, + DeviceHandle, + USBD_MARK_DEVICE_BUSY); + + Status = USBH_ResetDevice(HubExtension, + Port, + 1, + 0); + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + + KeReleaseSemaphore(&HubExtension->HubSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + +Exit: + + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESSETING; + + USBH_CompleteIrp(WorkItemReset->Irp, Status); + + WorkItemReset->PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL; +} + +NTSTATUS +NTAPI +USBH_PdoIoctlResetPort(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_RESET_PORT_CONTEXT HubWorkItemBuffer; + PUSBHUB_IO_WORK_ITEM HubIoWorkItem; + NTSTATUS Status; + + HubExtension = PortExtension->HubExtension; + + DPRINT("USBH_PdoIoctlResetPort ... \n"); + + if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_PORT_RESSETING | + 0x08000000)) + { + Status = STATUS_UNSUCCESSFUL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + Status = USBH_AllocateWorkItem(HubExtension, + &HubIoWorkItem, + USBH_ResetPortWorker, + sizeof(USBHUB_RESET_PORT_CONTEXT), + (PVOID *)&HubWorkItemBuffer, + DelayedWorkQueue); + + if (!NT_SUCCESS(Status)) + { + Status = STATUS_UNSUCCESSFUL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_PORT_RESSETING; + IoMarkIrpPending(Irp); + + HubWorkItemBuffer->PortExtension = PortExtension; + HubWorkItemBuffer->Irp = Irp; + + Status = STATUS_PENDING; + + USBH_QueueWorkItem(PortExtension->HubExtension, HubIoWorkItem); + + return Status; +} + +VOID +NTAPI +USBH_PortIdleNotificationCancelRoutine(IN PDEVICE_OBJECT Device, + IN PIRP Irp) +{ + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSBHUB_FDO_EXTENSION HubExtension; + PIRP PendingIdleIrp = NULL; + PUSBHUB_IO_WORK_ITEM HubIoWorkItem; + PUSBHUB_IDLE_PORT_CANCEL_CONTEXT HubWorkItemBuffer; + NTSTATUS Status; + + DPRINT("USBH_PortIdleNotificationCancelRoutine ... \n"); + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)Device->DeviceExtension; + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION; + + HubExtension = PortExtension->HubExtension; + + PortExtension->IdleNotificationIrp = NULL; + + if (HubExtension && + HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST) + { + PendingIdleIrp = HubExtension->PendingIdleIrp; + HubExtension->PendingIdleIrp = NULL; + } + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + if (PendingIdleIrp) + { + USBH_HubCancelIdleIrp(HubExtension, PendingIdleIrp); + } + + Status = USBH_AllocateWorkItem(HubExtension, + &HubIoWorkItem, + USBH_IdleCancelPowerHubWorker, + sizeof(USBHUB_IDLE_PORT_CANCEL_CONTEXT), + (PVOID *)&HubWorkItemBuffer, + DelayedWorkQueue); + + if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0 || + !NT_SUCCESS(Status)) + { + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + else + { + HubWorkItemBuffer->Irp = Irp; + USBH_QueueWorkItem(HubExtension, HubIoWorkItem); + } +} + +NTSTATUS +NTAPI +USBH_PortIdleNotificationRequest(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PIO_STACK_LOCATION IoStack; + PUSB_IDLE_CALLBACK_INFO IdleCallbackInfo; + NTSTATUS Status; + KIRQL Irql; + + DPRINT("USBH_PortIdleNotificationRequest ... \n"); + + HubExtension = PortExtension->HubExtension; + + IoAcquireCancelSpinLock(&Irql); + + if (PortExtension->IdleNotificationIrp) + { + IoReleaseCancelSpinLock(Irql); + Irp->IoStatus.Status = STATUS_DEVICE_BUSY; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_DEVICE_BUSY; + } + + IoStack = IoGetCurrentIrpStackLocation(Irp); + IdleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + if (!IdleCallbackInfo || !IdleCallbackInfo->IdleCallback) + { + IoReleaseCancelSpinLock(Irql); + + Status = STATUS_NO_CALLBACK_ACTIVE; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; + } + + IoSetCancelRoutine(Irp, USBH_PortIdleNotificationCancelRoutine); + + if (Irp->Cancel) + { + if (IoSetCancelRoutine(Irp, NULL)) + { + IoReleaseCancelSpinLock(Irql); + Status = STATUS_CANCELLED; + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + else + { + IoMarkIrpPending(Irp); + IoReleaseCancelSpinLock(Irql); + Status = STATUS_PENDING; + } + } + else + { + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_IDLE_NOTIFICATION; + + PortExtension->IdleNotificationIrp = Irp; + IoMarkIrpPending(Irp); + + IoReleaseCancelSpinLock(Irql); + Status = STATUS_PENDING; + + DPRINT("USBH_PortIdleNotificationRequest: IdleNotificationIrp - %p\n", + PortExtension->IdleNotificationIrp); + //DbgBreakPoint(); + + USBH_CheckIdleDeferred(HubExtension); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_IoctlGetNodeName(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSB_NODE_CONNECTION_NAME ConnectionName; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + ULONG LengthSkip; + PWCHAR BufferEnd; + WCHAR Symbol; + ULONG LengthReturned; + ULONG LengthName; + ULONG Length; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBH_IoctlGetNodeName ... \n"); + + Status = STATUS_SUCCESS; + + ConnectionName = (PUSB_NODE_CONNECTION_NAME)Irp->AssociatedIrp.SystemBuffer; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + if (Length < sizeof(USB_NODE_CONNECTION_NAME)) + { + Status = STATUS_BUFFER_TOO_SMALL; + USBH_CompleteIrp(Irp, STATUS_BUFFER_TOO_SMALL); + return Status; + } + + if (ConnectionName->ConnectionIndex == 0 || + ConnectionName->ConnectionIndex > HubExtension->HubDescriptor->bNumberOfPorts) + { + Status = STATUS_INVALID_PARAMETER; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + PortDevice = HubExtension->PortData[ConnectionName->ConnectionIndex - 1].DeviceObject; + + if (!PortDevice) + { + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME); + ConnectionName->NodeName[0] = 0; + ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME); + USBH_CompleteIrp(Irp, Status); + return Status; + } + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE) || + !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DEVICE_STARTED) || + !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE)) + { + ConnectionName->NodeName[0] = 0; + ConnectionName->ActualLength = sizeof(USB_NODE_CONNECTION_NAME); + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME); + USBH_CompleteIrp(Irp, Status); + return Status; + } + + LengthSkip = 0; + + if (PortExtension->SymbolicLinkName.Buffer[0] == '\\') + { + BufferEnd = &PortExtension->SymbolicLinkName.Buffer[1]; + Symbol = *BufferEnd; + + if (PortExtension->SymbolicLinkName.Buffer[1] == '\\') + { + LengthSkip = 2 * sizeof(WCHAR); + } + else + { + do + { + if (!Symbol) + { + break; + } + + BufferEnd += 1; + Symbol = *BufferEnd; + } + while (*BufferEnd != '\\'); + + if (*BufferEnd == '\\') + { + BufferEnd += 1; + } + + LengthSkip = (ULONG)BufferEnd - + (ULONG)&PortExtension->SymbolicLinkName.Buffer[0]; + } + } + + LengthName = PortExtension->SymbolicLinkName.Length - LengthSkip; + + RtlZeroMemory(&ConnectionName->ActualLength, Length - 2 * sizeof(WCHAR)); + + LengthReturned = sizeof(USB_NODE_CONNECTION_NAME) + LengthName; + + if (Length < LengthReturned) + { + ConnectionName->NodeName[0] = 0; + ConnectionName->ActualLength = LengthReturned; + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_NAME); + USBH_CompleteIrp(Irp, Status); + return Status; + } + + RtlCopyMemory(&ConnectionName->NodeName[0], + &PortExtension->SymbolicLinkName.Buffer[LengthSkip >> 1], + LengthName); + + ConnectionName->ActualLength = LengthReturned; + + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = LengthReturned; + USBH_CompleteIrp(Irp, Status); + return Status; +} + +NTSTATUS +NTAPI +USBH_IoctlGetNodeInformation(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSB_NODE_INFORMATION NodeInfo; + PIO_STACK_LOCATION IoStack; + ULONG BufferLength; + NTSTATUS Status; + BOOLEAN HubIsBusPowered; + + DPRINT("USBH_IoctlGetNodeInformation ... \n"); + + Status = STATUS_SUCCESS; + + NodeInfo = (PUSB_NODE_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, BufferLength); + + if (BufferLength < sizeof(USB_NODE_INFORMATION)) + { + USBH_CompleteIrp(Irp, STATUS_BUFFER_TOO_SMALL); + return STATUS_BUFFER_TOO_SMALL; + } + + NodeInfo->NodeType = UsbHub; + + RtlCopyMemory(&NodeInfo->u.HubInformation.HubDescriptor, + HubExtension->HubDescriptor, + sizeof(USB_HUB_DESCRIPTOR)); + + HubIsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice, + HubExtension->HubConfigDescriptor); + + NodeInfo->u.HubInformation.HubIsBusPowered = HubIsBusPowered; + + Irp->IoStatus.Information = sizeof(USB_NODE_INFORMATION); + + USBH_CompleteIrp(Irp, Status); + + return Status; +} + +NTSTATUS +NTAPI +USBH_IoctlGetHubCapabilities(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSB_HUB_CAPABILITIES Capabilities; + PIO_STACK_LOCATION IoStack; + ULONG BufferLength; + ULONG Length; + ULONG HubIs2xCapable = 0; + + DPRINT("USBH_IoctlGetHubCapabilities ... \n"); + + Capabilities = (PUSB_HUB_CAPABILITIES)Irp->AssociatedIrp.SystemBuffer; + + HubIs2xCapable = HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + if (BufferLength <= sizeof(HubIs2xCapable)) + { + Length = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + } + else + { + Length = sizeof(HubIs2xCapable); + } + + RtlZeroMemory(Capabilities, BufferLength); + RtlCopyMemory(Capabilities, &HubIs2xCapable, Length); + + Irp->IoStatus.Information = Length; + + USBH_CompleteIrp(Irp, STATUS_SUCCESS); + + return 0; +} + +NTSTATUS +NTAPI +USBH_IoctlGetNodeConnectionAttributes(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSB_NODE_CONNECTION_ATTRIBUTES Attributes; + ULONG ConnectionIndex; + ULONG NumPorts; + ULONG Port; + NTSTATUS Status; + PUSBHUB_PORT_DATA PortData; + PIO_STACK_LOCATION IoStack; + ULONG BufferLength; + + DPRINT("USBH_IoctlGetNodeConnectionAttributes ... \n"); + + PortData = HubExtension->PortData; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + Attributes = (PUSB_NODE_CONNECTION_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer; + + if (BufferLength < sizeof(USB_NODE_CONNECTION_ATTRIBUTES)) + { + Status = STATUS_BUFFER_TOO_SMALL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + ConnectionIndex = Attributes->ConnectionIndex; + RtlZeroMemory(Attributes, BufferLength); + Attributes->ConnectionIndex = ConnectionIndex; + + Status = STATUS_INVALID_PARAMETER; + + NumPorts = HubExtension->HubDescriptor->bNumberOfPorts; + Port = 1; + + if (NumPorts > 0) + { + while (Port != ConnectionIndex) + { + ++PortData; + ++Port; + + if (Port > NumPorts) + { + goto Exit; + } + } + + Attributes->ConnectionStatus = PortData->ConnectionStatus; + Attributes->PortAttributes = PortData->PortAttributes; + + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_ATTRIBUTES); + Status = STATUS_SUCCESS; + } + +Exit: + + USBH_CompleteIrp(Irp, Status); + return Status; +} + +NTSTATUS +NTAPI +USBH_IoctlGetNodeConnectionInformation(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN BOOLEAN IsExt) +{ + PUSBHUB_PORT_DATA PortData; + ULONG BufferLength; + PUSB_NODE_CONNECTION_INFORMATION_EX Info; + ULONG ConnectionIndex; + ULONG NumPorts; + NTSTATUS Status; + PDEVICE_OBJECT DeviceObject; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + ULONG Port; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBH_IoctlGetNodeConnectionInformation ... \n"); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Info = (PUSB_NODE_CONNECTION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; + BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + PortData = HubExtension->PortData; + + if (BufferLength < (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO))) + { + Status = STATUS_BUFFER_TOO_SMALL; + goto Exit; + } + + ConnectionIndex = Info->ConnectionIndex; + RtlZeroMemory(Info, BufferLength); + Info->ConnectionIndex = ConnectionIndex; + + NumPorts = HubExtension->HubDescriptor->bNumberOfPorts; + + Status = STATUS_INVALID_PARAMETER; + + Port = 1; + + if (NumPorts >= 1) + { + while (Port != Info->ConnectionIndex) + { + ++PortData; + ++Port; + + if (Port > NumPorts) + { + goto Exit; + } + } + + DeviceObject = PortData->DeviceObject; + + if (DeviceObject) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)DeviceObject->DeviceExtension; + + Info->ConnectionStatus = PortData->ConnectionStatus; + Info->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE; + + RtlCopyMemory(&Info->DeviceDescriptor, + &PortExtension->DeviceDescriptor, + sizeof(USB_DEVICE_DESCRIPTOR)); + + if (PortExtension->DeviceHandle) + { + Status = USBD_GetDeviceInformationEx(PortExtension, + HubExtension, + Info, + BufferLength, + PortExtension->DeviceHandle); + } + else + { + Status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(Status)) + { + if (!IsExt) + { + Info->Speed = Info->Speed == FALSE; + } + + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + + (Info->NumberOfOpenPipes - 1) * sizeof(USB_PIPE_INFO); + goto Exit; + } + + if (Status != STATUS_BUFFER_TOO_SMALL) + { + goto Exit; + } + } + else + { + Info->ConnectionStatus = PortData->ConnectionStatus; + } + + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - + sizeof(USB_PIPE_INFO); + + Status = STATUS_SUCCESS; + } + +Exit: + USBH_CompleteIrp(Irp, Status); + return Status; +} + +NTSTATUS +NTAPI +USBH_IoctlGetNodeConnectionDriverKeyName(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSBHUB_PORT_DATA PortData; + PDEVICE_OBJECT PortDevice; + ULONG Length; + ULONG ResultLength; + ULONG Port; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + ULONG BufferLength; + PUSB_NODE_CONNECTION_DRIVERKEY_NAME KeyName; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + + DPRINT("USBH_IoctlGetNodeConnectionDriverKeyName ... \n"); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + KeyName = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer; + BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + + if (BufferLength < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME)) + { + Status = STATUS_BUFFER_TOO_SMALL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + Status = STATUS_INVALID_PARAMETER; + + if (!HubExtension->HubDescriptor->bNumberOfPorts) + { + Status = STATUS_BUFFER_TOO_SMALL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + Port = 1; + + do + { + if (Port == KeyName->ConnectionIndex) + { + PortData = &HubExtension->PortData[KeyName->ConnectionIndex - 1]; + + PortDevice = PortData->DeviceObject; + + if (PortDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + if (PortExtension->PortPdoFlags & 0x04000000) + { + ResultLength = BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME); + + Status = IoGetDeviceProperty(PortDevice, + DevicePropertyDriverKeyName, + BufferLength - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME), + &KeyName->DriverKeyName, + &ResultLength); + + if (Status == STATUS_BUFFER_TOO_SMALL) + { + Status = STATUS_SUCCESS; + } + + Length = ResultLength + sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME); + + KeyName->ActualLength = Length; + + if (BufferLength < Length) + { + KeyName->DriverKeyName[0] = 0; + Irp->IoStatus.Information = sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME); + } + else + { + Irp->IoStatus.Information = Length; + } + } + else + { + Status = STATUS_INVALID_DEVICE_STATE; + } + } + } + + ++Port; + } + while (Port <= HubExtension->HubDescriptor->bNumberOfPorts); + + USBH_CompleteIrp(Irp, Status); + + return Status; +} + +NTSTATUS +NTAPI +USBH_IoctlGetDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + ULONG BufferLength; + PUSBHUB_PORT_DATA PortData; + PUSB_DESCRIPTOR_REQUEST UsbRequest; + ULONG Port; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + struct _URB_CONTROL_TRANSFER * Urb; + NTSTATUS Status; + ULONG RequestBufferLength; + PIO_STACK_LOCATION IoStack; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + BufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength; + PortData = HubExtension->PortData; + + DPRINT("USBH_IoctlGetDescriptor: BufferLength - %x\n", BufferLength); + + if (BufferLength < sizeof(USB_DESCRIPTOR_REQUEST)) + { + Status = STATUS_BUFFER_TOO_SMALL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + UsbRequest = (PUSB_DESCRIPTOR_REQUEST)Irp->AssociatedIrp.SystemBuffer; + + RequestBufferLength = UsbRequest->SetupPacket.wLength; + + if (RequestBufferLength > BufferLength - + (sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR))) + { + DPRINT("USBH_IoctlGetDescriptor: RequestBufferLength - %x\n", + RequestBufferLength); + + Status = STATUS_BUFFER_TOO_SMALL; + USBH_CompleteIrp(Irp, Status); + return Status; + } + + Port = 1; + + Status = STATUS_INVALID_PARAMETER; + + if (HubExtension->HubDescriptor->bNumberOfPorts >= 1) + { + while (Port != UsbRequest->ConnectionIndex) + { + ++PortData; + ++Port; + + if (Port > HubExtension->HubDescriptor->bNumberOfPorts) + { + goto Exit; + } + } + + PortDevice = PortData->DeviceObject; + + if (PortDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + if (UsbRequest->SetupPacket.bmRequest == USB_CONFIGURATION_DESCRIPTOR_TYPE && + RequestBufferLength == sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + Status = STATUS_SUCCESS; + + RtlCopyMemory(&UsbRequest->Data[0], + &PortExtension->ConfigDescriptor, + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + Irp->IoStatus.Information = sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR) + + sizeof(USB_CONFIGURATION_DESCRIPTOR); + } + else + { + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), + USB_HUB_TAG); + + if (Urb) + { + RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); + + Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); + + Urb->TransferBuffer = &UsbRequest->Data[0]; + Urb->TransferBufferLength = RequestBufferLength; + Urb->TransferBufferMDL = 0; + Urb->UrbLink = 0; + + RtlCopyMemory(Urb->SetupPacket, + &UsbRequest->SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + Status = USBH_SyncSubmitUrb(PortExtension->Common.SelfDevice, + (PURB)Urb); + + Irp->IoStatus.Information = (sizeof(USB_DESCRIPTOR_REQUEST) - sizeof(UCHAR)) + + Urb->TransferBufferLength; + + ExFreePool(Urb); + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + } + } + +Exit: + + USBH_CompleteIrp(Irp, Status); + return Status; +} + +NTSTATUS +NTAPI +USBH_DeviceControl(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + NTSTATUS Status = STATUS_DEVICE_BUSY; + PIO_STACK_LOCATION IoStack; + ULONG ControlCode; + BOOLEAN IsCheckHubIdle = FALSE; + + DPRINT("USBH_DeviceControl: HubExtension - %p, Irp - %p\n", + HubExtension, + Irp); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + DPRINT("USBH_DeviceControl: ControlCode - %p\n", ControlCode); + + if ((HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0) && + (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)) + { + IsCheckHubIdle = TRUE; + USBH_HubSetD0(HubExtension); + } + + switch (ControlCode) + { + case IOCTL_USB_GET_HUB_CAPABILITIES: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_HUB_CAPABILITIES. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetHubCapabilities(HubExtension, Irp); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_HUB_CYCLE_PORT: + DPRINT1("USBH_DeviceControl: IOCTL_USB_HUB_CYCLE_PORT UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + break; + + case IOCTL_USB_GET_NODE_INFORMATION: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_INFORMATION. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetNodeInformation(HubExtension, Irp); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetNodeConnectionInformation(HubExtension, + Irp, + FALSE); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetNodeConnectionInformation(HubExtension, + Irp, + TRUE); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetNodeConnectionAttributes(HubExtension, Irp); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_GET_NODE_CONNECTION_NAME: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_NAME.\n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetNodeName(HubExtension, Irp); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetNodeConnectionDriverKeyName(HubExtension, Irp); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION: + DPRINT("USBH_DeviceControl: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION. \n"); + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + Status = USBH_IoctlGetDescriptor(HubExtension, Irp); + break; + } + + USBH_CompleteIrp(Irp, Status); + break; + + case 0x2F0003: + DPRINT("USBH_DeviceControl: IOCTL_KS_PROPERTY. \n"); + Status = STATUS_INVALID_DEVICE_REQUEST; + USBH_CompleteIrp(Irp, Status); + break; + + default: + DPRINT1("USBH_DeviceControl: Unhandled IOCTL_ - %p\n", ControlCode); + Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp); + break; + } + + if (IsCheckHubIdle) + { + USBH_CheckHubIdle(HubExtension); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoInternalControl(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + NTSTATUS Status = STATUS_NOT_SUPPORTED; + ULONG ControlCode; + PIO_STACK_LOCATION IoStack; + PULONG HubCount; + + //DPRINT("USBH_PdoInternalControl: PortExtension - %p, Irp - %p\n", + // PortExtension, + // Irp); + + HubExtension = PortExtension->HubExtension; + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED) + { + Status = STATUS_DEVICE_NOT_CONNECTED; + goto Exit; + } + + if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD0) + { + Status = STATUS_DEVICE_POWERED_OFF; + goto Exit; + } + + IoStack = IoGetCurrentIrpStackLocation(Irp); + ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + //DPRINT("USBH_PdoInternalControl: ControlCode - %p\n", ControlCode); + + if (ControlCode == IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO) + { + HubExtension = PortExtension->RootHubExtension; + DPRINT("USBH_PdoInternalControl: HubExtension - %p\n", HubExtension); + } + + if (!HubExtension) + { + Status = STATUS_DEVICE_BUSY; + goto Exit; + } + + switch (ControlCode) + { + case IOCTL_INTERNAL_USB_SUBMIT_URB: + //DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_SUBMIT_URB. \n"); + return USBH_PdoIoctlSubmitUrb(PortExtension, Irp); + + case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION. \n"); + return USBH_PortIdleNotificationRequest(PortExtension, Irp); + + case IOCTL_INTERNAL_USB_GET_PORT_STATUS: + DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PORT_STATUS. \n"); + return USBH_PdoIoctlGetPortStatus(PortExtension, Irp); + + case IOCTL_INTERNAL_USB_RESET_PORT: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_RESET_PORT. \n"); + return USBH_PdoIoctlResetPort(PortExtension, Irp); + + case IOCTL_INTERNAL_USB_ENABLE_PORT: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_ENABLE_PORT. \n"); + DbgBreakPoint(); + break; + + case IOCTL_INTERNAL_USB_CYCLE_PORT: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_CYCLE_PORT. \n"); + DbgBreakPoint(); + break; + + case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE: + DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE. \n"); + *(PVOID *)IoStack->Parameters.Others.Argument1 = PortExtension->DeviceHandle; + Status = STATUS_SUCCESS; + break; + + case IOCTL_INTERNAL_USB_GET_HUB_COUNT: + DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_COUNT. PortPdoFlags - %p\n", + PortExtension->PortPdoFlags); + + if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE)) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + HubCount = (PULONG)IoStack->Parameters.Others.Argument1; + + ++*HubCount; + + Status = USBH_SyncGetHubCount(HubExtension->LowerDevice, + HubCount); + + DPRINT("USBH_PdoInternalControl: *HubCount - %p\n", *HubCount); + break; + + case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO: + DPRINT("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO. PortPdoFlags - %p\n", + PortExtension->PortPdoFlags); + + if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE)) + { + DbgBreakPoint(); + Status = STATUS_SUCCESS; + + *(PVOID *)IoStack->Parameters.Others.Argument1 = NULL; + + USBH_CompleteIrp(Irp, Status); + break; + } + + ASSERT(HubExtension->RootHubPdo); + return USBH_PassIrp(HubExtension->RootHubPdo, Irp); + + case IOCTL_INTERNAL_USB_GET_HUB_NAME: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_HUB_NAME. \n"); + DbgBreakPoint(); + break; + + case IOCTL_GET_HCD_DRIVERKEY_NAME: + DPRINT1("USBH_PdoInternalControl: IOCTL_GET_HCD_DRIVERKEY_NAME. \n"); + DbgBreakPoint(); + break; + + case IOCTL_INTERNAL_USB_GET_BUS_INFO: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_BUS_INFO. \n"); + DbgBreakPoint(); + break; + + case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO: + DPRINT1("USBH_PdoInternalControl: IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO. \n"); + DbgBreakPoint(); + break; + + default: + DPRINT1("USBH_PdoInternalControl: unhandled IOCTL_ - %p\n", ControlCode); + break; + } + +Exit: + USBH_CompleteIrp(Irp, Status); + return Status; +} diff --git a/reactos/drivers/usb/usbhub_new/pnp.c b/reactos/drivers/usb/usbhub_new/pnp.c new file mode 100644 index 00000000000..35f70f08249 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/pnp.c @@ -0,0 +1,2778 @@ +#include "usbhub.h" + +//#define NDEBUG +#include + +NTSTATUS +NTAPI +USBH_IrpCompletion(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PRKEVENT Event; + + DPRINT("USBH_IrpCompletion: Irp - %p\n", Irp); + + Event = (PRKEVENT)Context; + KeSetEvent(Event, EVENT_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBH_HubPnPIrpComplete(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + + DPRINT("USBH_HubPnPIrpComplete: Irp - %p\n", Irp); + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + DPRINT1("USBH_HubPnPIrpComplete: Irp failed - %p\n", Irp->IoStatus.Status); + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED; + } + + Irp->IoStatus.Status = STATUS_MORE_PROCESSING_REQUIRED; + + KeSetEvent(&HubExtension->LowerDeviceEvent, EVENT_INCREMENT, FALSE); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBH_QueryCapsComplete(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + PDEVICE_CAPABILITIES Capabilities; + + DPRINT("USBH_QueryCapsComplete: ... \n"); + + Status = Irp->IoStatus.Status; + + if (Irp->PendingReturned) + { + IoMarkIrpPending(Irp); + } + + IoStack= IoGetCurrentIrpStackLocation(Irp); + Capabilities = IoStack->Parameters.DeviceCapabilities.Capabilities; + + Capabilities->SurpriseRemovalOK = 1; + + return Status; +} + +NTSTATUS +NTAPI +USBHUB_GetBusInterface(IN PDEVICE_OBJECT DeviceObject, + IN PUSB_BUS_INTERFACE_HUB_V5 BusInterface) +{ + PIRP Irp; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + KEVENT Event; + + DPRINT("USBHUB_GetBusInterface: ... \n"); + + Irp = IoAllocateIrp(DeviceObject->StackSize, 0); + + if (!Irp) + { + DPRINT1("USBHUB_GetBusInterface: IoAllocateIrp() failed\n"); + return STATUS_UNSUCCESSFUL; + } + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + IoSetCompletionRoutine(Irp, + USBH_IrpCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_PNP; + IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + + IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_HUB_GUID; + IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_HUB_V5); + IoStack->Parameters.QueryInterface.Version = USB_BUSIF_HUB_VERSION_5; + IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface; + IoStack->Parameters.QueryInterface.InterfaceSpecificData = DeviceObject; + + Status = IoCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + + Status = Irp->IoStatus.Status; + } + + IoFreeIrp(Irp); + + return Status; +} + +NTSTATUS +NTAPI +USBHUB_GetBusInterfaceUSBDI(IN PDEVICE_OBJECT DeviceObject, + IN PUSB_BUS_INTERFACE_USBDI_V2 BusInterfaceUSBDI) +{ + PIRP Irp; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + KEVENT Event; + + DPRINT("USBHUB_GetBusInterfaceUSBDI: ... \n"); + + Irp = IoAllocateIrp(DeviceObject->StackSize, 0); + + if (!Irp) + { + DPRINT1("USBHUB_GetBusInterfaceUSBDI: IoAllocateIrp() failed\n"); + return STATUS_UNSUCCESSFUL; + } + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + IoSetCompletionRoutine(Irp, + USBH_IrpCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_PNP; + IoStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + + IoStack->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID; + IoStack->Parameters.QueryInterface.Size = sizeof(USB_BUS_INTERFACE_USBDI_V2); + IoStack->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_2; + IoStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterfaceUSBDI; + IoStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; + + Status = IoCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + + Status = Irp->IoStatus.Status; + } + + IoFreeIrp(Irp); + + return Status; +} + +VOID +NTAPI +USBH_QueryCapabilities(IN PDEVICE_OBJECT DeviceObject, + IN PDEVICE_CAPABILITIES DeviceCapabilities) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + KEVENT Event; + + DPRINT("USBH_QueryCapabilities: ... \n"); + + Irp = IoAllocateIrp(DeviceObject->StackSize, 0); + + if (!Irp) + { + DPRINT1("USBH_QueryCapabilities: IoAllocateIrp() failed\n"); + return; + } + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES)); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + IoSetCompletionRoutine(Irp, + USBH_IrpCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_PNP; + IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; + + IoStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities; + IoStack->Parameters.DeviceCapabilities.Capabilities->Size = sizeof(DEVICE_CAPABILITIES); + IoStack->Parameters.DeviceCapabilities.Capabilities->Version = 1; + IoStack->Parameters.DeviceCapabilities.Capabilities->Address = -1; + IoStack->Parameters.DeviceCapabilities.Capabilities->UINumber = -1; + + if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + + IoFreeIrp(Irp); +} + +NTSTATUS +NTAPI +USBH_OpenConfiguration(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_INTERFACE_DESCRIPTOR Pid; + PURB Urb; + NTSTATUS Status; + USBD_INTERFACE_LIST_ENTRY InterfaceList[2] = {{NULL, NULL}, {NULL, NULL}}; + + DPRINT("USBH_OpenConfiguration ... \n"); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB && + HubExtension->LowerPDO != HubExtension->RootHubPdo) + { + Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor, + HubExtension->HubConfigDescriptor, + -1, + -1, + USB_DEVICE_CLASS_HUB, + -1, + 2); + + if (Pid) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_MULTIPLE_TTS; + } + else + { + Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor, + HubExtension->HubConfigDescriptor, + -1, + -1, + USB_DEVICE_CLASS_HUB, + -1, + 1); + + if (Pid) + { + goto Next; + } + + Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor, + HubExtension->HubConfigDescriptor, + -1, + -1, + USB_DEVICE_CLASS_HUB, + -1, + 0); + } + } + else + { + Pid = USBD_ParseConfigurationDescriptorEx(HubExtension->HubConfigDescriptor, + HubExtension->HubConfigDescriptor, + -1, + -1, + USB_DEVICE_CLASS_HUB, + -1, + -1); + } + + if (!Pid) + { + return STATUS_UNSUCCESSFUL; + } + + Next: + + if (Pid->bInterfaceClass != USB_DEVICE_CLASS_HUB) + { + return STATUS_UNSUCCESSFUL; + } + + InterfaceList[0].InterfaceDescriptor = Pid; + + Urb = USBD_CreateConfigurationRequestEx(HubExtension->HubConfigDescriptor, + InterfaceList); + + if (!Urb) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, Urb); + + if (NT_SUCCESS(Status)) + { + RtlCopyMemory(&HubExtension->PipeInfo, + InterfaceList[0].Interface->Pipes, + sizeof(USBD_PIPE_INFORMATION)); + + HubExtension->ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle; + } + + ExFreePool(Urb); + + return Status; +} + +NTSTATUS +NTAPI +USBD_Initialize20Hub(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_BUSIFFN_INITIALIZE_20HUB Initialize20Hub; + ULONG TtCount; + PUSB_DEVICE_HANDLE DeviceHandle; + + DPRINT("USBD_InitUsb2Hub ... \n"); + + Initialize20Hub = HubExtension->BusInterface.Initialize20Hub; + + if (!Initialize20Hub) + { + return STATUS_NOT_IMPLEMENTED; + } + + TtCount = 1; + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_MULTIPLE_TTS) + { + TtCount = HubExtension->HubDescriptor->bNumberOfPorts; + } + + DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice); + + return Initialize20Hub(HubExtension->BusInterface.BusContext, + DeviceHandle, + TtCount); +} + +NTSTATUS +NTAPI +USBH_AbortInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + struct _URB_PIPE_REQUEST * Urb; + NTSTATUS Status; + + DPRINT("USBH_AbortInterruptPipe: HubExtension - %p\n", HubExtension); + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_PIPE_REQUEST), + USB_HUB_TAG); + + if (!Urb) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST)); + + Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST); + Urb->Hdr.Function = URB_FUNCTION_ABORT_PIPE; + Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle; + + Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, + (PURB)Urb); + + if (NT_SUCCESS(Status)) + { + KeWaitForSingleObject(&HubExtension->StatusChangeEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + ExFreePool(Urb); + + return Status; +} + +VOID +NTAPI +USBH_FdoCleanup(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PIRP IdleIrp = NULL; + PIRP WakeIrp = NULL; + PUSBHUB_PORT_DATA PortData; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + ULONG NumberPorts; + ULONG Port; + PIRP PortIdleIrp = NULL; + PIRP PortWakeIrp = NULL; + LONG DeviceHandle; + NTSTATUS Status; + KIRQL Irql; + + DPRINT("USBH_FdoCleanup: HubExtension - %p\n", HubExtension); + + USBD_UnRegisterRootHubCallBack(HubExtension); + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STOPPING; + + if (HubExtension->ResetRequestCount) + { + IoCancelIrp(HubExtension->ResetPortIrp); + + KeWaitForSingleObject(&HubExtension->IdleEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + IoFreeIrp(HubExtension->ResetPortIrp); + + HubExtension->ResetPortIrp = NULL; + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST) + { + KeWaitForSingleObject(&HubExtension->IdleEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + IoAcquireCancelSpinLock(&Irql); + + if (HubExtension->PendingWakeIrp) + { + WakeIrp = HubExtension->PendingWakeIrp; + HubExtension->PendingWakeIrp = NULL; + } + + if (HubExtension->PendingIdleIrp) + { + IdleIrp = HubExtension->PendingIdleIrp; + HubExtension->PendingIdleIrp = NULL; + } + + IoReleaseCancelSpinLock(Irql); + + if (WakeIrp) + { + USBH_HubCancelWakeIrp(HubExtension, WakeIrp); + } + + USBH_HubCompletePortWakeIrps(HubExtension, STATUS_DELETE_PENDING); + + if (IdleIrp) + { + USBH_HubCancelIdleIrp(HubExtension, IdleIrp); + } + + if (InterlockedDecrement(&HubExtension->PendingRequestCount) > 0) + { + KeWaitForSingleObject(&HubExtension->PendingRequestEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + if (HubExtension->SCEIrp) + { + Status = USBH_AbortInterruptPipe(HubExtension); + + if (!NT_SUCCESS(Status) && IoCancelIrp(HubExtension->SCEIrp)) + { + KeWaitForSingleObject(&HubExtension->StatusChangeEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + IoFreeIrp(HubExtension->SCEIrp); + + HubExtension->SCEIrp = NULL; + } + + if (!HubExtension->PortData || + !HubExtension->HubDescriptor) + { + goto Exit; + } + + if (!HubExtension->HubDescriptor->bNumberOfPorts) + { + goto Exit; + } + + PortData = HubExtension->PortData; + NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts; + + for (Port = 0; Port < NumberPorts; Port++) + { + if (PortData[Port].DeviceObject) + { + PortExtension = PortData[Port].DeviceObject->DeviceExtension; + + IoAcquireCancelSpinLock(&Irql); + + PortIdleIrp = PortExtension->IdleNotificationIrp; + + if (PortIdleIrp) + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION; + PortExtension->IdleNotificationIrp = NULL; + + if (PortIdleIrp->Cancel) + { + PortIdleIrp = NULL; + } + + if (PortIdleIrp) + { + IoSetCancelRoutine(PortIdleIrp, NULL); + } + } + + PortWakeIrp = PortExtension->PdoWaitWakeIrp; + + if (PortWakeIrp) + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE; + PortExtension->PdoWaitWakeIrp = NULL; + + if (PortIdleIrp->Cancel || + !IoSetCancelRoutine(PortWakeIrp, NULL)) + { + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + } + } + + IoReleaseCancelSpinLock(Irql); + + if (PortIdleIrp) + { + PortIdleIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(PortIdleIrp, IO_NO_INCREMENT); + } + + if (PortWakeIrp) + { + USBH_CompletePowerIrp(HubExtension, + PortWakeIrp, + STATUS_CANCELLED); + } + + if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3)) + { + DeviceHandle = InterlockedExchange((PLONG)&PortExtension->DeviceHandle, + 0); + + if (DeviceHandle) + { + USBD_RemoveDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)DeviceHandle, + 0); + } + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3; + } + } + + USBH_SyncDisablePort(HubExtension, Port + 1); + } + +Exit: + + if (HubExtension->SCEBitmap) + { + ExFreePool(HubExtension->SCEBitmap); + } + + if (HubExtension->HubDescriptor) + { + ExFreePool(HubExtension->HubDescriptor); + } + + if (HubExtension->HubConfigDescriptor) + { + ExFreePool(HubExtension->HubConfigDescriptor); + } + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEVICE_STARTED; + + HubExtension->HubDescriptor = NULL; + HubExtension->HubConfigDescriptor = NULL; + + HubExtension->SCEIrp = NULL; + HubExtension->SCEBitmap = NULL; +} + +NTSTATUS +NTAPI +USBH_StartHubFdoDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + NTSTATUS Status; + WCHAR KeyName[64]; + PVOID DisableRemoteWakeup = NULL; + ULONG HubCount = 0; + PUSB_DEVICE_HANDLE DeviceHandle; + USB_DEVICE_TYPE DeviceType; + DEVICE_CAPABILITIES DeviceCapabilities; + BOOLEAN IsBusPowered; + + DPRINT("USBH_StartHubFdoDevice: ... \n"); + + KeInitializeEvent(&HubExtension->IdleEvent, NotificationEvent, FALSE); + KeInitializeEvent(&HubExtension->ResetEvent, NotificationEvent, TRUE); + KeInitializeEvent(&HubExtension->PendingRequestEvent, NotificationEvent, FALSE); + KeInitializeEvent(&HubExtension->LowerDeviceEvent, NotificationEvent, FALSE); + KeInitializeEvent(&HubExtension->StatusChangeEvent, NotificationEvent, TRUE); + KeInitializeEvent(&HubExtension->RootHubNotificationEvent, + NotificationEvent, + TRUE); + + KeInitializeSpinLock(&HubExtension->RelationsWorkerSpinLock); + KeInitializeSpinLock(&HubExtension->CheckIdleSpinLock); + + KeInitializeSemaphore(&HubExtension->ResetDeviceSemaphore, 1, 1); + KeInitializeSemaphore(&HubExtension->HubPortSemaphore, 1, 1); + KeInitializeSemaphore(&HubExtension->HubSemaphore, 1, 1); + + HubExtension->HubFlags = 0; + HubExtension->HubConfigDescriptor = NULL; + HubExtension->HubDescriptor = NULL; + HubExtension->SCEIrp = NULL; + HubExtension->SCEBitmap = NULL; + HubExtension->SystemPowerState.SystemState = PowerSystemWorking; + HubExtension->PendingRequestCount = 1; + HubExtension->ResetRequestCount = 0; + HubExtension->PendingIdleIrp = NULL; + HubExtension->PendingWakeIrp = NULL; + + InitializeListHead(&HubExtension->PdoList); + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_WITEM_INIT; + InitializeListHead(&HubExtension->WorkItemList); + KeInitializeSpinLock(&HubExtension->WorkItemSpinLock); + + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBH_HubPnPIrpComplete, + HubExtension, + TRUE, + TRUE, + TRUE); + + if (IoCallDriver(HubExtension->LowerDevice, Irp) == STATUS_PENDING) + { + KeWaitForSingleObject(&HubExtension->LowerDeviceEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + HubExtension->RootHubPdo = NULL; + + Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice, + &HubExtension->RootHubPdo, + &HubExtension->RootHubPdo2); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_SyncGetRootHubPdo() failed - %p\n", Status); + goto ErrorExit; + } + + USBH_WriteFailReasonID(HubExtension->LowerPDO, 5); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) + { + DPRINT1("USBH_StartHubFdoDevice: USBHUB_FDO_FLAG_DEVICE_FAILED - TRUE\n"); + Status = STATUS_UNSUCCESSFUL; + goto ErrorExit; + } + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_REMOTE_WAKEUP; + + swprintf(KeyName, L"DisableRemoteWakeup"); + + Status = USBD_GetPdoRegistryParameter(HubExtension->LowerPDO, + &DisableRemoteWakeup, + sizeof(DisableRemoteWakeup), + KeyName, + (wcslen(KeyName) + 1) * sizeof(WCHAR)); + + if (NT_SUCCESS(Status) && DisableRemoteWakeup) + { + DPRINT("USBH_StartHubFdoDevice: DisableRemoteWakeup - TRUE\n"); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_REMOTE_WAKEUP; + } + + HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0; + + USBH_SyncGetHubCount(HubExtension->LowerDevice, + &HubCount); + + Status = USBHUB_GetBusInterface(HubExtension->RootHubPdo, + &HubExtension->BusInterface); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterface() failed - %p\n", + Status); + goto ErrorExit; + } + + Status = USBHUB_GetBusInterfaceUSBDI(HubExtension->LowerDevice, + &HubExtension->BusInterfaceUSBDI); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBHUB_GetBusInterfaceUSBDI() failed - %p\n", + Status); + goto ErrorExit; + } + + DeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice); + + if (DeviceHandle) + { + Status = USBH_GetDeviceType(HubExtension, DeviceHandle, &DeviceType); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceType() failed - %p\n", + Status); + + goto ErrorExit; + } + + if (DeviceType == Usb20Device) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_USB20_HUB; + } + } + + if (HubCount > 6) + { + DPRINT1("USBH_StartHubFdoDevice: HubCount > 6 - %x\n", HubCount); + USBH_WriteFailReasonID(HubExtension->LowerPDO, 6); + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED; + DbgBreakPoint(); + } + + RtlZeroMemory(&DeviceCapabilities, sizeof(DEVICE_CAPABILITIES)); + + USBH_QueryCapabilities(HubExtension->LowerDevice, &DeviceCapabilities); + + HubExtension->SystemWake = DeviceCapabilities.SystemWake; + HubExtension->DeviceWake = DeviceCapabilities.DeviceWake; + + RtlCopyMemory(HubExtension->DeviceState, + &DeviceCapabilities.DeviceState, + POWER_SYSTEM_MAXIMUM * sizeof(DEVICE_POWER_STATE)); + + Status = USBH_GetDeviceDescriptor(HubExtension->Common.SelfDevice, + &HubExtension->HubDeviceDescriptor); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBH_GetDeviceDescriptor() failed - %p\n", + Status); + goto ErrorExit; + } + + Status = USBH_GetConfigurationDescriptor(HubExtension->Common.SelfDevice, + &HubExtension->HubConfigDescriptor); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBH_GetConfigurationDescriptor() failed - %p\n", + Status); + goto ErrorExit; + } + + Status = USBH_SyncGetHubDescriptor(HubExtension); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBH_SyncGetHubDescriptor() failed - %p\n", + Status); + goto ErrorExit; + } + + IsBusPowered = USBH_HubIsBusPowered(HubExtension->Common.SelfDevice, + HubExtension->HubConfigDescriptor); + + if (IsBusPowered) + { + HubExtension->MaxPower = 100; + HubExtension->HubConfigDescriptor->MaxPower = 250; // 500 mA + } + else + { + HubExtension->MaxPower = 500; + } + + Status = USBH_OpenConfiguration(HubExtension); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_StartHubFdoDevice: USBH_OpenConfiguration() failed - %p\n", + Status); + goto ErrorExit; + } + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB) + { + Status = USBD_Initialize20Hub(HubExtension); + } + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + HubExtension->SCEIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize, + FALSE); + + HubExtension->ResetPortIrp = IoAllocateIrp(HubExtension->Common.SelfDevice->StackSize, + FALSE); + + if (!HubExtension->SCEIrp || !HubExtension->ResetPortIrp) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + HubExtension->SCEBitmapLength = HubExtension->PipeInfo.MaximumPacketSize; + + HubExtension->SCEBitmap = ExAllocatePoolWithTag(NonPagedPool, + HubExtension->SCEBitmapLength, + USB_HUB_TAG); + + if (!HubExtension->SCEBitmap) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + RtlZeroMemory(HubExtension->SCEBitmap, HubExtension->SCEBitmapLength); + + Status = USBH_SyncPowerOnPorts(HubExtension); + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + else + { + USHORT Port; + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_STARTED; + + Port = 1; + + if (HubExtension->HubDescriptor->bNumberOfPorts >= 1) + { + do + { + USBH_SyncClearPortStatus(HubExtension, + Port++, + USBHUB_FEATURE_C_PORT_CONNECTION); + } + while (Port <= HubExtension->HubDescriptor->bNumberOfPorts); + } + } + + if (HubExtension->LowerPDO == HubExtension->RootHubPdo) + { + USBD_RegisterRootHubCallBack(HubExtension); + } + else + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION; + USBH_SubmitStatusChangeTransfer(HubExtension); + } + + goto Exit; + + ErrorExit: + + if (HubExtension->HubDescriptor) + { + ExFreePool(HubExtension->HubDescriptor); + HubExtension->HubDescriptor = NULL; + } + + if (HubExtension->SCEIrp) + { + IoFreeIrp(HubExtension->SCEIrp); + HubExtension->SCEIrp = NULL; + } + + if (HubExtension->ResetPortIrp) + { + IoFreeIrp(HubExtension->ResetPortIrp); + HubExtension->ResetPortIrp = NULL; + } + + if (HubExtension->SCEBitmap) + { + ExFreePool(HubExtension->SCEBitmap); + HubExtension->SCEBitmap = NULL; + } + + if (HubExtension->HubConfigDescriptor) + { + ExFreePool(HubExtension->HubConfigDescriptor); + HubExtension->HubConfigDescriptor = NULL; + } + + Exit: + + USBH_CompleteIrp(Irp, Status); + + return Status; +} + +NTSTATUS +NTAPI +USBH_FdoStartDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + NTSTATUS Status; + + DPRINT("USBH_FdoStartDevice: HubExtension - %p\n", HubExtension); + + HubExtension->RootHubPdo = NULL; + + Status = USBH_SyncGetRootHubPdo(HubExtension->LowerDevice, + &HubExtension->RootHubPdo, + &HubExtension->RootHubPdo2); + + if (NT_SUCCESS(Status)) + { + if (HubExtension->RootHubPdo) + { + Status = USBH_StartHubFdoDevice(HubExtension, Irp); + } + else + { + DPRINT1("USBH_FdoStartDevice: FIXME. start ParentDevice\n"); + DbgBreakPoint(); + } + } + else + { + DPRINT1("USBH_FdoStartDevice: FIXME. USBH_SyncGetRootHubPdo return - %p\n", + Status); + + DbgBreakPoint(); + USBH_CompleteIrp(Irp, Status); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_FdoQueryBusRelations(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PDEVICE_RELATIONS DeviceRelations = NULL; + NTSTATUS Status = STATUS_SUCCESS; + LIST_ENTRY GhostPdoList; + KIRQL OldIrql; + PLIST_ENTRY PdoList; + UCHAR NumberPorts; + USHORT Port; + PUSBHUB_PORT_DATA PortData; + PDEVICE_OBJECT PdoDevice; + PUSBHUB_PORT_PDO_EXTENSION PdoExtension; + NTSTATUS NtStatus; + LONG SerialNumber; + LONG DeviceHandle; + USB_PORT_STATUS UsbPortStatus; + PLIST_ENTRY Entry; + + DPRINT("USBH_FdoQueryBusRelations: HubFlags - %p\n", HubExtension->HubFlags); + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED)) + { + Status = STATUS_INVALID_DEVICE_STATE; + goto RelationsWorker; + } + + if (!HubExtension->HubDescriptor) + { + Status = STATUS_UNSUCCESSFUL; + goto RelationsWorker; + } + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION)) + { + DPRINT("USBH_FdoQueryBusRelations: Skip enumeration\n"); + goto RelationsWorker; + } + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts; + DPRINT("USBH_FdoQueryBusRelations: NumberPorts - %x\n", NumberPorts); + + DeviceRelations = ExAllocatePoolWithTag(NonPagedPool, + sizeof(ULONG) + NumberPorts * sizeof(PDEVICE_OBJECT), + USB_HUB_TAG); + + if (!DeviceRelations) + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED;//0xFF7FFFFF + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE); + } + + Status = STATUS_INSUFFICIENT_RESOURCES; + goto RelationsWorker; + } + + RtlZeroMemory(DeviceRelations, sizeof(ULONG) + NumberPorts * sizeof(PDEVICE_OBJECT)); + + DeviceRelations->Count = 0; + +EnumStart: + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING) + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED; + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE); + } + + Status = STATUS_SUCCESS; + goto RelationsWorker; + } + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_ENUM_POST_RECOVER; + + PortData = HubExtension->PortData; + Port = 1; + + while (Port <= NumberPorts) + { + DPRINT("USBH_FdoQueryBusRelations: Port - %x, ConnectStatus - %x\n", + Port, + PortData->PortStatus.UsbPortStatus.ConnectStatus); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) + { + goto NextPort; + } + + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortData->PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + if (!NT_SUCCESS(Status)) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED; + DeviceRelations->Count = 0; + goto EnumStart; + } + + PdoDevice = PortData->DeviceObject; + + if (PortData->DeviceObject) + { + PdoExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + + if (PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT) + { + PortData->PortStatus.UsbPortStatus.ConnectStatus = 1; + } + } + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) + { + DPRINT1("USBH_FdoQueryBusRelations: DbgBreakPoint() \n"); + DbgBreakPoint(); + } + + if (!PortData->PortStatus.UsbPortStatus.ConnectStatus) + { + if (PdoDevice) + { + PdoExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + + PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING; + PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT; + + SerialNumber = InterlockedExchange((PLONG)&PdoExtension->SerialNumber, + 0); + + if (SerialNumber) + { + ExFreePool((PVOID)SerialNumber); + } + + DeviceHandle = InterlockedExchange((PLONG)&PdoExtension->DeviceHandle, + 0); + + if (DeviceHandle) + { + USBD_RemoveDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)DeviceHandle, + 0); + + USBH_SyncDisablePort(HubExtension, Port); + } + } + + PortData->DeviceObject = NULL; + PortData->ConnectionStatus = NoDeviceConnected; + goto NextPort; + } + + if (PdoDevice) + { + ObReferenceObject(PdoDevice); + + PdoDevice->Flags |= DO_POWER_PAGABLE; + PdoDevice->Flags &= ~DO_DEVICE_INITIALIZING; + + DeviceRelations->Objects[DeviceRelations->Count++] = PdoDevice; + + PdoExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + PdoExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D1_OR_D2; + + goto NextPort; + } + + USBH_Wait(100); + + NtStatus = USBH_SyncResetPort(HubExtension, Port); + + if (!NT_SUCCESS(NtStatus)) + { + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB) + { + PortData->DeviceObject = NULL; + PortData->ConnectionStatus = NoDeviceConnected; + goto NextPort; + } + } + else + { + NtStatus = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortData->PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + UsbPortStatus = PortData->PortStatus.UsbPortStatus; + + if (NT_SUCCESS(NtStatus)) + { + ULONG ix = 0; + + for (NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, 0); + NtStatus < 0; + NtStatus = USBH_CreateDevice(HubExtension, Port, UsbPortStatus, ix)) + { + ++ix; + + USBH_Wait(500); + + if (ix >= 3) + { + goto AddObject; + } + + if (PortData->DeviceObject) + { + IoDeleteDevice(PortData->DeviceObject); + PortData->DeviceObject = NULL; + PortData->ConnectionStatus = NoDeviceConnected; + } + + USBH_SyncResetPort(HubExtension, Port); + } + + if (PortData->DeviceObject) + { + PdoExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortData->DeviceObject->DeviceExtension; + + if (!(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_LOW_SPEED) && + !(PdoExtension->PortPdoFlags & USBHUB_PDO_FLAG_PORT_HIGH_SPEED) && + !(HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB)) + { + DPRINT1("USBH_FdoQueryBusRelations: FIXME USBH_DeviceIs2xDualMode()\n"); + + if (0)//USBH_DeviceIs2xDualMode(PdoExtension)) + { + PdoExtension->PortPdoFlags |= USBHUB_PDO_FLAG_HS_USB1_DUALMODE; + } + } + } + + AddObject: + + if (NtStatus >= 0) + { + ObReferenceObject(PortData->DeviceObject); + + DeviceRelations->Objects[DeviceRelations->Count] = PortData->DeviceObject; + + PortData->DeviceObject->Flags |= DO_POWER_PAGABLE; + PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + ++DeviceRelations->Count; + + PortData->ConnectionStatus = DeviceConnected; + + goto NextPort; + } + } + } + + PortData->ConnectionStatus = DeviceFailedEnumeration; + + if ((USBH_SyncDisablePort(HubExtension, Port) & 0xC0000000) == 0xC0000000) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED; + } + + if (PortData->DeviceObject) + { + ObReferenceObject(PortData->DeviceObject); + PortData->DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + DeviceRelations->Objects[DeviceRelations->Count++] = PortData->DeviceObject; + } + + NextPort: + ++Port; + ++PortData; + } + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_NOT_ENUMERATED; + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE); + } + +RelationsWorker: + + Irp->IoStatus.Status = Status; + + if (!NT_SUCCESS(Status)) + { + Irp->IoStatus.Information = 0; + + if (DeviceRelations) + { + ExFreePool(DeviceRelations); + } + + USBH_CompleteIrp(Irp, Status); + + return Status; + } + + KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &OldIrql); + + if (DeviceRelations && DeviceRelations->Count) + { + Port = 0; + + do + { + PdoDevice = DeviceRelations->Objects[Port]; + Entry = HubExtension->PdoList.Flink; + + if (Entry == &HubExtension->PdoList) + { + PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_DEVICE_PRESENT; + } + else + { + PUSBHUB_PORT_PDO_EXTENSION pdoExtension; + + while (TRUE) + { + pdoExtension = CONTAINING_RECORD(Entry, + USBHUB_PORT_PDO_EXTENSION, + PortLink); + + if (pdoExtension == (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension) + { + break; + } + + Entry = Entry->Flink; + + if (Entry == &HubExtension->PdoList) + { + PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_DEVICE_PRESENT; + goto PortNext; + } + } + + PdoExt(PdoDevice)->EnumFlags |= USBHUB_ENUM_FLAG_GHOST_DEVICE; + } + + PortNext: + ++Port; + } + while (Port < DeviceRelations->Count); + + Port = 0; + + if (DeviceRelations->Count) + { + do + { + PdoDevice = DeviceRelations->Objects[Port]; + + ++Port; + + if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE) + { + while (Port < DeviceRelations->Count) + { + DeviceRelations->Objects[Port-1] = DeviceRelations->Objects[Port]; + ++Port; + } + + ObDereferenceObject(PdoDevice); + + --DeviceRelations->Count; + + if (PdoExt(PdoDevice)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT) + { + PdoExt(PdoDevice)->EnumFlags &= ~USBHUB_ENUM_FLAG_GHOST_DEVICE; + } + } + } + while (Port < DeviceRelations->Count); + } + } + + Irp->IoStatus.Information = (ULONG)DeviceRelations; + + InitializeListHead(&GhostPdoList); + PdoList = &HubExtension->PdoList; + + while (!IsListEmpty(PdoList)) + { + Entry = RemoveHeadList(PdoList); + + PdoExtension = CONTAINING_RECORD(Entry, + USBHUB_PORT_PDO_EXTENSION, + PortLink); + + PdoExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT; + + if (PdoExtension->EnumFlags & USBHUB_ENUM_FLAG_GHOST_DEVICE) + { + InsertTailList(&GhostPdoList, &PdoExtension->PortLink); + } + } + + KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, OldIrql); + + while (TRUE) + { + if (IsListEmpty(&GhostPdoList)) + { + break; + } + + Entry = RemoveHeadList(&GhostPdoList); + + PdoExtension = CONTAINING_RECORD(Entry, + USBHUB_PORT_PDO_EXTENSION, + PortLink); + + IoDeleteDevice(PdoExtension->Common.SelfDevice); + } + + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + return Status; +} + +NTSTATUS +NTAPI +USBH_FdoStopDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + DPRINT1("USBH_FdoStopDevice: UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + return 0; +} + +NTSTATUS +NTAPI +USBH_FdoRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSB_HUB_DESCRIPTOR HubDescriptor; + PUSBHUB_PORT_DATA PortData; + USHORT NumPorts; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + NTSTATUS Status; + + DPRINT("USBH_FdoRemoveDevice: HubExtension - %p\n", HubExtension); + + PortData = HubExtension->PortData; + + if (PortData) + { + HubDescriptor = HubExtension->HubDescriptor; + + if (HubDescriptor) + { + if (HubDescriptor->bNumberOfPorts) + { + NumPorts = HubDescriptor->bNumberOfPorts; + + do + { + PortDevice = PortData->DeviceObject; + + if (PortDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + PortData->PortStatus.AsULONG = 0; + PortData->DeviceObject = NULL; + + PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT; + + USBH_PdoRemoveDevice(PortExtension, HubExtension); + } + + ++PortData; + --NumPorts; + } + while (NumPorts); + } + } + } + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + USBH_FdoCleanup(HubExtension); + } + + if (HubExtension->PortData) + { + ExFreePool(HubExtension->PortData); + HubExtension->PortData = NULL; + + } + + DPRINT1("USBH_FdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME. \n"); + + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + + IoDetachDevice(HubExtension->LowerDevice); + IoDeleteDevice(HubExtension->Common.SelfDevice); + + return Status; +} + +VOID +NTAPI +USBH_FdoSurpriseRemoveDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSBHUB_PORT_DATA PortData; + ULONG NumberPorts; + ULONG Port; + + DPRINT("USBH_FdoSurpriseRemoveDevice: HubExtension - %p, Irp - %p\n", + HubExtension, + Irp); + + if (!HubExtension->PortData || + !HubExtension->HubDescriptor) + { + return; + } + + if (!HubExtension->HubDescriptor->bNumberOfPorts) + { + return; + } + + PortData = HubExtension->PortData; + NumberPorts = HubExtension->HubDescriptor->bNumberOfPorts; + + for (Port = 0; Port < NumberPorts; Port++) + { + if (PortData[Port].DeviceObject) + { + PortExtension = PdoExt(PortData[Port].DeviceObject); + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DELETE_PENDING; + PortExtension->EnumFlags &= ~USBHUB_ENUM_FLAG_DEVICE_PRESENT; + + PortData[Port].DeviceObject = NULL; + PortData[Port].ConnectionStatus = NoDeviceConnected; + } + } +} + +NTSTATUS +NTAPI +USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + ULONG IdType; + ULONG Index = 0; + WCHAR Buffer[200]; + PVOID Id = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType; + + RtlZeroMemory(Buffer, 200 * sizeof(WCHAR)); + + switch (IdType) + { + case BusQueryDeviceID: + DPRINT("USBH_PdoQueryId: BusQueryDeviceID\n"); + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED) + { + Index = swprintf(Buffer, L"USB\\Vid_0000&Pid0000") + 2; + } + else + { + Index = swprintf(Buffer, + L"USB\\Vid_%04x&Pid_%04x", + PortExtension->DeviceDescriptor.idVendor, + PortExtension->DeviceDescriptor.idProduct) + 2; + } + + Id = ExAllocatePool(PagedPool, Index * sizeof(WCHAR)); + + if (!Id) + { + break; + } + + RtlZeroMemory(Id, Index * sizeof(WCHAR)); + RtlCopyMemory(Id, Buffer, (Index-2) * sizeof(WCHAR)); + + //DPRINT("USBH_PdoQueryId: BusQueryDeviceID - %S\n", Id); + break; + + case BusQueryHardwareIDs: + DPRINT("USBH_PdoQueryId: BusQueryHardwareIDs\n"); + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED) + { + Index = swprintf(Buffer, L"USB\\UNKNOWN") + 2; + } + else + { + Index += swprintf(&Buffer[Index], + L"USB\\Vid_%04x&Pid_%04x&Rev_%04x", + PortExtension->DeviceDescriptor.idVendor, + PortExtension->DeviceDescriptor.idProduct, + PortExtension->DeviceDescriptor.bcdDevice) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\Vid_%04x&Pid_%04x", + PortExtension->DeviceDescriptor.idVendor, + PortExtension->DeviceDescriptor.idProduct) + 2; + } + + Id = ExAllocatePool(PagedPool, Index * sizeof(WCHAR)); + + if (!Id) + { + break; + } + + RtlZeroMemory(Id, Index * sizeof(WCHAR)); + RtlCopyMemory(Id, Buffer, (Index-2) * sizeof(WCHAR)); + + break; + + case BusQueryCompatibleIDs: + DPRINT("USBH_PdoQueryId: BusQueryCompatibleIDs\n"); + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED) + { + Index = swprintf(Buffer, L"USB\\UNKNOWN") + 2; + } + else if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_MULTI_INTERFACE) + { + Index += swprintf(&Buffer[Index], + L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x", + PortExtension->InterfaceDescriptor.bInterfaceClass, + PortExtension->InterfaceDescriptor.bInterfaceSubClass, + PortExtension->InterfaceDescriptor.bInterfaceProtocol) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\DevClass_%02x&SubClass_%02x", + PortExtension->InterfaceDescriptor.bInterfaceClass, + PortExtension->InterfaceDescriptor.bInterfaceSubClass) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\DevClass_%02x", + PortExtension->InterfaceDescriptor.bInterfaceClass) + 1; + + Index += swprintf(&Buffer[Index], L"USB\\COMPOSITE") + 2; + } + else + { + Index += swprintf(&Buffer[Index], + L"USB\\Class_%02x&SubClass_%02x&Prot_%02x", + PortExtension->InterfaceDescriptor.bInterfaceClass, + PortExtension->InterfaceDescriptor.bInterfaceSubClass, + PortExtension->InterfaceDescriptor.bInterfaceProtocol) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\Class_%02x&SubClass_%02x", + PortExtension->InterfaceDescriptor.bInterfaceClass, + PortExtension->InterfaceDescriptor.bInterfaceSubClass) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\Class_%02x", + PortExtension->InterfaceDescriptor.bInterfaceClass) + 2; + } + + Id = ExAllocatePool(PagedPool, Index * sizeof(WCHAR)); + + if (!Id) + { + break; + } + + RtlZeroMemory(Id, Index * sizeof(WCHAR)); + RtlCopyMemory(Id, Buffer, (Index-2) * sizeof(WCHAR)); + + break; + + case BusQueryInstanceID: + DPRINT("USBH_PdoQueryId: BusQueryInstanceID\n"); + + if (PortExtension->SerialNumber) + { + Id = ExAllocatePoolWithTag(PagedPool, + PortExtension->SN_DescriptorLength + 2, + USB_HUB_TAG); + + if (Id) + { + RtlZeroMemory(Id, PortExtension->SN_DescriptorLength + 2); + + RtlCopyMemory(Id, + PortExtension->SerialNumber, + PortExtension->SN_DescriptorLength - 2); + } + } + else + { + Id = ExAllocatePoolWithTag(PagedPool, + 4 * sizeof(WCHAR) + 2, + USB_HUB_TAG); + + if (Id) + { + RtlZeroMemory(Id, 4 * sizeof(WCHAR) + 2); + + RtlCopyMemory(Id, + &PortExtension->InstanceID, + 4 * sizeof(WCHAR)); + } + } + + break; + + default: + DPRINT1("USBH_PdoQueryId: unknown query id type 0x%lx\n", IdType); + return Irp->IoStatus.Status; + } + + Irp->IoStatus.Information = (ULONG)Id; + + if (!Id) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + USBPORT_DumpingIDs(Id); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoQueryDeviceText(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PDEVICE_OBJECT DeviceObject; + PIO_STACK_LOCATION IoStack; + DEVICE_TEXT_TYPE DeviceTextType; + USHORT LanguageId; + PUSB_STRING_DESCRIPTOR Descriptor; + PVOID DeviceText; + UCHAR iProduct = 0; + NTSTATUS Status; + ULONG NumSymbols; + ULONG Length; + + DPRINT("USBH_PdoQueryDeviceText ... \n"); + + DeviceObject = PortExtension->Common.SelfDevice; + IoStack = IoGetCurrentIrpStackLocation(Irp); + DeviceTextType = IoStack->Parameters.QueryDeviceText.DeviceTextType; + + if (DeviceTextType != DeviceTextDescription && + DeviceTextType != DeviceTextLocationInformation) + { + return Irp->IoStatus.Status; + } + + LanguageId = IoStack->Parameters.QueryDeviceText.LocaleId; + + if (!LanguageId) + { + LanguageId = 0x0409; + } + + iProduct = PortExtension->DeviceDescriptor.iProduct; + + if (PortExtension->DeviceHandle && iProduct && + !PortExtension->IgnoringHwSerial && + !(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED)) + { + Descriptor = ExAllocatePoolWithTag(NonPagedPool, + 0xFF, + USB_HUB_TAG); + + if (Descriptor) + { + RtlZeroMemory(Descriptor, 0xFF); + + for (Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId); + ; + Status = USBH_CheckDeviceLanguage(DeviceObject, 0x0409)) + { + if (NT_SUCCESS(Status)) + { + Status = USBH_SyncGetStringDescriptor(DeviceObject, + iProduct, + LanguageId, + Descriptor, + 0xFF, + 0, + 1); + + if (NT_SUCCESS(Status)) + { + break; + } + } + + if (LanguageId == 0x0409) + { + goto Exit; + } + + LanguageId = 0x0409; + } + + if (Descriptor->bLength <= 2) + { + Status = STATUS_UNSUCCESSFUL; + } + + if (NT_SUCCESS(Status)) + { + DeviceText = ExAllocatePoolWithTag(PagedPool, + Descriptor->bLength, + USB_HUB_TAG); + + if (DeviceText) + { + RtlZeroMemory(DeviceText, Descriptor->bLength); + + RtlCopyMemory(DeviceText, + Descriptor->bString, + Descriptor->bLength - 2); + + Irp->IoStatus.Information = (ULONG)DeviceText; + + DPRINT("USBH_PdoQueryDeviceText: Descriptor->bString - %S\n", + DeviceText); + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + Exit: + + ExFreePool(Descriptor); + + if (NT_SUCCESS(Status)) + { + return Status; + } + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + Status = STATUS_NOT_SUPPORTED; + } + + if (GenericUSBDeviceString) + { + NumSymbols = 0; + + if (*(PWCHAR)GenericUSBDeviceString) + { + do + { + ++NumSymbols; + } + while (*((PWCHAR)GenericUSBDeviceString + NumSymbols)); + } + + Length = NumSymbols * sizeof(WCHAR) + 2; + + DeviceText = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG); + + if (DeviceText) + { + RtlZeroMemory(DeviceText, Length); + + RtlCopyMemory(DeviceText, + GenericUSBDeviceString, + NumSymbols * sizeof(WCHAR)); + + Status = STATUS_SUCCESS; + + Irp->IoStatus.Information = (ULONG)DeviceText; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_SymbolicLink(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN const GUID * InterfaceClassGuid, + IN BOOLEAN IsEnable) +{ + NTSTATUS Status = STATUS_SUCCESS; + PVOID NameBuffer; + + DPRINT("USBH_SymbolicLink ... \n"); + + if (IsEnable) + { + Status = IoRegisterDeviceInterface(PortExtension->Common.SelfDevice, + InterfaceClassGuid, + NULL, + &PortExtension->SymbolicLinkName); + + if (NT_SUCCESS(Status)) + { + USBH_SetPdoRegistryParameter(PortExtension->Common.SelfDevice, + L"SymbolicName", + PortExtension->SymbolicLinkName.Buffer, + PortExtension->SymbolicLinkName.Length, + REG_SZ, + PLUGPLAY_REGKEY_DEVICE); + + Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName, + TRUE); + } + } + else + { + NameBuffer = PortExtension->SymbolicLinkName.Buffer; + + if (NameBuffer && NameBuffer != (PVOID)-2) + { + Status = IoSetDeviceInterfaceState(&PortExtension->SymbolicLinkName, + FALSE); + + ExFreePool(PortExtension->SymbolicLinkName.Buffer); + + PortExtension->SymbolicLinkName.Buffer = (PVOID)-2; + } + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_RestoreDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN BOOLEAN IsKeepDeviceData) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_PORT_DATA PortData; + NTSTATUS Status; + ULONG ix = 0; + + DPRINT("USBH_RestoreDevice ... \n"); + + HubExtension = PortExtension->HubExtension; + + if (!HubExtension) + { + Status = STATUS_UNSUCCESSFUL; + return Status; + } + + PortData = &HubExtension->PortData[PortExtension->PortNumber - 1]; + + if ( PortExtension->Common.SelfDevice == PortData->DeviceObject ) + { + Status = STATUS_UNSUCCESSFUL; + return Status; + } + + Status = USBH_SyncGetPortStatus(HubExtension, + PortExtension->PortNumber, + &PortData->PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + if (NT_SUCCESS(Status)) + { + do + { + Status = USBH_ResetDevice((PUSBHUB_FDO_EXTENSION)HubExtension, + PortExtension->PortNumber, + IsKeepDeviceData, + ix++); + + if (NT_SUCCESS(Status)) + { + break; + } + + if (Status == STATUS_NO_SUCH_DEVICE) + { + break; + } + + USBH_Wait(1000); + } + while (ix < 3); + } + + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_POWER_D3; + + if (NT_SUCCESS(Status)) + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_PORT_RESTORE_FAIL; + } + else + { + PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_INIT_PORT_FAILED | + USBHUB_PDO_FLAG_PORT_RESTORE_FAIL); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoStartDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + const GUID * Guid; + NTSTATUS Status; + + DPRINT("USBH_PdoStartDevice: PortExtension - %p\n", PortExtension); + + if (!PortExtension->HubExtension && + PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3) + { + PortExtension->HubExtension = PortExtension->RootHubExtension; + } + + HubExtension = PortExtension->HubExtension; + + if (HubExtension) + { + USBHUB_SetDeviceHandleData(HubExtension, + PortExtension->Common.SelfDevice, + PortExtension->DeviceHandle); + } + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE) + { + Guid = &GUID_DEVINTERFACE_USB_HUB; + } + else + { + Guid = &GUID_DEVINTERFACE_USB_DEVICE; + } + + Status = USBH_SymbolicLink(PortExtension, Guid, TRUE); + + if (NT_SUCCESS(Status)) + { + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REG_DEV_INTERFACE; + } + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3) + { + Status = USBH_RestoreDevice(PortExtension, 0); + } + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_DEVICE_STARTED; + + PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0; + + DPRINT1("USBH_PdoStartDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME. \n"); + //IoWMIRegistrationControl() + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoRemoveDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + NTSTATUS Status = STATUS_SUCCESS; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExt; + PUSBHUB_PORT_DATA PortData; + PIRP IdleNotificationIrp; + PIRP WakeIrp; + LONG DeviceHandle; + PDEVICE_OBJECT Pdo; + LONG SerialNumber; + USHORT Port; + KIRQL Irql; + + DPRINT("USBH_PdoRemoveDevice ... \n"); + + PortDevice = PortExtension->Common.SelfDevice; + PortExtension->HubExtension = NULL; + + Port = PortExtension->PortNumber; + + if (HubExtension) + { + if (HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0) + { + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + USBH_HubSetD0(HubExtension); + } + } + } + + IoAcquireCancelSpinLock(&Irql); + IdleNotificationIrp = PortExtension->IdleNotificationIrp; + + if (IdleNotificationIrp) + { + PortExtension->IdleNotificationIrp = NULL; + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_IDLE_NOTIFICATION; + + if (IdleNotificationIrp->Cancel) + { + IdleNotificationIrp = NULL; + } + + if (IdleNotificationIrp) + { + IoSetCancelRoutine(IdleNotificationIrp, NULL); + } + } + + WakeIrp = PortExtension->PdoWaitWakeIrp; + + if (WakeIrp) + { + PortExtension->PdoWaitWakeIrp = NULL; + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_WAIT_WAKE; + + if (WakeIrp->Cancel || !IoSetCancelRoutine(WakeIrp, NULL)) + { + WakeIrp = NULL; + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + } + } + + IoReleaseCancelSpinLock(Irql); + + if (IdleNotificationIrp) + { + IdleNotificationIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(IdleNotificationIrp, IO_NO_INCREMENT); + } + + if (WakeIrp) + { + USBH_CompletePowerIrp(HubExtension, WakeIrp, STATUS_CANCELLED); + } + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_POWER_D3; + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE) + { + Status = USBH_SymbolicLink(PortExtension, NULL, FALSE); + + if (NT_SUCCESS(Status)) + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE; + } + } + + DeviceHandle = InterlockedExchange((PLONG)&PortExtension->DeviceHandle, 0); + + if (DeviceHandle) + { + Status = USBD_RemoveDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)DeviceHandle, + 0); + + if (HubExtension->PortData) + { + if (HubExtension->PortData[Port - 1].DeviceObject == PortDevice) + { + USBH_SyncDisablePort(HubExtension, Port); + } + } + } + + if (NT_SUCCESS(Status)) + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_DEVICE_STARTED; + + if (HubExtension) + { + if (HubExtension->PortData) + { + PortData = &HubExtension->PortData[Port - 1]; + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_DELETE_PENDING) + { + Pdo = PortData->DeviceObject; + + if (Pdo) + { + PortData->DeviceObject = NULL; + PortData->ConnectionStatus = NoDeviceConnected; + + if (PdoExt(Pdo)->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT) + { + PortExt = PdoExt(Pdo); + + InsertTailList(&HubExtension->PdoList, + &PortExt->PortLink); + } + } + } + } + } + + if (!(PortExtension->EnumFlags & USBHUB_ENUM_FLAG_DEVICE_PRESENT)) + { + if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_NOT_CONNECTED)) + { + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_NOT_CONNECTED; + + SerialNumber = InterlockedExchange((PLONG)&PortExtension->SerialNumber, + 0); + + if (SerialNumber) + { + ExFreePool((PVOID)SerialNumber); + } + + DPRINT1("USBH_PdoRemoveDevice: call IoWMIRegistrationControl UNIMPLEMENTED. FIXME. \n"); + + if (HubExtension) + { + USBHUB_FlushAllTransfers(HubExtension); + } + + IoDeleteDevice(PortDevice); + } + } + } + + if (HubExtension) + { + DPRINT("USBH_PdoRemoveDevice: call USBH_CheckIdleDeferred()\n"); + USBH_CheckIdleDeferred(HubExtension); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoStopDevice(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + DPRINT1("USBH_PdoStopDevice: UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + return 0; +} + +NTSTATUS +NTAPI +USBH_FdoPnP(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN UCHAR Minor) +{ + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + BOOLEAN IsCheckIdle = FALSE; + + DPRINT("USBH_FdoPnP: HubExtension - %p, Irp - %p, Minor - %x\n", + HubExtension, + Irp, + Minor); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST && + (Minor == IRP_MN_REMOVE_DEVICE || Minor == IRP_MN_STOP_DEVICE)) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED; + } + + KeWaitForSingleObject(&HubExtension->IdleSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + DPRINT("USBH_FdoPnP: HubFlags - %p\n", HubExtension->HubFlags); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_GOING_IDLE) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_SUSPENDED; + } + + if ((HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0) && + (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED) && + (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) && + (Minor != IRP_MN_QUERY_DEVICE_RELATIONS || Minor != IRP_MN_STOP_DEVICE)) + { + DPRINT("USBH_FdoPnP: IsCheckIdle - TRUE\n"); + IsCheckIdle = TRUE; + USBH_HubSetD0(HubExtension); + } + + switch (Minor) + { + case IRP_MN_START_DEVICE: // 0 + DPRINT("FDO IRP_MN_START_DEVICE\n"); + IsCheckIdle = FALSE; + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_FdoStartDevice(HubExtension, Irp); + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: // 1 + DPRINT("FDO IRP_MN_QUERY_REMOVE_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_REMOVE_DEVICE: // 2 + DPRINT("FDO IRP_MN_REMOVE_DEVICE\n"); + IsCheckIdle = FALSE; + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED; + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_FdoRemoveDevice(HubExtension, Irp); + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: // 3 + DPRINT("FDO IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_STOP_DEVICE: // 4 + DPRINT("FDO IRP_MN_STOP_DEVICE\n"); + IsCheckIdle = FALSE; + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_FdoStopDevice(HubExtension, Irp); + break; + + case IRP_MN_QUERY_STOP_DEVICE: // 5 + DPRINT("FDO IRP_MN_QUERY_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_CANCEL_STOP_DEVICE: // 6 + DPRINT("FDO IRP_MN_CANCEL_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: // 7 + DPRINT("FDO IRP_MN_QUERY_DEVICE_RELATIONS\n"); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations) + { + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + } + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_HUB_BUSY; + + IsCheckIdle = TRUE; + DPRINT("USBH_FdoPnP: IsCheckIdle - TRUE\n"); + + Status = USBH_FdoQueryBusRelations(HubExtension, Irp); + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HUB_BUSY; + break; + + case IRP_MN_QUERY_INTERFACE: // 8 + DPRINT("FDO IRP_MN_QUERY_INTERFACE\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_CAPABILITIES: // 9 + DPRINT("FDO IRP_MN_QUERY_CAPABILITIES\n"); + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBH_QueryCapsComplete, + HubExtension, + TRUE, + FALSE, + FALSE); + + Status = IoCallDriver(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_RESOURCES: // 10 + DPRINT("FDO IRP_MN_QUERY_RESOURCES\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 11 + DPRINT("FDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_DEVICE_TEXT: // 12 + DPRINT("FDO IRP_MN_QUERY_DEVICE_TEXT\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 13 + DPRINT("FDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_READ_CONFIG: // 15 + DPRINT("FDO IRP_MN_READ_CONFIG\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_WRITE_CONFIG: // 16 + DPRINT("FDO IRP_MN_WRITE_CONFIG\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_EJECT: // 17 + DPRINT("FDO IRP_MN_EJECT\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_SET_LOCK: // 18 + DPRINT("FDO IRP_MN_SET_LOCK\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_ID: // 19 + DPRINT("FDO IRP_MN_QUERY_ID\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_PNP_DEVICE_STATE: // 20 + DPRINT("FDO IRP_MN_QUERY_PNP_DEVICE_STATE\n"); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) + { + Irp->IoStatus.Information |= PNP_DEVICE_FAILED; + } + + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_QUERY_BUS_INFORMATION: // 21 + DPRINT("FDO IRP_MN_QUERY_BUS_INFORMATION\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: // 22 + DPRINT("FDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + case IRP_MN_SURPRISE_REMOVAL: // 23 + DPRINT("FDO IRP_MN_SURPRISE_REMOVAL\n"); + USBH_FdoSurpriseRemoveDevice(HubExtension, Irp); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + + default: + DPRINT("FDO unknown IRP_MN_???\n"); + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + } + + KeReleaseSemaphore(&HubExtension->IdleSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (IsCheckIdle) + { + DPRINT("USBH_FdoPnP: call USBH_CheckIdleDeferred()\n"); + USBH_CheckIdleDeferred(HubExtension); + } + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_STATE_CHANGING; + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoPnP(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp, + IN UCHAR Minor, + OUT BOOLEAN * IsCompleteIrp) +{ + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + PPNP_BUS_INFORMATION BusInfo; + PDEVICE_CAPABILITIES DeviceCapabilities; + USHORT Size; + USHORT Version; + PUSBHUB_FDO_EXTENSION HubExtension; + PDEVICE_RELATIONS DeviceRelation; + + DPRINT("USBH_PdoPnP: PortExtension - %p, Irp - %p, Minor - %d\n", + PortExtension, + Irp, + Minor); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + *IsCompleteIrp = TRUE; + + switch (Minor) + { + case IRP_MN_START_DEVICE: // 0 + DPRINT("PDO IRP_MN_START_DEVICE\n"); + return USBH_PdoStartDevice(PortExtension, Irp); + + case IRP_MN_QUERY_REMOVE_DEVICE: // 1 + DPRINT("PDO IRP_MN_QUERY_REMOVE_DEVICE\n"); + return STATUS_SUCCESS; + + case IRP_MN_REMOVE_DEVICE: // 2 + DPRINT("PDO IRP_MN_REMOVE_DEVICE\n"); + return USBH_PdoRemoveDevice(PortExtension, PortExtension->HubExtension); + + case IRP_MN_CANCEL_REMOVE_DEVICE: // 3 + DPRINT("PDO IRP_MN_CANCEL_REMOVE_DEVICE\n"); + return STATUS_SUCCESS; + + case IRP_MN_STOP_DEVICE: // 4 + DPRINT("PDO IRP_MN_STOP_DEVICE\n"); + return USBH_PdoStopDevice(PortExtension, Irp); + + case IRP_MN_QUERY_STOP_DEVICE: // 5 + DPRINT("PDO IRP_MN_QUERY_STOP_DEVICE\n"); + return STATUS_SUCCESS; + + case IRP_MN_CANCEL_STOP_DEVICE: // 6 + DPRINT("PDO IRP_MN_CANCEL_STOP_DEVICE\n"); + return STATUS_SUCCESS; + + case IRP_MN_QUERY_DEVICE_RELATIONS: // 7 + DPRINT("PDO IRP_MN_QUERY_DEVICE_RELATIONS\n"); + + if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + { + return Irp->IoStatus.Status; + } + + DeviceRelation = ExAllocatePoolWithTag(PagedPool, + sizeof(DEVICE_RELATIONS), + USB_HUB_TAG); + + if (DeviceRelation) + { + RtlZeroMemory(DeviceRelation, sizeof(DEVICE_RELATIONS)); + + DeviceRelation->Count = 1; + DeviceRelation->Objects[0] = PortExtension->Common.SelfDevice; + + ObReferenceObject(DeviceRelation->Objects[0]); + + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation; + break; + + case IRP_MN_QUERY_INTERFACE: // 8 + DPRINT("PDO IRP_MN_QUERY_INTERFACE\n"); + + *IsCompleteIrp = 0; + + if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType, + &USB_BUS_INTERFACE_USBDI_GUID)) + { + IoStack->Parameters.QueryInterface.InterfaceSpecificData = PortExtension->DeviceHandle; + } + + HubExtension = PortExtension->HubExtension; + + if (!HubExtension) + { + HubExtension = PortExtension->RootHubExtension; + } + + Status = USBH_PassIrp(HubExtension->RootHubPdo, Irp); + break; + + case IRP_MN_QUERY_CAPABILITIES: // 9 + DPRINT("PDO IRP_MN_QUERY_CAPABILITIES\n"); + + DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities; + + Size = DeviceCapabilities->Size; + Version = DeviceCapabilities->Version; + + RtlCopyMemory(DeviceCapabilities, + &PortExtension->Capabilities, + sizeof(DEVICE_CAPABILITIES)); + + DeviceCapabilities->Size = Size; + DeviceCapabilities->Version = Version; + + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_RESOURCES: // 10 + DPRINT("PDO IRP_MN_QUERY_RESOURCES\n"); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 11 + DPRINT("PDO IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + PortExtension->PortPdoFlags |= 0x04000000; + + /* FIXME HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Enum\USB\ + Vid_????&Pid_????\????????????\Device Parameters\ + if (ExtPropDescSemaphore) + */ + + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_DEVICE_TEXT: // 12 + DPRINT("PDO IRP_MN_QUERY_DEVICE_TEXT\n"); + return USBH_PdoQueryDeviceText(PortExtension, Irp); + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 13 + DPRINT("PDO IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_READ_CONFIG: // 15 + DPRINT("PDO IRP_MN_READ_CONFIG\n"); + DbgBreakPoint(); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_WRITE_CONFIG: // 16 + DPRINT("PDO IRP_MN_WRITE_CONFIG\n"); + DbgBreakPoint(); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_EJECT: // 17 + DPRINT("PDO IRP_MN_EJECT\n"); + DbgBreakPoint(); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_SET_LOCK: // 18 + DPRINT("PDO IRP_MN_SET_LOCK\n"); + DbgBreakPoint(); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_QUERY_ID: // 19 + DPRINT("PDO IRP_MN_QUERY_ID\n"); + return USBH_PdoQueryId(PortExtension, Irp); + + case IRP_MN_QUERY_PNP_DEVICE_STATE: // 20 + DPRINT("PDO IRP_MN_QUERY_PNP_DEVICE_STATE\n"); + if (PortExtension->PortPdoFlags & (USBHUB_PDO_FLAG_INSUFFICIENT_PWR | + USBHUB_PDO_FLAG_OVERCURRENT_PORT | + USBHUB_PDO_FLAG_PORT_RESTORE_FAIL | + USBHUB_PDO_FLAG_INIT_PORT_FAILED)) + { + Irp->IoStatus.Information |= PNP_DEVICE_FAILED; + } + + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_BUS_INFORMATION: // 21 + DPRINT("PDO IRP_MN_QUERY_BUS_INFORMATION\n"); + + BusInfo = ExAllocatePoolWithTag(PagedPool, + sizeof(PNP_BUS_INFORMATION), + USB_HUB_TAG); + + if (!BusInfo) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(BusInfo, sizeof(PNP_BUS_INFORMATION)); + + RtlCopyMemory(&BusInfo->BusTypeGuid, + &GUID_BUS_TYPE_USB, + sizeof(BusInfo->BusTypeGuid)); + + BusInfo->LegacyBusType = PNPBus; + BusInfo->BusNumber = 0; + + Irp->IoStatus.Information = (ULONG_PTR)BusInfo; + Status = STATUS_SUCCESS; + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: // 22 + DPRINT("PDO IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); + DbgBreakPoint(); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_SURPRISE_REMOVAL: // 23 + DPRINT("PDO IRP_MN_SURPRISE_REMOVAL\n"); + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REG_DEV_INTERFACE) + { + Status = USBH_SymbolicLink(PortExtension, NULL, FALSE); + + if (NT_SUCCESS(Status)) + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REG_DEV_INTERFACE; + } + } + + Status = STATUS_SUCCESS; + break; + + default: + DPRINT("PDO unknown IRP_MN_???\n"); + Status = Irp->IoStatus.Status; + break; + } + + return Status; +} diff --git a/reactos/drivers/usb/usbhub_new/power.c b/reactos/drivers/usb/usbhub_new/power.c new file mode 100644 index 00000000000..73cb962237e --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/power.c @@ -0,0 +1,821 @@ +#include "usbhub.h" + +//#define NDEBUG +#include + +VOID +NTAPI +USBH_CompletePowerIrp(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN NTSTATUS NtStatus) +{ + DPRINT("USBH_CompletePowerIrp: HubExtension - %p, Irp - %p, NtStatus - %p\n", + HubExtension, + Irp, + NtStatus); + + Irp->IoStatus.Status = NtStatus; + + PoStartNextPowerIrp(Irp); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +VOID +NTAPI +USBH_HubCancelWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + DPRINT("USBH_HubCancelWakeIrp: HubExtension - %p, Irp - %p\n", + HubExtension, + Irp); + + IoCancelIrp(Irp); + + if (InterlockedExchange((PLONG)&HubExtension->FdoWaitWakeLock, 1)) + { + PoStartNextPowerIrp(Irp); + Irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } +} + +VOID +NTAPI +USBH_HubESDRecoverySetD3Completion(IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus) +{ + DPRINT("USBH_HubESDRecoverySetD3Completion ... \n"); + + KeSetEvent((PRKEVENT)Context, + EVENT_INCREMENT, + FALSE); +} + +NTSTATUS +NTAPI +USBH_HubSetD0(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSBHUB_FDO_EXTENSION RootHubDevExt; + NTSTATUS Status; + KEVENT Event; + POWER_STATE PowerState; + + DPRINT("USBH_HubSetD0: HubExtension - %p\n", HubExtension); + + RootHubDevExt = USBH_GetRootHubExtension(HubExtension); + + if (RootHubDevExt->SystemPowerState.SystemState != PowerSystemWorking) + { + Status = STATUS_INVALID_DEVICE_STATE; + return Status; + } + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST) + { + DPRINT("USBH_HubSetD0: HubFlags - %p\n", HubExtension->HubFlags); + + KeWaitForSingleObject(&HubExtension->IdleEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + PowerState.DeviceState = PowerDeviceD0; + + Status = PoRequestPowerIrp(HubExtension->LowerPDO, + IRP_MN_SET_POWER, + PowerState, + USBH_HubESDRecoverySetD3Completion, + &Event, + NULL); + + if (Status == STATUS_PENDING) + { + Status = KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + + while (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAKEUP_START) + { + USBH_Wait(10); + } + + return Status; +} + +VOID +NTAPI +USBH_IdleCancelPowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + PUSBHUB_IDLE_PORT_CANCEL_CONTEXT WorkItemIdlePower; + PIRP Irp; + + DPRINT("USBH_IdleCancelPowerHubWorker: ... \n"); + + WorkItemIdlePower = (PUSBHUB_IDLE_PORT_CANCEL_CONTEXT)Context; + + if (HubExtension && + HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 && + HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + USBH_HubSetD0(HubExtension); + } + + Irp = WorkItemIdlePower->Irp; + Irp->IoStatus.Status = STATUS_CANCELLED; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +VOID +NTAPI +USBH_HubQueuePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PLIST_ENTRY ListIrps) +{ + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + USHORT NumPorts; + USHORT Port; + PIRP WakeIrp; + KIRQL OldIrql; + + DPRINT("USBH_HubQueuePortWakeIrps ... \n"); + + NumPorts = HubExtension->HubDescriptor->bNumberOfPorts; + + InitializeListHead(ListIrps); + + IoAcquireCancelSpinLock(&OldIrql); + + if (NumPorts) + { + Port = 0; + + do + { + PortDevice = HubExtension->PortData[Port].DeviceObject; + + if (PortDevice) + { + PortExtension = PortDevice->DeviceExtension; + + WakeIrp = PortExtension->PdoWaitWakeIrp; + PortExtension->PdoWaitWakeIrp = NULL; + + if (WakeIrp) + { + DPRINT1("USBH_HubQueuePortWakeIrps: UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + } + } + + ++Port; + } + while (Port < NumPorts); + } + + IoReleaseCancelSpinLock(OldIrql); +} + +VOID +NTAPI +USBH_HubCompleteQueuedPortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PLIST_ENTRY ListIrps, + IN NTSTATUS NtStatus) +{ + DPRINT("USBH_HubCompleteQueuedPortWakeIrps ... \n"); + + while (!IsListEmpty(ListIrps)) + { + DPRINT1("USBH_HubCompleteQueuedPortWakeIrps: UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + } +} + +VOID +NTAPI +USBH_HubCompletePortWakeIrps(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN NTSTATUS NtStatus) +{ + LIST_ENTRY ListIrps; + + DPRINT("USBH_HubCompletePortWakeIrps: NtStatus - %x\n", NtStatus); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + USBH_HubQueuePortWakeIrps(HubExtension, &ListIrps); + + USBH_HubCompleteQueuedPortWakeIrps(HubExtension, + &ListIrps, + NtStatus); + } +} + +VOID +NTAPI +USBH_FdoPoRequestD0Completion(IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + + DPRINT("USBH_FdoPoRequestD0Completion ... \n"); + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + USBH_HubCompletePortWakeIrps(HubExtension, STATUS_SUCCESS); + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAKEUP_START; + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } +} + +VOID +NTAPI +USBH_CompletePortWakeIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + DPRINT1("USBH_CompletePortWakeIrpsWorker: UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); +} + +NTSTATUS +NTAPI +USBH_FdoWWIrpIoCompletion(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + NTSTATUS Status; + KIRQL OldIrql; + POWER_STATE PowerState; + LONG WakeIrp; + + DPRINT("USBH_FdoWWIrpIoCompletion: DeviceObject - %p, Irp - %p\n", + DeviceObject, + Irp); + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + Status = Irp->IoStatus.Status; + + IoAcquireCancelSpinLock(&OldIrql); + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP; + + WakeIrp = InterlockedExchange((PLONG)&HubExtension->PendingWakeIrp, + 0); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + IoReleaseCancelSpinLock(OldIrql); + + DPRINT("USBH_FdoWWIrpIoCompletion: Status - %p\n", Status); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_FdoWWIrpIoCompletion: DbgBreakPoint() \n"); + DbgBreakPoint(); + } + else + { + PowerState.DeviceState = PowerDeviceD0; + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAKEUP_START; + InterlockedIncrement(&HubExtension->PendingRequestCount); + + Status = STATUS_SUCCESS; + + PoRequestPowerIrp(HubExtension->LowerPDO, + IRP_MN_SET_POWER, + PowerState, + USBH_FdoPoRequestD0Completion, + (PVOID)HubExtension, + NULL); + } + + if (!WakeIrp) + { + if (!InterlockedExchange(&HubExtension->FdoWaitWakeLock, 1)) + { + Status = STATUS_MORE_PROCESSING_REQUIRED; + } + } + + DPRINT("USBH_FdoWWIrpIoCompletion: Status - %p\n", Status); + + IoMarkIrpPending(Irp); + + if (Status != STATUS_MORE_PROCESSING_REQUIRED) + { + PoStartNextPowerIrp(Irp); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PIO_STACK_LOCATION IoStack; + DEVICE_POWER_STATE OldDeviceState; + NTSTATUS Status; + POWER_STATE PowerState; + + DPRINT("USBH_PowerIrpCompletion: DeviceObject - %p, Irp - %p\n", + DeviceObject, + Irp); + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + PowerState = IoStack->Parameters.Power.State; + + Status = Irp->IoStatus.Status; + DPRINT("USBH_PowerIrpCompletion: Status - %p\n", Status); + + + if (Irp->PendingReturned) + { + IoMarkIrpPending(Irp); + } + + if (!NT_SUCCESS(Status)) + { + if (PowerState.DeviceState == PowerDeviceD0) + { + PoStartNextPowerIrp(Irp); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE; + } + } + else if (PowerState.DeviceState == PowerDeviceD0) + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_SET_D0_STATE; + + OldDeviceState = HubExtension->CurrentPowerState.DeviceState; + HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0; + + DPRINT("USBH_PowerIrpCompletion: OldDeviceState - %x\n", OldDeviceState); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_HIBERNATE_STATE) + { + DPRINT1("USBH_PowerIrpCompletion: USBHUB_FDO_FLAG_HIBERNATE_STATE. FIXME. \n"); + DbgBreakPoint(); + } + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_HIBERNATE_STATE; + + if (OldDeviceState == PowerDeviceD3) + { + DPRINT1("USBH_PowerIrpCompletion: PowerDeviceD3. FIXME. \n"); + DbgBreakPoint(); + } + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED) && + HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION) + { + USBH_SubmitStatusChangeTransfer(HubExtension); + } + + DPRINT("USBH_PowerIrpCompletion: Status - %p\n", Status); + + if (Status != STATUS_MORE_PROCESSING_REQUIRED) + { + PoStartNextPowerIrp(Irp); + return Status; + } + } + + return Status; +} + +VOID +NTAPI +USBH_FdoDeferPoRequestCompletion(IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus) +{ + PUSBHUB_FDO_EXTENSION Extension; + PUSBHUB_FDO_EXTENSION HubExtension = NULL; + PIRP PowerIrp; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBH_FdoDeferPoRequestCompletion ... \n"); + + Extension = (PUSBHUB_FDO_EXTENSION)Context; + + PowerIrp = Extension->PowerIrp; + + if (Extension->Common.ExtensionType == USBH_EXTENSION_TYPE_HUB) + { + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + } + + IoStack = IoGetCurrentIrpStackLocation(PowerIrp); + + if (IoStack->Parameters.Power.State.SystemState == PowerSystemWorking && + HubExtension && HubExtension->LowerPDO == HubExtension->RootHubPdo) + { + HubExtension->SystemPowerState.SystemState = PowerSystemWorking; + USBH_CheckIdleDeferred(HubExtension); + } + + IoCopyCurrentIrpStackLocationToNext(PowerIrp); + PoStartNextPowerIrp(PowerIrp); + PoCallDriver(Extension->LowerDevice, PowerIrp); +} + +NTSTATUS +NTAPI +USBH_FdoPower(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN UCHAR Minor) +{ + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + POWER_STATE PowerState; + POWER_STATE DevicePwrState; + BOOLEAN IsAllPortsD3; + PUSBHUB_PORT_DATA PortData; + PDEVICE_OBJECT PdoDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + ULONG Port; + + DPRINT("USBH_FdoPower: HubExtension - %p, Irp - %p, Minor - %x\n", + HubExtension, + Irp, + Minor); + + switch (Minor) + { + case IRP_MN_WAIT_WAKE: + DPRINT("USBH_FdoPower: IRP_MN_WAIT_WAKE\n"); + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBH_FdoWWIrpIoCompletion, + HubExtension, + TRUE, + TRUE, + TRUE); + + PoStartNextPowerIrp(Irp); + IoMarkIrpPending(Irp); + + PoCallDriver(HubExtension->LowerDevice, Irp); + + return STATUS_PENDING; + + case IRP_MN_POWER_SEQUENCE: + DPRINT("USBH_FdoPower: IRP_MN_POWER_SEQUENCE\n"); + break; + + case IRP_MN_SET_POWER: + DPRINT("USBH_FdoPower: IRP_MN_SET_POWER\n"); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + DPRINT("USBH_FdoPower: IRP_MN_SET_POWER/DevicePowerState\n"); + PowerState = IoStack->Parameters.Power.State; + + if (IoStack->Parameters.Power.Type == DevicePowerState) + { + DPRINT("USBH_FdoPower: PowerState - %x\n", PowerState); + + if (HubExtension->CurrentPowerState.DeviceState == PowerState.DeviceState) + { + IoCopyCurrentIrpStackLocationToNext(Irp); + PoStartNextPowerIrp(Irp); + IoMarkIrpPending(Irp); + + PoCallDriver(HubExtension->LowerDevice, Irp); + + return STATUS_PENDING; + } + + switch (PowerState.DeviceState) + { + case PowerDeviceD0: + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_SET_D0_STATE)) + { + HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE | + USBHUB_FDO_FLAG_DEVICE_STOPPING); + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_SET_D0_STATE; + + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBH_PowerIrpCompletion, + HubExtension, + TRUE, + TRUE, + TRUE); + } + else + { + IoCopyCurrentIrpStackLocationToNext(Irp); + PoStartNextPowerIrp(Irp); + } + + IoMarkIrpPending(Irp); + PoCallDriver(HubExtension->LowerDevice, Irp); + return STATUS_PENDING; + + case PowerDeviceD1: + case PowerDeviceD2: + case PowerDeviceD3: + if (HubExtension->ResetRequestCount) + { + IoCancelIrp(HubExtension->ResetPortIrp); + + KeWaitForSingleObject(&HubExtension->ResetEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + HubExtension->HubFlags |= (USBHUB_FDO_FLAG_NOT_D0_STATE | + USBHUB_FDO_FLAG_DEVICE_STOPPING); + + IoCancelIrp(HubExtension->SCEIrp); + + KeWaitForSingleObject(&HubExtension->StatusChangeEvent, + Suspended, + KernelMode, + FALSE, + NULL); + } + + HubExtension->CurrentPowerState.DeviceState = PowerState.DeviceState; + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE && + USBH_CheckIdleAbort(HubExtension, TRUE, TRUE) == TRUE) + { + HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_NOT_D0_STATE | + USBHUB_FDO_FLAG_DEVICE_STOPPING); + + HubExtension->CurrentPowerState.DeviceState = PowerDeviceD0; + + USBH_SubmitStatusChangeTransfer(HubExtension); + + PoStartNextPowerIrp(Irp); + + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE; + + KeReleaseSemaphore(&HubExtension->IdleSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + return STATUS_UNSUCCESSFUL; + } + + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBH_PowerIrpCompletion, + HubExtension, + TRUE, + TRUE, + TRUE); + + PoStartNextPowerIrp(Irp); + + IoMarkIrpPending(Irp); + PoCallDriver(HubExtension->LowerDevice, Irp); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_SUSPENSE) + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DO_SUSPENSE; + + KeReleaseSemaphore(&HubExtension->IdleSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + } + + return STATUS_PENDING; + + default: + DPRINT1("USBH_FdoPower: Unsupported PowerState.DeviceState\n"); + DbgBreakPoint(); + break; + } + } + else + { + if (PowerState.SystemState != PowerSystemWorking) + { + USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState = + PowerState.SystemState; + } + + if (PowerState.SystemState == PowerSystemHibernate) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_HIBERNATE_STATE; + } + + PortData = HubExtension->PortData; + + IsAllPortsD3 = 1; + + if (PortData) + { + if (HubExtension->HubDescriptor && + HubExtension->HubDescriptor->bNumberOfPorts) + { + Port = 0; + + while (TRUE) + { + PdoDevice = PortData[Port].DeviceObject; + + if (PdoDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + + if (PortExtension->CurrentPowerState.DeviceState != PowerDeviceD3) + { + break; + } + } + + ++Port; + + if (Port >= HubExtension->HubDescriptor->bNumberOfPorts) + { + goto Next; + } + } + + IsAllPortsD3 = FALSE; + } + } + + Next: + + if (PowerState.SystemState == PowerSystemWorking) + { + DevicePwrState.DeviceState = PowerDeviceD0; + } + else if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP || + !IsAllPortsD3) + { + DevicePwrState.DeviceState = HubExtension->DeviceState[PowerState.SystemState]; + + if (DevicePwrState.DeviceState == PowerDeviceUnspecified) + { + goto Exit; + } + } + else + { + DevicePwrState.DeviceState = PowerDeviceD3; + } + + if (DevicePwrState.DeviceState != HubExtension->CurrentPowerState.DeviceState && + HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + HubExtension->PowerIrp = Irp; + + IoMarkIrpPending(Irp); + + if (PoRequestPowerIrp(HubExtension->LowerPDO, + IRP_MN_SET_POWER, + DevicePwrState, + USBH_FdoDeferPoRequestCompletion, + (PVOID)HubExtension, + 0) == STATUS_PENDING) + { + return STATUS_PENDING; + } + + IoCopyCurrentIrpStackLocationToNext(Irp); + PoStartNextPowerIrp(Irp); + PoCallDriver(HubExtension->LowerDevice, Irp); + + return STATUS_PENDING; + } + + Exit: + + HubExtension->SystemPowerState.SystemState = PowerState.SystemState; + + if (PowerState.SystemState == PowerSystemWorking) + { + USBH_CheckIdleDeferred(HubExtension); + } + + IoCopyCurrentIrpStackLocationToNext(Irp); + PoStartNextPowerIrp(Irp); + + return PoCallDriver(HubExtension->LowerDevice, Irp); + } + + break; + + case IRP_MN_QUERY_POWER: + DPRINT("USBH_FdoPower: IRP_MN_QUERY_POWER\n"); + break; + + default: + DPRINT1("USBH_FdoPower: unknown IRP_MN_POWER!\n"); + break; + } + + IoCopyCurrentIrpStackLocationToNext(Irp); + PoStartNextPowerIrp(Irp); + Status = PoCallDriver(HubExtension->LowerDevice, Irp); + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoPower(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp, + IN UCHAR Minor) +{ + NTSTATUS Status=0; + + DPRINT("USBH_FdoPower: PortExtension - %p, Irp - %p, Minor - %x\n", + PortExtension, + Irp, + Minor); + + switch (Minor) + { + case IRP_MN_WAIT_WAKE: + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE\n"); + PoStartNextPowerIrp(Irp); + break; + + 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"); + PoStartNextPowerIrp(Irp); + break; + + case IRP_MN_QUERY_POWER: + DPRINT("USBPORT_PdoPower: IRP_MN_QUERY_POWER\n"); + 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; +} diff --git a/reactos/drivers/usb/usbhub_new/usbhub.c b/reactos/drivers/usb/usbhub_new/usbhub.c new file mode 100644 index 00000000000..5b0ed9f8098 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/usbhub.c @@ -0,0 +1,5143 @@ +#include "usbhub.h" + +//#define NDEBUG +#include + +PVOID GenericUSBDeviceString = NULL; + +NTSTATUS +NTAPI +USBH_Wait(IN ULONG Milliseconds) +{ + LARGE_INTEGER Interval = {{0, 0}}; + + DPRINT("USBH_Wait: Milliseconds - %x\n", Milliseconds); + Interval.QuadPart -= 10000 * Milliseconds + (KeQueryTimeIncrement() - 1); + Interval.HighPart = -1; + return KeDelayExecutionThread(KernelMode, FALSE, &Interval); +} + +NTSTATUS +NTAPI +USBH_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_BINARY) + { + *(PUCHAR)EntryContext = *(PUCHAR)ValueData; + } + else if (ValueType == REG_DWORD) + { + *(PULONG)EntryContext = *(PULONG)ValueData; + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + + return Status; +} + +VOID +NTAPI +USBH_CompleteIrp(IN PIRP Irp, + IN NTSTATUS CompleteStatus) +{ + if (CompleteStatus != STATUS_SUCCESS) + { + //DbgBreakPoint(); + DPRINT1("USBH_CompleteIrp: Irp - %p, CompleteStatus - %x\n", + Irp, + CompleteStatus); + } + + Irp->IoStatus.Status = CompleteStatus; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +NTSTATUS +NTAPI +USBH_PassIrp(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + //DPRINT("USBH_PassIrp: DeviceObject - %p, Irp - %p\n", + // DeviceObject, + // Irp); + + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceObject, Irp); +} + +NTSTATUS +NTAPI +USBH_SyncIrpComplete(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext; + KIRQL OldIrql; + BOOLEAN TimerCancelled; + + DPRINT("USBH_SyncIrpComplete: ... \n"); + + HubTimeoutContext = (PUSBHUB_URB_TIMEOUT_CONTEXT)Context; + + KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql); + HubTimeoutContext->IsNormalCompleted = TRUE; + TimerCancelled = KeCancelTimer(&HubTimeoutContext->UrbTimeoutTimer); + KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql); + + if (TimerCancelled) + { + KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent, + EVENT_INCREMENT, + FALSE); + } + + return STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +IsBitSet(IN ULONG_PTR BitMapAddress, + IN ULONG Bit) +{ + BOOLEAN IsSet; + + IsSet = (*(PUCHAR)(BitMapAddress + (Bit >> 3)) & (1 << (Bit & 7))) != 0; + DPRINT("IsBitSet: Bit - %p, IsSet - %x\n", Bit, IsSet); + return IsSet; +} + +PUSBHUB_PORT_PDO_EXTENSION +NTAPI +PdoExt(IN PDEVICE_OBJECT DeviceObject) +{ + PVOID PdoExtension; + + DPRINT("PdoExt: DeviceObject - %p\n", DeviceObject); + + if (DeviceObject) + { + PdoExtension = DeviceObject->DeviceExtension; + } + else + { + PdoExtension = (PVOID)-1; + } + + return (PUSBHUB_PORT_PDO_EXTENSION)PdoExtension; +} + +NTSTATUS +NTAPI +USBH_WriteFailReasonID(IN PDEVICE_OBJECT DeviceObject, + IN ULONG Data) +{ + NTSTATUS Status; + WCHAR SourceString[64]; + HANDLE KeyHandle; + UNICODE_STRING DestinationString; + + DPRINT("USBH_WriteFailReason: ID - %x\n", Data); + + swprintf(SourceString, L"FailReasonID"); + + Status = IoOpenDeviceRegistryKey(DeviceObject, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + &KeyHandle); + + if (NT_SUCCESS(Status)) + { + RtlInitUnicodeString(&DestinationString, SourceString); + + return ZwSetValueKey(KeyHandle, + &DestinationString, + 0, + REG_DWORD, + &Data, + sizeof(Data)); + + ZwClose(KeyHandle); + } + + return Status; +} + +VOID +NTAPI +USBH_UrbTimeoutDPC(IN PKDPC Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext; + KIRQL OldIrql; + BOOL IsCompleted; + + DPRINT("USBH_TimeoutDPC ... \n"); + + HubTimeoutContext = (PUSBHUB_URB_TIMEOUT_CONTEXT)DeferredContext; + + KeAcquireSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, &OldIrql); + IsCompleted = HubTimeoutContext->IsNormalCompleted; + KeReleaseSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock, OldIrql); + + if (!IsCompleted) + { + IoCancelIrp(HubTimeoutContext->Irp); + } + + KeSetEvent(&HubTimeoutContext->UrbTimeoutEvent, + EVENT_INCREMENT, + FALSE); +} + +NTSTATUS +NTAPI +USBH_SetPdoRegistryParameter(IN PDEVICE_OBJECT DeviceObject, + IN PCWSTR SourceString, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG Type, + IN ULONG DevInstKeyType) +{ + NTSTATUS Status; + UNICODE_STRING ValueName; + HANDLE KeyHandle; + + DPRINT("USBH_SetPdoRegistryParameter ... \n"); + + RtlInitUnicodeString(&ValueName, SourceString); + + Status = IoOpenDeviceRegistryKey(DeviceObject, + DevInstKeyType, + STANDARD_RIGHTS_ALL, + &KeyHandle); + + if (NT_SUCCESS(Status)) + { + ZwSetValueKey(KeyHandle, + &ValueName, + 0, + Type, + Data, + DataSize); + + ZwClose(KeyHandle); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncSubmitUrb(IN PDEVICE_OBJECT DeviceObject, + IN PURB Urb) +{ + KEVENT Event; + IO_STATUS_BLOCK IoStatusBlock; + PIRP Irp; + PIO_STACK_LOCATION IoStack; + PUSBHUB_URB_TIMEOUT_CONTEXT HubTimeoutContext; + BOOLEAN IsWaitTimeout = FALSE; + LARGE_INTEGER DueTime = {{0, 0}}; + NTSTATUS Status; + + DPRINT("USBH_SyncSubmitUrb: ... \n"); + + Urb->UrbHeader.UsbdDeviceHandle = NULL; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, + DeviceObject, + NULL, + 0, + NULL, + 0, + TRUE, + &Event, + &IoStatusBlock); + + if (!Irp) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->Parameters.Others.Argument1 = Urb; + + HubTimeoutContext = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBHUB_URB_TIMEOUT_CONTEXT), + USB_HUB_TAG); + + if (HubTimeoutContext) + { + RtlZeroMemory(HubTimeoutContext, sizeof(USBHUB_URB_TIMEOUT_CONTEXT)); + + HubTimeoutContext->Irp = Irp; + HubTimeoutContext->IsNormalCompleted = FALSE; + + KeInitializeEvent(&HubTimeoutContext->UrbTimeoutEvent, + NotificationEvent, + FALSE); + + KeInitializeSpinLock(&HubTimeoutContext->UrbTimeoutSpinLock); + KeInitializeTimer(&HubTimeoutContext->UrbTimeoutTimer); + + KeInitializeDpc(&HubTimeoutContext->UrbTimeoutDPC, + USBH_UrbTimeoutDPC, + HubTimeoutContext); + + DueTime.QuadPart -= 5000 * 10000; // Timeout 5 sec. + + KeSetTimer(&HubTimeoutContext->UrbTimeoutTimer, + DueTime, + &HubTimeoutContext->UrbTimeoutDPC); + + IoSetCompletionRoutine(Irp, + USBH_SyncIrpComplete, + HubTimeoutContext, + TRUE, + TRUE, + TRUE); + + IsWaitTimeout = TRUE; + } + + Status = IoCallDriver(DeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + else + { + IoStatusBlock.Status = Status; + } + + if (IsWaitTimeout) + { + KeWaitForSingleObject(&HubTimeoutContext->UrbTimeoutEvent, + Suspended, + KernelMode, + FALSE, + NULL); + + ExFreePool(HubTimeoutContext); + } + + Status = IoStatusBlock.Status; + + return Status; +} + +NTSTATUS +NTAPI +USBH_FdoSyncSubmitUrb(IN PDEVICE_OBJECT FdoDevice, + IN PURB Urb) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + + DPRINT("USBH_FdoSyncSubmitUrb: FdoDevice - %p, Urb - %p\n", + FdoDevice, + Urb); + + HubExtension = (PUSBHUB_FDO_EXTENSION)FdoDevice->DeviceExtension; + return USBH_SyncSubmitUrb(HubExtension->LowerDevice, Urb); +} + +NTSTATUS +NTAPI +USBH_Transact(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID TransferBuffer, + IN ULONG BufferLen, + IN BOOLEAN Direction, + IN USHORT Function, + IN BM_REQUEST_TYPE RequestType, + IN UCHAR Request, + IN USHORT RequestValue, + IN USHORT RequestIndex) +{ + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb; + ULONG TransferFlags; + PVOID Buffer = NULL; + NTSTATUS Status; + + DPRINT("USBH_Transact: ... \n"); + + if (BufferLen) + { + Buffer = ExAllocatePoolWithTag(NonPagedPool, + (BufferLen + sizeof(ULONG)) & ~((sizeof(ULONG) - 1)), + USB_HUB_TAG); + + if (!Buffer) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Buffer, (BufferLen + sizeof(ULONG)) & ~((sizeof(ULONG) - 1))); + } + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), + USB_HUB_TAG); + + if (!Urb) + { + if (Buffer) + { + ExFreePool(Buffer); + } + + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); + + if (Direction) + { + if (BufferLen) + { + RtlCopyMemory(Buffer, TransferBuffer, BufferLen); + } + + TransferFlags = USBD_TRANSFER_DIRECTION_OUT; + } + else + { + if (BufferLen) + { + RtlZeroMemory(TransferBuffer, BufferLen); + } + + TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK; + } + + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); + Urb->Hdr.Function = Function; + Urb->Hdr.UsbdDeviceHandle = NULL; + + Urb->TransferFlags = TransferFlags; + Urb->TransferBuffer = BufferLen != 0 ? Buffer : NULL; + Urb->TransferBufferLength = BufferLen; + Urb->TransferBufferMDL = NULL; + Urb->UrbLink = NULL; + + Urb->RequestTypeReservedBits = RequestType.B; + Urb->Request = Request; + Urb->Value = RequestValue; + Urb->Index = RequestIndex; + + Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, (PURB)Urb); + + if (!Direction && BufferLen) + { + RtlCopyMemory(TransferBuffer, Buffer, BufferLen); + } + + if (Buffer) + { + ExFreePool(Buffer); + } + + ExFreePool(Urb); + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncResetPort(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port) +{ + USBHUB_PORT_STATUS PortStatus; + KEVENT Event; + LARGE_INTEGER Timeout = {{0, 0}}; + ULONG ix; + NTSTATUS Status; + + DPRINT("USBH_SyncResetPort: Port - %x\n", Port); + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->HubPortSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortStatus, + 4); + + if (NT_SUCCESS(Status) && !PortStatus.UsbPortStatus.ConnectStatus) + { + Status = STATUS_UNSUCCESSFUL; + goto Exit; + } + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_RESET_PORT_LOCK; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + ix = 0; + + while (TRUE) + { + BM_REQUEST_TYPE RequestType; + + InterlockedExchange((PLONG)&HubExtension->pResetPortEvent, + (LONG)&Event); + + RequestType.B = 0;//0x23 + RequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + + Status = USBH_Transact(HubExtension, + NULL, + 0, + 1, // to device + URB_FUNCTION_CLASS_OTHER, + RequestType, + USB_REQUEST_SET_FEATURE, + USBHUB_FEATURE_PORT_RESET, + Port); + + Timeout.QuadPart -= 5000 * 10000; + + if (!NT_SUCCESS(Status)) + { + InterlockedExchange((PLONG)&HubExtension->pResetPortEvent, 0); + + USBH_Wait(10); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK; + + goto Exit; + } + + Status = KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + &Timeout); + + if (Status != STATUS_TIMEOUT) + { + break; + } + + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortStatus, + 4); + + if (!NT_SUCCESS(Status) || + !PortStatus.UsbPortStatus.ConnectStatus || + ix >= 3) + { + InterlockedExchange((PLONG)&HubExtension->pResetPortEvent, 0); + + USBH_Wait(10); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK; + + Status = STATUS_DEVICE_DATA_ERROR; + goto Exit; + } + + ++ix; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + } + + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortStatus, + 4); + + if (!PortStatus.UsbPortStatus.ConnectStatus && + NT_SUCCESS(Status) && + HubExtension->HubFlags & USBHUB_FDO_FLAG_USB20_HUB) + { + Status = STATUS_DEVICE_DATA_ERROR; + } + + USBH_Wait(10); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_RESET_PORT_LOCK; + +Exit: + + KeReleaseSemaphore(&HubExtension->HubPortSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_GetDeviceType(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE DeviceHandle, + OUT USB_DEVICE_TYPE * OutDeviceType) +{ + PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation; + PUSB_DEVICE_INFORMATION_0 DeviceInfo; + SIZE_T DeviceInformationBufferLength; + USB_DEVICE_TYPE DeviceType = Usb11Device; + ULONG dummy; + NTSTATUS Status; + + DPRINT("USBH_GetDeviceType: ... \n"); + + QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation; + + if (!QueryDeviceInformation) + { + DPRINT1("USBH_GetDeviceType: no QueryDeviceInformation()\n"); + return STATUS_NOT_IMPLEMENTED; + } + + DeviceInformationBufferLength = sizeof(USB_DEVICE_INFORMATION_0); + + while (TRUE) + { + DeviceInfo = ExAllocatePoolWithTag(PagedPool, + DeviceInformationBufferLength, + USB_HUB_TAG); + + if (!DeviceInfo) + { + DPRINT1("USBH_GetDeviceType: ExAllocatePoolWithTag() failed\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + RtlZeroMemory(DeviceInfo, DeviceInformationBufferLength); + + DeviceInfo->InformationLevel = 0; + + Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext, + DeviceHandle, + DeviceInfo, + DeviceInformationBufferLength, + &dummy); + + if (Status != STATUS_BUFFER_TOO_SMALL) + { + if (NT_SUCCESS(Status)) + { + DeviceType = DeviceInfo->DeviceType; + } + + ExFreePool(DeviceInfo); + break; + } + + DeviceInformationBufferLength = DeviceInfo->ActualLength; + ExFreePool(DeviceInfo); + } + + if (OutDeviceType) + { + *OutDeviceType = DeviceType; + DPRINT("USBH_GetDeviceType: DeviceType - %x\n", DeviceType); + } + + return Status; +} + +NTSTATUS +NTAPI +USBHUB_GetExtendedHubInfo(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_EXTHUB_INFORMATION_0 HubInfoBuffer) +{ + PUSB_BUSIFFN_GET_EXTENDED_HUB_INFO GetExtendedHubInformation; + ULONG dummy = 0; + + DPRINT("USBHUB_GetExtendedHubInfo: ... \n"); + + GetExtendedHubInformation = HubExtension->BusInterface.GetExtendedHubInformation; + + return GetExtendedHubInformation(HubExtension->BusInterface.BusContext, + HubExtension->LowerPDO, + HubInfoBuffer, + sizeof(USB_EXTHUB_INFORMATION_0), + &dummy); +} + +PUSBHUB_FDO_EXTENSION +NTAPI +USBH_GetRootHubExtension(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PDEVICE_OBJECT RootHubPdo; + PDEVICE_OBJECT RootHubFdo; + PUSBHUB_FDO_EXTENSION RootHubExtension; + + DPRINT("USBH_GetRootHubExtension: HubExtension - %p\n", HubExtension); + + RootHubExtension = HubExtension; + + if (HubExtension->LowerPDO != HubExtension->RootHubPdo) + { + RootHubPdo = HubExtension->RootHubPdo; + + do + { + RootHubFdo = RootHubPdo->AttachedDevice; + } + while (RootHubFdo->DriverObject != HubExtension->Common.SelfDevice->DriverObject); + + RootHubExtension = (PUSBHUB_FDO_EXTENSION)RootHubFdo->DeviceExtension; + } + + DPRINT("USBH_GetRootHubExtension: RootHubExtension - %p\n", RootHubExtension); + + return RootHubExtension; +} + +NTSTATUS +NTAPI +USBH_SyncGetRootHubPdo(IN PDEVICE_OBJECT DeviceObject, + IN OUT PDEVICE_OBJECT * OutPdo1, + IN OUT PDEVICE_OBJECT * OutPdo2) +{ + KEVENT Event; + IO_STATUS_BLOCK IoStatusBlock; + PIRP Irp; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + NTSTATUS result; + + DPRINT("USBH_SyncGetRootHubPdo: ... \n"); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO, + DeviceObject, + NULL, + 0, + NULL, + 0, + TRUE, + &Event, + &IoStatusBlock); + + if (!Irp) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->Parameters.Others.Argument1 = OutPdo1; + IoStack->Parameters.Others.Argument2 = OutPdo2; + + result = IoCallDriver(DeviceObject, Irp); + + if (result == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + else + { + IoStatusBlock.Status = result; + } + + Status = IoStatusBlock.Status; + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncGetHubCount(IN PDEVICE_OBJECT DeviceObject, + IN OUT PULONG OutHubCount) +{ + KEVENT Event; + IO_STATUS_BLOCK IoStatusBlock; + PIRP Irp; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + NTSTATUS result; + + DPRINT("USBH_SyncGetHubCount: *OutHubCount - %x\n", *OutHubCount); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_HUB_COUNT, + DeviceObject, + NULL, + 0, + NULL, + 0, + TRUE, + &Event, + &IoStatusBlock); + + if (!Irp) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->Parameters.Others.Argument1 = OutHubCount; + + result = IoCallDriver(DeviceObject, Irp); + + if (result == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + else + { + IoStatusBlock.Status = result; + } + + Status = IoStatusBlock.Status; + + return Status; +} + +PUSB_DEVICE_HANDLE +NTAPI +USBH_SyncGetDeviceHandle(IN PDEVICE_OBJECT DeviceObject) +{ + PIRP Irp; + KEVENT Event; + IO_STATUS_BLOCK IoStatusBlock; + PUSB_DEVICE_HANDLE DeviceHandle = NULL; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBH_SyncGetDeviceHandle: ... \n"); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE, + DeviceObject, + NULL, + 0, + NULL, + 0, + TRUE, + &Event, + &IoStatusBlock); + + if (!Irp) + { + DPRINT1("USBH_SyncGetDeviceHandle: Irp - NULL!\n"); + return NULL; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->Parameters.Others.Argument1 = &DeviceHandle; + + if (IoCallDriver(DeviceObject, Irp) == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + + return DeviceHandle; +} + +NTSTATUS +NTAPI +USBH_GetDeviceDescriptor(IN PDEVICE_OBJECT DeviceObject, + IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor) +{ + struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb; + NTSTATUS Status; + + DPRINT("USBH_GetDeviceDescriptor: ... \n"); + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), + USB_HUB_TAG); + + if (!Urb) + { + DPRINT1("USBH_SyncGetDeviceHandle: Urb - NULL!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); + + Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); + + Urb->TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR); + Urb->TransferBuffer = HubDeviceDescriptor; + Urb->DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; + + Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb); + + ExFreePool(Urb); + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncGetDeviceConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject, + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, + IN ULONG NumberOfBytes, + IN PULONG OutLength) +{ + PCOMMON_DEVICE_EXTENSION DeviceExtension; + struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb; + NTSTATUS Status; + + DPRINT("USBH_SyncGetDeviceConfigurationDescriptor: ... \n"); + + DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + if (OutLength) + { + *OutLength = 0; + } + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), + USB_HUB_TAG); + + if (!Urb) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); + + Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); + + Urb->TransferBufferLength = NumberOfBytes; + Urb->TransferBuffer = ConfigDescriptor; + Urb->DescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE; + + if (DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_HUB || + DeviceExtension->ExtensionType == USBH_EXTENSION_TYPE_PARENT) + { + Status = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb); + } + else + { + Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb); + } + + if (OutLength) + { + *OutLength = Urb->TransferBufferLength; + } + + if (Urb) + { + ExFreePool(Urb); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_GetConfigurationDescriptor(IN PDEVICE_OBJECT DeviceObject, + IN PUSB_CONFIGURATION_DESCRIPTOR * pConfigurationDescriptor) +{ + PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; + NTSTATUS Status; + ULONG Length; + + DPRINT("USBH_GetConfigurationDescriptor: ... \n"); + + ConfigDescriptor = ExAllocatePoolWithTag(NonPagedPool, 0xFF, USB_HUB_TAG); + + if (!ConfigDescriptor) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + RtlZeroMemory(ConfigDescriptor, 0xFF); + + Status = USBH_SyncGetDeviceConfigurationDescriptor(DeviceObject, + ConfigDescriptor, + 0xFF, + &Length); + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + if (Length < sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + Status = STATUS_DEVICE_DATA_ERROR; + goto ErrorExit; + } + + if (Length < ConfigDescriptor->wTotalLength) + { + Status = STATUS_DEVICE_DATA_ERROR; + goto ErrorExit; + } + + if (ConfigDescriptor->wTotalLength > 0xFF) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + *pConfigurationDescriptor = ConfigDescriptor; + + return Status; + +ErrorExit: + + if (ConfigDescriptor) + { + ExFreePool(ConfigDescriptor); + } + + *pConfigurationDescriptor = NULL; + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncGetHubDescriptor(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_EXTHUB_INFORMATION_0 ExtendedHubInfo; + ULONG NumberPorts; + PUSBHUB_PORT_DATA PortData; + USHORT RequestValue; + ULONG NumberOfBytes; + NTSTATUS Status; + PUSB_HUB_DESCRIPTOR HubDescriptor; + ULONG ix; + + DPRINT("USBH_SyncGetHubDescriptor: ... \n"); + + ExtendedHubInfo = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USB_EXTHUB_INFORMATION_0), + USB_HUB_TAG); + + if (!ExtendedHubInfo) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + RtlZeroMemory(ExtendedHubInfo, sizeof(USB_EXTHUB_INFORMATION_0)); + + Status = USBHUB_GetExtendedHubInfo(HubExtension, ExtendedHubInfo); + + if (!NT_SUCCESS(Status)) + { + ExFreePool(ExtendedHubInfo); + ExtendedHubInfo = NULL; + } + + NumberOfBytes = sizeof(USB_HUB_DESCRIPTOR); + + HubDescriptor = ExAllocatePoolWithTag(NonPagedPool, + NumberOfBytes, + USB_HUB_TAG); + + if (!HubDescriptor) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + RtlZeroMemory(HubDescriptor, NumberOfBytes); + + RequestValue = 0; + + while (TRUE) + { + while (TRUE) + { + BM_REQUEST_TYPE RequestType; + + RequestType.B = 0;//0xA0 + RequestType._BM.Recipient = 0; + RequestType._BM.Type = 0; + RequestType._BM.Dir = 0; + + Status = USBH_Transact(HubExtension, + HubDescriptor, + NumberOfBytes, + 0, + URB_FUNCTION_CLASS_DEVICE, + RequestType, + USB_REQUEST_GET_DESCRIPTOR, + RequestValue, + 0); + + if (NT_SUCCESS(Status)) + { + break; + } + + RequestValue = 0x2900; // Hub DescriptorType - 0x29 + } + + if (HubDescriptor->bDescriptorLength <= NumberOfBytes) + { + break; + } + + NumberOfBytes = HubDescriptor->bDescriptorLength; + ExFreePool(HubDescriptor); + + HubDescriptor = ExAllocatePoolWithTag(NonPagedPool, + NumberOfBytes, + USB_HUB_TAG); + + if (!HubDescriptor) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + RtlZeroMemory(HubDescriptor, NumberOfBytes); + } + + NumberPorts = HubDescriptor->bNumberOfPorts; + + if (HubExtension->PortData) + { + PortData = HubExtension->PortData; + + if (HubDescriptor->bNumberOfPorts) + { + for (ix = 0; ix < NumberPorts; ix++) + { + PortData[ix].PortStatus.AsULONG = 0; + + if (ExtendedHubInfo) + { + PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes; + } + else + { + PortData[ix].PortAttributes = 0; + } + + PortData[ix].ConnectionStatus = NoDeviceConnected; + + if (PortData[ix].DeviceObject != NULL) + { + PortData[ix].ConnectionStatus = DeviceConnected; + } + } + } + } + else + { + PortData = NULL; + + if (HubDescriptor->bNumberOfPorts) + { + PortData = ExAllocatePoolWithTag(NonPagedPool, + NumberPorts * sizeof(USBHUB_PORT_DATA), + USB_HUB_TAG); + } + + if (!PortData) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ErrorExit; + } + + RtlZeroMemory(PortData, NumberPorts * sizeof(USBHUB_PORT_DATA)); + + if (NumberPorts) + { + for (ix = 0; ix < NumberPorts; ix++) + { + PortData[ix].ConnectionStatus = NoDeviceConnected; + + if (ExtendedHubInfo) + { + PortData[ix].PortAttributes = ExtendedHubInfo->Port[ix].PortAttributes; + } + } + } + } + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + HubExtension->HubDescriptor = HubDescriptor; + + HubExtension->PortData = PortData; + + if (ExtendedHubInfo) + { + ExFreePool(ExtendedHubInfo); + } + + return Status; + +ErrorExit: + + if (HubDescriptor) + { + ExFreePool(HubDescriptor); + } + + if (ExtendedHubInfo) + { + ExFreePool(ExtendedHubInfo); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncGetStringDescriptor(IN PDEVICE_OBJECT DeviceObject, + IN UCHAR Index, + IN USHORT LanguageId, + IN PUSB_STRING_DESCRIPTOR Descriptor, + IN ULONG NumberOfBytes, + IN PULONG OutLength, + IN BOOLEAN IsValidateLength) +{ + struct _URB_CONTROL_DESCRIPTOR_REQUEST * Urb; + ULONG TransferedLength; + NTSTATUS Status; + + DPRINT("USBH_SyncGetStringDescriptor: Index - %x, LanguageId - %x\n", + Index, + LanguageId); + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), + USB_HUB_TAG); + + if (!Urb) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); + + Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); + + Urb->TransferBuffer = Descriptor; + Urb->TransferBufferLength = NumberOfBytes; + + Urb->Index = Index; + Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE; + Urb->LanguageId = LanguageId; + + Status = USBH_SyncSubmitUrb(DeviceObject, (PURB)Urb); + + if (!NT_SUCCESS(Status)) + { + ExFreePool(Urb); + return Status; + } + + TransferedLength = Urb->TransferBufferLength; + + if (TransferedLength > NumberOfBytes) + { + Status = STATUS_DEVICE_DATA_ERROR; + } + + if (!NT_SUCCESS(Status)) + { + ExFreePool(Urb); + return Status; + } + + if (OutLength) + { + *OutLength = TransferedLength; + } + + if (IsValidateLength && TransferedLength != Descriptor->bLength) + { + Status = STATUS_DEVICE_DATA_ERROR; + } + + ExFreePool(Urb); + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncGetStatus(IN PDEVICE_OBJECT DeviceObject, + IN PUSHORT OutStatus, + IN USHORT Function, + IN USHORT RequestIndex) +{ + struct _URB_CONTROL_GET_STATUS_REQUEST * Urb; + NTSTATUS NtStatus; + USHORT UsbStatus; + + DPRINT("USBH_SyncGetStatus: ... \n"); + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST), + USB_HUB_TAG); + + if (!Urb) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST)); + + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST); + Urb->Hdr.Function = Function; + + Urb->TransferBuffer = &UsbStatus; + Urb->TransferBufferLength = sizeof(UsbStatus); + Urb->Index = RequestIndex; + + NtStatus = USBH_FdoSyncSubmitUrb(DeviceObject, (PURB)Urb); + + *OutStatus = UsbStatus; + + ExFreePool(Urb); + + return NtStatus; +} + +NTSTATUS +NTAPI +USBH_SyncGetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN PUSBHUB_PORT_STATUS PortStatus, + IN ULONG Length) +{ + BM_REQUEST_TYPE RequestType; + + DPRINT("USBH_SyncGetPortStatus: Port - %x\n", Port); + + RequestType.B = 0;//0xA3 + RequestType._BM.Recipient = BMREQUEST_TO_OTHER; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST; + + return USBH_Transact(HubExtension, + PortStatus, + Length, + 0, // to host + URB_FUNCTION_CLASS_OTHER, + RequestType, + USB_REQUEST_GET_STATUS, + 0, + Port); +} + + +NTSTATUS +NTAPI +USBH_SyncClearPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN USHORT RequestValue) +{ + BM_REQUEST_TYPE RequestType; + + DPRINT("USBH_SyncClearPortStatus: Port - %x, RequestValue - %x\n", + Port, + RequestValue); + + RequestType.B = 0;//0x23 + RequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + + return USBH_Transact(HubExtension, + NULL, + 0, + 1, // to device + URB_FUNCTION_CLASS_OTHER, + RequestType, + USB_REQUEST_CLEAR_FEATURE, + RequestValue, + Port); +} + +NTSTATUS +NTAPI +USBH_SyncPowerOnPort(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN BOOLEAN IsWait) +{ + PUSBHUB_PORT_DATA PortData; + PUSB_HUB_DESCRIPTOR HubDescriptor; + NTSTATUS Status; + BM_REQUEST_TYPE RequestType; + + DPRINT("USBH_SyncPowerOnPort: Port - %x, IsWait - %x\n", Port, IsWait); + + PortData = &HubExtension->PortData[Port - 1]; + + HubDescriptor = HubExtension->HubDescriptor; + + if (PortData->PortStatus.UsbPortStatus.ConnectStatus) + { + return STATUS_SUCCESS; + } + + RequestType.B = 0; + RequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + + Status = USBH_Transact(HubExtension, + NULL, + 0, + 1, + URB_FUNCTION_CLASS_OTHER, + RequestType, + USB_REQUEST_SET_FEATURE, + USBHUB_FEATURE_PORT_POWER, + Port); + + if (NT_SUCCESS(Status)) + { + if (IsWait) + { + USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood); + } + + PortData->PortStatus.UsbPortStatus.ConnectStatus = 1; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncPowerOnPorts(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_HUB_DESCRIPTOR HubDescriptor; + ULONG NumberOfPorts; + ULONG Port; + NTSTATUS Status; + + DPRINT("USBH_SyncPowerOnPorts: ... \n"); + + HubDescriptor = HubExtension->HubDescriptor; + NumberOfPorts = HubDescriptor->bNumberOfPorts; + + Port = 1; + + if (HubDescriptor->bNumberOfPorts) + { + do + { + Status = USBH_SyncPowerOnPort(HubExtension, Port, 0); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_SyncPowerOnPorts: USBH_SyncPowerOnPort() failed - %p\n", + Status); + break; + } + + ++Port; + } + while (Port <= NumberOfPorts); + } + + USBH_Wait(2 * HubDescriptor->bPowerOnToPowerGood); + + return Status; +} + +NTSTATUS +NTAPI +USBH_SyncDisablePort(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port) +{ + PUSBHUB_PORT_DATA PortData; + NTSTATUS Status; + BM_REQUEST_TYPE RequestType; + + DPRINT("USBH_SyncDisablePort ... \n"); + + PortData = &HubExtension->PortData[Port - 1]; + + RequestType.B = 0;//0x23 + RequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + + Status = USBH_Transact(HubExtension, + NULL, + 0, + 1, // to device + URB_FUNCTION_CLASS_OTHER, + RequestType, + USB_REQUEST_CLEAR_FEATURE, + USBHUB_FEATURE_PORT_ENABLE, + Port); + + if (NT_SUCCESS(Status)) + { + PortData->PortStatus.UsbPortStatus.EnableStatus = 0; + } + + return Status; +} + +BOOLEAN +NTAPI +USBH_HubIsBusPowered(IN PDEVICE_OBJECT DeviceObject, + IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor) +{ + BOOLEAN Result; + USHORT UsbStatus; + NTSTATUS Status; + + DPRINT("USBH_HubIsBusPowered: ... \n"); + + Status = USBH_SyncGetStatus(DeviceObject, + &UsbStatus, + URB_FUNCTION_GET_STATUS_FROM_DEVICE, + 0); + + if (!NT_SUCCESS(Status)) + { + Result = (HubConfigDescriptor->bmAttributes & 0xC0) == 0x80; + } + else + { + Result = ~UsbStatus & 1; //SelfPowered bit from status word + } + + return Result; +} + +NTSTATUS +NTAPI +USBH_ChangeIndicationAckChangeComplete(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + LONG Event; + USHORT Port; + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + DPRINT("USBH_ChangeIndicationAckChangeComplete: ... \n"); + + Port = HubExtension->Port - 1; + HubExtension->PortData[Port].PortStatus = HubExtension->PortStatus; + + Event = InterlockedExchange((PLONG)&HubExtension->pResetPortEvent, 0); + + if (Event) + { + KeSetEvent((PRKEVENT)Event, EVENT_INCREMENT, FALSE); + } + + USBH_SubmitStatusChangeTransfer(HubExtension); + + if (!InterlockedDecrement(&HubExtension->ResetRequestCount)) + { + KeSetEvent(&HubExtension->ResetEvent, + EVENT_INCREMENT, + FALSE); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBH_ChangeIndicationAckChange(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb, + IN USHORT Port, + IN USHORT RequestValue) +{ + PIO_STACK_LOCATION IoStack; + BM_REQUEST_TYPE RequestType; + + DPRINT("USBH_ChangeIndicationAckChange: ... \n"); + + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); + Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER; + Urb->Hdr.UsbdDeviceHandle = NULL; + + Urb->TransferFlags = USBD_SHORT_TRANSFER_OK; + Urb->TransferBufferLength = 0; + Urb->TransferBuffer = NULL; + Urb->TransferBufferMDL = NULL; + Urb->UrbLink = NULL; + + RequestType.B = 0; + RequestType._BM.Recipient = BMREQUEST_TO_OTHER; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + + Urb->RequestTypeReservedBits = RequestType.B; + Urb->Request = USB_REQUEST_CLEAR_FEATURE; + Urb->Index = Port; + Urb->Value = RequestValue; + + IoInitializeIrp(Irp, + IoSizeOfIrp(HubExtension->LowerDevice->StackSize), + HubExtension->LowerDevice->StackSize); + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.Others.Argument1 = Urb; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + + IoSetCompletionRoutine(Irp, + USBH_ChangeIndicationAckChangeComplete, + HubExtension, + TRUE, + TRUE, + TRUE); + + return IoCallDriver(HubExtension->LowerDevice, Irp); +} + +NTSTATUS +NTAPI +USBH_ChangeIndicationProcessChange(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_IO_WORK_ITEM WorkItem; + USHORT RequestValue; + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + DPRINT("USBH_ChangeIndicationProcessChange: PortStatus - %p\n", + HubExtension->PortStatus.AsULONG); + + if ((NT_SUCCESS(Irp->IoStatus.Status) || + USBD_SUCCESS(HubExtension->SCEWorkerUrb.Hdr.Status)) && + (HubExtension->PortStatus.UsbPortStatusChange.ResetStatusChange || + HubExtension->PortStatus.UsbPortStatusChange.EnableStatusChange)) + { + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + USBH_FreeWorkItem(HubExtension->WorkItemToQueue); + + HubExtension->WorkItemToQueue = NULL; + + if (HubExtension->PortStatus.UsbPortStatusChange.ResetStatusChange) + { + RequestValue = USBHUB_FEATURE_C_PORT_RESET; + } + else + { + RequestValue = USBHUB_FEATURE_C_PORT_ENABLE; + } + + USBH_ChangeIndicationAckChange(HubExtension, + HubExtension->ResetPortIrp, + &HubExtension->SCEWorkerUrb, + HubExtension->Port, + RequestValue); + } + else + { + WorkItem = HubExtension->WorkItemToQueue; + + if (!HubExtension->WorkItemToQueue) + { + DPRINT1("USBH_ChangeIndicationProcessChange: WorkItem == NULL \n"); + KeBugCheckEx(0xFE, 0xC1, 0, 0, 0); + //DbgBreakPoint(); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + HubExtension->WorkItemToQueue = NULL; + + USBH_QueueWorkItem(HubExtension, WorkItem); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBH_ChangeIndicationQueryChange(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST * Urb, + IN USHORT Port) +{ + PUSBHUB_IO_WORK_ITEM WorkItem; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + BM_REQUEST_TYPE RequestType; + + DPRINT("USBH_ChangeIndicationQueryChange: Port - %x\n", Port); + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + if (!Port) + { + WorkItem = HubExtension->WorkItemToQueue; + if (!HubExtension->WorkItemToQueue) + { + DPRINT1("USBH_ChangeIndicationProcessChange: WorkItem == NULL \n"); + KeBugCheckEx(0xFE, 0xC2, 0, 0, 0); + //DbgBreakPoint(); + return STATUS_MORE_PROCESSING_REQUIRED; + } + else + { + HubExtension->WorkItemToQueue = NULL; + + USBH_QueueWorkItem(HubExtension, WorkItem); + + Status = STATUS_SUCCESS; + } + } + + Urb->Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST); + Urb->Hdr.UsbdDeviceHandle = NULL; + Urb->Hdr.Function = URB_FUNCTION_CLASS_OTHER; + + Urb->TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN; + Urb->TransferBuffer = &HubExtension->PortStatus; + Urb->TransferBufferLength = sizeof(HubExtension->PortStatus); + Urb->TransferBufferMDL = NULL; + Urb->UrbLink = NULL; + + RequestType.B = 0; + RequestType._BM.Recipient = BMREQUEST_TO_OTHER; + RequestType._BM.Type = BMREQUEST_CLASS; + RequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST; + + Urb->RequestTypeReservedBits = RequestType.B; + Urb->Request = USB_REQUEST_GET_STATUS; + Urb->Value = 0; + Urb->Index = Port; + + HubExtension->Port = Port; + + IoInitializeIrp(Irp, + IoSizeOfIrp(HubExtension->LowerDevice->StackSize), + HubExtension->LowerDevice->StackSize); + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.Others.Argument1 = Urb; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + + IoSetCompletionRoutine(Irp, + USBH_ChangeIndicationProcessChange, + HubExtension, + TRUE, + TRUE, + TRUE); + + Status = IoCallDriver(HubExtension->LowerDevice, Irp); + + return Status; +} + +VOID +NTAPI +USBH_ProcessPortStateChange(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN PUSBHUB_PORT_STATUS PortStatus) +{ + PUSBHUB_PORT_DATA PortData; + USB_PORT_STATUS_CHANGE PortStatusChange; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + LONG SerialNumber; + LONG DeviceHandle; + USHORT RequestValue; + KIRQL Irql; + + DPRINT("USBH_ProcessPortStateChange ... \n"); + + PortData = &HubExtension->PortData[Port - 1]; + + PortStatusChange = PortStatus->UsbPortStatusChange; + + if (PortStatusChange.ConnectStatusChange) + { + PortData->PortStatus.AsULONG = *(PULONG)PortStatus; + + USBH_SyncClearPortStatus(HubExtension, + Port, + USBHUB_FEATURE_C_PORT_CONNECTION); + + PortData = &HubExtension->PortData[Port - 1]; + + PortDevice = PortData->DeviceObject; + + if (!PortDevice) + { + IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations); + return; + } + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_OVERCURRENT_PORT) + { + return; + } + + KeAcquireSpinLock(&HubExtension->RelationsWorkerSpinLock, &Irql); + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D3) + { + KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql); + IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations); + return; + } + + PortData->DeviceObject = NULL; + PortData->ConnectionStatus = NoDeviceConnected; + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_STATE_CHANGING; + + InsertTailList(&HubExtension->PdoList, &PortExtension->PortLink); + + KeReleaseSpinLock(&HubExtension->RelationsWorkerSpinLock, Irql); + + SerialNumber = InterlockedExchange((PLONG)&PortExtension->SerialNumber, 0); + + if (SerialNumber) + { + ExFreePool((PVOID)SerialNumber); + } + + DeviceHandle = InterlockedExchange((PLONG)&PortExtension->DeviceHandle, 0); + + if (DeviceHandle) + { + USBD_RemoveDeviceEx(HubExtension, (PUSB_DEVICE_HANDLE)DeviceHandle, 0); + USBH_SyncDisablePort(HubExtension, Port); + } + + IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations); + } + else if (PortStatusChange.EnableStatusChange) + { + RequestValue = USBHUB_FEATURE_C_PORT_ENABLE; + PortData->PortStatus = *PortStatus; + USBH_SyncClearPortStatus(HubExtension, Port, RequestValue); + return; + } + else if (PortStatusChange.SuspendStatusChange) + { + DPRINT1("USBH_ProcessPortStateChange: SuspendStatusChange UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + } + else if (PortStatusChange.OverCurrentChange) + { + DPRINT1("USBH_ProcessPortStateChange: OverCurrentChange UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + } + else if (PortStatusChange.ResetStatusChange) + { + RequestValue = USBHUB_FEATURE_C_PORT_RESET; + PortData->PortStatus = *PortStatus; + USBH_SyncClearPortStatus(HubExtension, Port, RequestValue); + } +} + +NTSTATUS +NTAPI +USBH_GetPortStatus(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PULONG PortStatus) +{ + PIRP Irp; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; + KEVENT Event; + IO_STATUS_BLOCK IoStatusBlock; + + DPRINT("USBH_GetPortStatus ... \n"); + + *PortStatus = 0; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_GET_PORT_STATUS, + HubExtension->LowerDevice, + NULL, + 0, + NULL, + 0, + TRUE, + &Event, + &IoStatusBlock); + + if (Irp) + { + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->Parameters.Others.Argument1 = PortStatus; + + Status = IoCallDriver(HubExtension->LowerDevice, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + else + { + IoStatusBlock.Status = Status; + } + + Status = IoStatusBlock.Status; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_EnableParentPort(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PIRP Irp; + NTSTATUS Status; + KEVENT Event; + IO_STATUS_BLOCK IoStatusBlock; + + DPRINT("USBH_EnableParentPort ... \n"); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_ENABLE_PORT, + HubExtension->LowerDevice, + NULL, + 0, + NULL, + 0, + TRUE, + &Event, + &IoStatusBlock); + + if (Irp) + { + Status = IoCallDriver(HubExtension->LowerDevice, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + } + else + { + IoStatusBlock.Status = Status; + } + + Status = IoStatusBlock.Status; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_ResetInterruptPipe(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + struct _URB_PIPE_REQUEST * Urb; + NTSTATUS Status; + + DPRINT("USBH_ResetInterruptPipe ... \n"); + + Urb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(struct _URB_PIPE_REQUEST), + USB_HUB_TAG); + + if (Urb) + { + RtlZeroMemory(Urb, sizeof(struct _URB_PIPE_REQUEST)); + + Urb->Hdr.Length = sizeof(struct _URB_PIPE_REQUEST); + Urb->Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL; + Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle; + + Status = USBH_FdoSyncSubmitUrb(HubExtension->Common.SelfDevice, + (PURB)Urb); + + ExFreePool(Urb); + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(Status)) + { + HubExtension->RequestErrors = 0; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_ResetHub(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN ULONG PortStatus) +{ + NTSTATUS Status; + + DPRINT("USBH_ResetHub: ... \n"); + + Status = USBH_GetPortStatus(HubExtension, &PortStatus); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + if (!(PortStatus & USBD_PORT_ENABLED)) + { + if (PortStatus & USBD_PORT_CONNECTED) + { + USBH_EnableParentPort(HubExtension); + } + } + + Status = USBH_ResetInterruptPipe(HubExtension); + + return Status; +} + +VOID +NTAPI +USBH_ChangeIndicationWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION LowerHubExtension; + PUSBHUB_PORT_PDO_EXTENSION LowerPortExtension; + PUSBHUB_STATUS_CHANGE_CONTEXT WorkItem; + USBHUB_PORT_STATUS PortStatus; + ULONG Port = 0; + NTSTATUS Status; + + DPRINT("USBH_ChangeIndicationWorker ... \n"); + + WorkItem = (PUSBHUB_STATUS_CHANGE_CONTEXT)Context; + + KeWaitForSingleObject(&HubExtension->HubSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) + { + KeSetEvent(&HubExtension->StatusChangeEvent, + EVENT_INCREMENT, + FALSE); + + goto Exit; + } + + if (!HubExtension->RequestErrors) + { + goto Enum; + } + + DPRINT("USBH_ChangeIndicationWorker: RequestErrors - %x\n", + HubExtension->RequestErrors); + + if (HubExtension->LowerPDO == HubExtension->RootHubPdo) + { + goto Enum; + } + + LowerPortExtension = (PUSBHUB_PORT_PDO_EXTENSION)HubExtension->LowerPDO->DeviceExtension; + + if (LowerPortExtension->PortPdoFlags & USBHUB_PDO_FLAG_POWER_D1_OR_D2) + { + goto Enum; + } + + LowerHubExtension = LowerPortExtension->HubExtension; + + if (!LowerHubExtension) + { + goto Enum; + } + + Status = USBH_SyncGetPortStatus(LowerHubExtension, + LowerPortExtension->PortNumber, + &PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + if (!NT_SUCCESS(Status) || !PortStatus.UsbPortStatus.ConnectStatus) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_REMOVED; + + KeSetEvent(&HubExtension->StatusChangeEvent, + EVENT_INCREMENT, + FALSE); + + goto Exit; + } + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_ESD_RECOVERING; + + DPRINT1("USBH_ChangeIndicationWorker: USBHUB_FDO_FLAG_ESD_RECOVERING FIXME. \n"); + DbgBreakPoint(); + + goto Exit; + } + +Enum: + + if (WorkItem->RequestErrors & 1) + { + ULONG PortStatusFlags = 0x200; + USBH_ResetHub(HubExtension, PortStatusFlags); + } + else + { + do + { + if (IsBitSet(((ULONG)WorkItem + sizeof(USBHUB_STATUS_CHANGE_CONTEXT)), Port)) + { + break; + } + + ++Port; + } + while (Port <= HubExtension->HubDescriptor->bNumberOfPorts); + + if (Port <= HubExtension->HubDescriptor->bNumberOfPorts) + { + if (Port) + { + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortStatus, + sizeof(USBHUB_PORT_STATUS)); + } + else + { + DPRINT1("USBH_ChangeIndicationWorker: USBH_SyncGetHubStatus() UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + } + + if (NT_SUCCESS(Status)) + { + if (Port) + { + USBH_ProcessPortStateChange(HubExtension, + Port, + &PortStatus); + } + else + { + DPRINT1("USBH_ChangeIndicationWorker: USBH_ProcessHubStateChange() UNIMPLEMENTED. FIXME. \n"); + DbgBreakPoint(); + } + } + else + { + ++HubExtension->RequestErrors; + + if (HubExtension->RequestErrors > 3) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED; + goto Exit; + } + } + } + } + + USBH_SubmitStatusChangeTransfer(HubExtension); + +Exit: + + KeReleaseSemaphore(&HubExtension->HubSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + if (!InterlockedDecrement((PLONG)&HubExtension->ResetRequestCount)) + { + KeSetEvent(&HubExtension->ResetEvent, + EVENT_INCREMENT, + FALSE); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEFER_CHECK_IDLE) + { + USBH_CheckHubIdle(HubExtension); + } + } +} + +NTSTATUS +NTAPI +USBH_ChangeIndication(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + USBD_STATUS UrbStatus; + BOOLEAN IsErrors = FALSE; + PUSBHUB_IO_WORK_ITEM HubWorkItem; + PUSBHUB_STATUS_CHANGE_CONTEXT HubWorkItemBuffer; + USHORT NumPorts; + USHORT Port; + NTSTATUS Status; + ULONG_PTR Bitmap; + ULONG BufferLength; + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + UrbStatus = HubExtension->SCEWorkerUrb.Hdr.Status; + + DPRINT("USBH_ChangeIndication: IrpStatus - %p, UrbStatus - %p, HubFlags - %p\n", + Irp->IoStatus.Status, + UrbStatus, + HubExtension->HubFlags); + + if (NT_ERROR(Irp->IoStatus.Status) || USBD_ERROR(UrbStatus) || + (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) || + (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING)) + { + ++HubExtension->RequestErrors; + + IsErrors = TRUE; + + KeSetEvent(&HubExtension->StatusChangeEvent, + EVENT_INCREMENT, + FALSE); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING || + HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED || + HubExtension->RequestErrors > 3 || + Irp->IoStatus.Status == STATUS_DELETE_PENDING) + { + DPRINT("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n", + HubExtension->RequestErrors); + + return STATUS_MORE_PROCESSING_REQUIRED; + } + + DPRINT("USBH_ChangeIndication: HubExtension->RequestErrors - %x\n", + HubExtension->RequestErrors); + } + else + { + HubExtension->RequestErrors = 0; + } + + BufferLength = sizeof(USBHUB_STATUS_CHANGE_CONTEXT) + + HubExtension->SCEBitmapLength; + + Status = USBH_AllocateWorkItem(HubExtension, + &HubWorkItem, + USBH_ChangeIndicationWorker, + BufferLength, + (PVOID *)&HubWorkItemBuffer, + DelayedWorkQueue); + + if (!NT_SUCCESS(Status)) + { + return STATUS_MORE_PROCESSING_REQUIRED; + } + + RtlZeroMemory(HubWorkItemBuffer, BufferLength); + + HubWorkItemBuffer->RequestErrors = 0; + + if (IsErrors == TRUE) + { + HubWorkItemBuffer->RequestErrors = 1; + } + + if (InterlockedIncrement(&HubExtension->ResetRequestCount) == 1) + { + KeResetEvent(&HubExtension->ResetEvent); + } + + HubWorkItemBuffer->HubExtension = HubExtension; + + Port = 0; + + HubExtension->WorkItemToQueue = HubWorkItem; + + RtlCopyMemory((PVOID)((ULONG)HubWorkItemBuffer + sizeof(USBHUB_STATUS_CHANGE_CONTEXT)), + HubExtension->SCEBitmap, + HubExtension->SCEBitmapLength); + + NumPorts = HubExtension->HubDescriptor->bNumberOfPorts; + + Bitmap = (ULONG)HubWorkItemBuffer + sizeof(USBHUB_STATUS_CHANGE_CONTEXT); + + do + { + if (IsBitSet(Bitmap, Port)) + { + break; + } + + ++Port; + } + while (Port <= NumPorts); + + if (Port > NumPorts) + { + Port = 0; + } + + Status = USBH_ChangeIndicationQueryChange(HubExtension, + HubExtension->ResetPortIrp, + &HubExtension->SCEWorkerUrb, + Port); + + if (NT_ERROR(Status)) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEVICE_FAILED; + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBH_SubmitStatusChangeTransfer(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PIRP Irp; + NTSTATUS Status; + struct _URB_BULK_OR_INTERRUPT_TRANSFER * Urb; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBH_SubmitStatusChangeTransfer: HubExtension - %p, SCEIrp - %p\n", + HubExtension, + HubExtension->SCEIrp); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_NOT_D0_STATE) + { + DPRINT("USBH_SubmitStatusChangeTransfer: USBHUB_FDO_FLAG_NOT_D0_STATE - FALSE\n"); + DPRINT("USBH_SubmitStatusChangeTransfer: HubFlags - %p\n", HubExtension->HubFlags); + return STATUS_INVALID_DEVICE_STATE; + } + + Irp = HubExtension->SCEIrp; + + if (!Irp) + { + return STATUS_INVALID_DEVICE_STATE; + } + + Urb = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *)&HubExtension->SCEWorkerUrb; + + Urb->Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER); + Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; + Urb->Hdr.UsbdDeviceHandle = NULL; + + Urb->PipeHandle = HubExtension->PipeInfo.PipeHandle; + Urb->TransferFlags = USBD_SHORT_TRANSFER_OK; + Urb->TransferBuffer = HubExtension->SCEBitmap; + Urb->TransferBufferLength = HubExtension->SCEBitmapLength; + Urb->TransferBufferMDL = NULL; + Urb->UrbLink = NULL; + + IoInitializeIrp(Irp, + IoSizeOfIrp(HubExtension->LowerDevice->StackSize), + HubExtension->LowerDevice->StackSize); + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.Others.Argument1 = &HubExtension->SCEWorkerUrb; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + + IoSetCompletionRoutine(Irp, + USBH_ChangeIndication, + HubExtension, + TRUE, + TRUE, + TRUE); + + KeResetEvent(&HubExtension->StatusChangeEvent); + + Status = IoCallDriver(HubExtension->LowerDevice, Irp); + + return Status; +} + +NTSTATUS +NTAPI +USBD_CreateDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE * OutDeviceHandle, + IN USB_PORT_STATUS UsbPortStatus, + IN USHORT Port) +{ + PUSB_DEVICE_HANDLE HubDeviceHandle; + PUSB_BUSIFFN_CREATE_USB_DEVICE CreateUsbDevice; + + DPRINT("USBD_CreateDeviceEx: Port - %x, UsbPortStatus - 0x%04X\n", + Port, + UsbPortStatus.AsUSHORT); + + CreateUsbDevice = HubExtension->BusInterface.CreateUsbDevice; + + if (!CreateUsbDevice) + { + return STATUS_NOT_IMPLEMENTED; + } + + HubDeviceHandle = USBH_SyncGetDeviceHandle(HubExtension->LowerDevice); + + return CreateUsbDevice(HubExtension->BusInterface.BusContext, + OutDeviceHandle, + HubDeviceHandle, + UsbPortStatus.AsUSHORT, + Port); +} + +NTSTATUS +NTAPI +USBD_RemoveDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE DeviceHandle, + IN ULONG Flags) +{ + PUSB_BUSIFFN_REMOVE_USB_DEVICE RemoveUsbDevice; + + DPRINT("USBD_RemoveDeviceEx: DeviceHandle - %p, Flags - %x\n", + DeviceHandle, + Flags); + + RemoveUsbDevice = HubExtension->BusInterface.RemoveUsbDevice; + + if (!RemoveUsbDevice) + { + return STATUS_NOT_IMPLEMENTED; + } + + return RemoveUsbDevice(HubExtension->BusInterface.BusContext, + DeviceHandle, + Flags); +} + +NTSTATUS +NTAPI +USBD_InitializeDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE DeviceHandle, + IN PUCHAR DeviceDescriptorBuffer, + IN ULONG DeviceDescriptorBufferLength, + IN PUCHAR ConfigDescriptorBuffer, + IN ULONG ConfigDescriptorBufferLength) +{ + NTSTATUS Status; + PUSB_BUSIFFN_INITIALIZE_USB_DEVICE InitializeUsbDevice; + PUSB_BUSIFFN_GET_USB_DESCRIPTORS GetUsbDescriptors; + + DPRINT("USBD_InitializeDeviceEx: ... \n"); + + InitializeUsbDevice = HubExtension->BusInterface.InitializeUsbDevice; + GetUsbDescriptors = HubExtension->BusInterface.GetUsbDescriptors; + + if (!InitializeUsbDevice || !GetUsbDescriptors) + { + return STATUS_NOT_IMPLEMENTED; + } + + Status = InitializeUsbDevice(HubExtension->BusInterface.BusContext, + DeviceHandle); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + return GetUsbDescriptors(HubExtension->BusInterface.BusContext, + DeviceHandle, + DeviceDescriptorBuffer, + &DeviceDescriptorBufferLength, + ConfigDescriptorBuffer, + &ConfigDescriptorBufferLength); +} + +VOID +NTAPI +USBHUB_SetDeviceHandleData(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PDEVICE_OBJECT UsbDevicePdo, + IN PVOID DeviceHandle) +{ + PUSB_BUSIFFN_SET_DEVHANDLE_DATA SetDeviceHandleData; + + DPRINT("USBHUB_SetDeviceHandleData ... \n"); + + SetDeviceHandleData = HubExtension->BusInterface.SetDeviceHandleData; + + if (!SetDeviceHandleData) + { + return; + } + + SetDeviceHandleData(HubExtension->BusInterface.BusContext, + DeviceHandle, + UsbDevicePdo); +} + +VOID +NTAPI +USBHUB_FlushAllTransfers(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_BUSIFFN_FLUSH_TRANSFERS FlushTransfers; + + DPRINT("USBHUB_FlushAllTransfers ... \n"); + + FlushTransfers = HubExtension->BusInterface.FlushTransfers; + + if (FlushTransfers) + { + FlushTransfers(HubExtension->BusInterface.BusContext, NULL); + } +} + +NTSTATUS +NTAPI +USBD_GetDeviceInformationEx(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_NODE_CONNECTION_INFORMATION_EX Info, + IN ULONG Length, + IN PUSB_DEVICE_HANDLE DeviceHandle) +{ + PUSB_BUSIFFN_GET_DEVICE_INFORMATION QueryDeviceInformation; + PUSB_DEVICE_INFORMATION_0 DeviceInfo; + SIZE_T DeviceInfoLength; + PUSB_NODE_CONNECTION_INFORMATION_EX NodeInfo; + SIZE_T NodeInfoLength; + ULONG PipeNumber; + ULONG dummy; + NTSTATUS Status; + + DPRINT("USBD_GetDeviceInformationEx ... \n"); + + QueryDeviceInformation = HubExtension->BusInterface.QueryDeviceInformation; + + if (!QueryDeviceInformation) + { + Status = STATUS_NOT_IMPLEMENTED; + return Status; + } + + DeviceInfoLength = sizeof(USB_DEVICE_INFORMATION_0); + + while (TRUE) + { + DeviceInfo = ExAllocatePoolWithTag(PagedPool, + DeviceInfoLength, + USB_HUB_TAG); + + if (!DeviceInfo) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(DeviceInfo, DeviceInfoLength); + + DeviceInfo->InformationLevel = 0; + + Status = QueryDeviceInformation(HubExtension->BusInterface.BusContext, + DeviceHandle, + DeviceInfo, + DeviceInfoLength, + &dummy); + + if (Status != STATUS_BUFFER_TOO_SMALL) + { + break; + } + + DeviceInfoLength = DeviceInfo->ActualLength; + + ExFreePool(DeviceInfo); + } + + NodeInfo = NULL; + NodeInfoLength = 0; + + if (NT_SUCCESS(Status)) + { + NodeInfoLength = (sizeof(USB_NODE_CONNECTION_INFORMATION_EX) - sizeof(USB_PIPE_INFO)) + + DeviceInfo->NumberOfOpenPipes * sizeof(USB_PIPE_INFO); + + NodeInfo = ExAllocatePoolWithTag(PagedPool, NodeInfoLength, USB_HUB_TAG); + + if (!NodeInfo) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(NodeInfo, NodeInfoLength); + + if (NT_SUCCESS(Status)) + { + NodeInfo->ConnectionIndex = Info->ConnectionIndex; + + RtlCopyMemory(&NodeInfo->DeviceDescriptor, + &DeviceInfo->DeviceDescriptor, + sizeof(USB_DEVICE_DESCRIPTOR)); + + NodeInfo->CurrentConfigurationValue = DeviceInfo->CurrentConfigurationValue; + NodeInfo->Speed = DeviceInfo->DeviceSpeed; + NodeInfo->DeviceIsHub = PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_HUB_DEVICE; + NodeInfo->DeviceAddress = DeviceInfo->DeviceAddress; + NodeInfo->NumberOfOpenPipes = DeviceInfo->NumberOfOpenPipes; + NodeInfo->ConnectionStatus = Info->ConnectionStatus; + + PipeNumber = 0; + + if (DeviceInfo->NumberOfOpenPipes) + { + do + { + RtlCopyMemory(&NodeInfo->PipeList[PipeNumber], + &DeviceInfo->PipeList[PipeNumber], + sizeof(USB_PIPE_INFO)); + + ++PipeNumber; + } + while (PipeNumber < DeviceInfo->NumberOfOpenPipes); + } + } + } + + ExFreePool(DeviceInfo); + + if (NodeInfo) + { + if (NodeInfoLength <= Length) + { + Length = NodeInfoLength; + } + else + { + Status = STATUS_BUFFER_TOO_SMALL; + } + + RtlCopyMemory(Info, NodeInfo, Length); + + ExFreePool(NodeInfo); + } + + return Status; +} + +NTSTATUS +NTAPI +USBD_RestoreDeviceEx(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle, + IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle) +{ + PUSB_BUSIFFN_RESTORE_DEVICE RestoreUsbDevice; + NTSTATUS Status; + + DPRINT("USBD_RestoreDeviceEx: HubExtension - %p, OldDeviceHandle - %p, NewDeviceHandle - %p\n", + HubExtension, + OldDeviceHandle, + NewDeviceHandle); + + RestoreUsbDevice = HubExtension->BusInterface.RestoreUsbDevice; + + if (RestoreUsbDevice) + { + Status = RestoreUsbDevice(HubExtension->BusInterface.BusContext, + OldDeviceHandle, + NewDeviceHandle); + } + else + { + Status = STATUS_NOT_IMPLEMENTED; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_AllocateWorkItem(PUSBHUB_FDO_EXTENSION HubExtension, + PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem, + PVOID WorkerRoutine, + SIZE_T BufferLength, + PVOID * OutHubWorkItemBuffer, + WORK_QUEUE_TYPE Type) +{ + PUSBHUB_IO_WORK_ITEM HubIoWorkItem; + PIO_WORKITEM WorkItem; + PVOID WorkItemBuffer; + + DPRINT("USBH_AllocateWorkItem: ... \n"); + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WITEM_INIT)) + { + return STATUS_INVALID_PARAMETER; + } + + HubIoWorkItem = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBHUB_IO_WORK_ITEM), + USB_HUB_TAG); + + if (!HubIoWorkItem) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(HubIoWorkItem, sizeof(USBHUB_IO_WORK_ITEM)); + + WorkItem = IoAllocateWorkItem(HubExtension->Common.SelfDevice); + + HubIoWorkItem->HubWorkItem = WorkItem; + + if (!WorkItem) + { + ExFreePool(HubIoWorkItem); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (BufferLength && OutHubWorkItemBuffer) + { + WorkItemBuffer = ExAllocatePoolWithTag(NonPagedPool, + BufferLength, + USB_HUB_TAG); + + HubIoWorkItem->HubWorkItemBuffer = WorkItemBuffer; + + if (!WorkItemBuffer) + { + IoFreeWorkItem(HubIoWorkItem->HubWorkItem); + ExFreePool(HubIoWorkItem); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(WorkItemBuffer, BufferLength); + } + else + { + HubIoWorkItem->HubWorkItemBuffer = NULL; + } + + HubIoWorkItem->HubWorkItemType = Type; + HubIoWorkItem->HubExtension = HubExtension; + HubIoWorkItem->HubWorkerRoutine = WorkerRoutine; + + if (OutHubIoWorkItem) + { + *OutHubIoWorkItem = HubIoWorkItem; + } + + if (OutHubWorkItemBuffer) + { + *OutHubWorkItemBuffer = HubIoWorkItem->HubWorkItemBuffer; + } + + return STATUS_SUCCESS; +} + +VOID +NTAPI +USBH_Worker(IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context) +{ + PUSBHUB_IO_WORK_ITEM HubIoWorkItem; + PUSBHUB_FDO_EXTENSION HubExtension; + KIRQL OldIrql; + PIO_WORKITEM WorkItem; + + DPRINT("USBH_Worker: HubIoWorkItem - %p\n", Context); + + HubIoWorkItem = (PUSBHUB_IO_WORK_ITEM)Context; + + InterlockedDecrement(&HubIoWorkItem->HubWorkerQueued); + + HubExtension = HubIoWorkItem->HubExtension; + WorkItem = HubIoWorkItem->HubWorkItem; + + HubIoWorkItem->HubWorkerRoutine(HubIoWorkItem->HubExtension, + HubIoWorkItem->HubWorkItemBuffer); + + KeAcquireSpinLock(&HubExtension->WorkItemSpinLock, &OldIrql); + RemoveEntryList(&HubIoWorkItem->HubWorkItemLink); + KeReleaseSpinLock(&HubExtension->WorkItemSpinLock, OldIrql); + + if (HubIoWorkItem->HubWorkItemBuffer) + { + ExFreePool(HubIoWorkItem->HubWorkItemBuffer); + } + + ExFreePool(HubIoWorkItem); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + IoFreeWorkItem(WorkItem); + + DPRINT("USBH_Worker: HubIoWorkItem %p complete\n", Context); +} + +VOID +NTAPI +USBH_QueueWorkItem(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem) +{ + DPRINT("USBH_QueueWorkItem: ... \n"); + + InterlockedIncrement(&HubExtension->PendingRequestCount); + InterlockedIncrement(&HubIoWorkItem->HubWorkerQueued); + + ExInterlockedInsertTailList(&HubExtension->WorkItemList, + &HubIoWorkItem->HubWorkItemLink, + &HubExtension->WorkItemSpinLock); + + IoQueueWorkItem(HubIoWorkItem->HubWorkItem, + USBH_Worker, + HubIoWorkItem->HubWorkItemType, + HubIoWorkItem); +} + +VOID +NTAPI +USBH_FreeWorkItem(IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem) +{ + PIO_WORKITEM WorkItem; + + DPRINT("USBH_FreeWorkItem: ... \n"); + + WorkItem = HubIoWorkItem->HubWorkItem; + + if (HubIoWorkItem->HubWorkItemBuffer) + { + ExFreePool(HubIoWorkItem->HubWorkItemBuffer); + } + + ExFreePool(HubIoWorkItem); + + IoFreeWorkItem(WorkItem); +} + +VOID +NTAPI +USBHUB_RootHubCallBack(IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + + DPRINT("USBHUB_RootHubCallBack: ... \n"); + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + if (HubExtension->SCEIrp) + { + HubExtension->HubFlags |= (USBHUB_FDO_FLAG_DO_ENUMERATION | + USBHUB_FDO_FLAG_NOT_ENUMERATED); + + USBH_SubmitStatusChangeTransfer(HubExtension); + + IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations); + } + else + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_ENUMERATION; + } + + KeSetEvent(&HubExtension->RootHubNotificationEvent, + EVENT_INCREMENT, + FALSE); +} + +NTSTATUS +NTAPI +USBD_RegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification; + + DPRINT("USBD_RegisterRootHubCallBack: ... \n"); + + RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification; + + if (!RootHubInitNotification) + { + return STATUS_NOT_IMPLEMENTED; + } + + KeResetEvent(&HubExtension->RootHubNotificationEvent); + + return RootHubInitNotification(HubExtension->BusInterface.BusContext, + HubExtension, + USBHUB_RootHubCallBack); +} + +NTSTATUS +NTAPI +USBD_UnRegisterRootHubCallBack(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSB_BUSIFFN_ROOTHUB_INIT_NOTIFY RootHubInitNotification; + NTSTATUS Status; + + DPRINT("USBD_UnRegisterRootHubCallBack ... \n"); + + RootHubInitNotification = HubExtension->BusInterface.RootHubInitNotification; + + if (!RootHubInitNotification) + { + return STATUS_NOT_IMPLEMENTED; + } + + Status = RootHubInitNotification(HubExtension->BusInterface.BusContext, + NULL, + NULL); + + if (!NT_SUCCESS(Status)) + { + KeWaitForSingleObject(&HubExtension->RootHubNotificationEvent, + Executive, + KernelMode, + FALSE, + NULL); + } + + return Status; +} + +VOID +NTAPI +USBH_HubSetDWakeCompletion(IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus) +{ + DPRINT("USBH_HubSetDWakeCompletion: ... \n"); + KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE); +} + +VOID +NTAPI +USBH_HubQueuePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PLIST_ENTRY IdleList) +{ + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PIRP IdleIrp; + PIRP HubIdleIrp; + ULONG NumPorts; + ULONG Port; + KIRQL Irql; + + DPRINT("USBH_HubQueuePortIdleIrps ... \n"); + + InitializeListHead(IdleList); + + IoAcquireCancelSpinLock(&Irql); + + NumPorts = HubExtension->HubDescriptor->bNumberOfPorts; + + if (NumPorts) + { + Port = 0; + + do + { + PortDevice = HubExtension->PortData[Port].DeviceObject; + + if (PortDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + IdleIrp = PortExtension->IdleNotificationIrp; + PortExtension->IdleNotificationIrp = NULL; + + if (IdleIrp && IoSetCancelRoutine(IdleIrp, NULL)) + { + DPRINT1("USBH_HubQueuePortIdleIrps: IdleIrp != NULL. FIXME. \n"); + DbgBreakPoint(); + } + } + + ++Port; + } + while (Port < NumPorts); + } + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST) + { + HubIdleIrp = HubExtension->PendingIdleIrp; + HubExtension->PendingIdleIrp = NULL; + } + else + { + HubIdleIrp = NULL; + } + + IoReleaseCancelSpinLock(Irql); + + if (HubIdleIrp) + { + USBH_HubCancelIdleIrp(HubExtension, HubIdleIrp); + } +} + +VOID +NTAPI +USBH_HubCompleteQueuedPortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PLIST_ENTRY IdleList, + IN NTSTATUS NtStatus) +{ + DPRINT("USBH_HubCompleteQueuedPortIdleIrps ... \n"); + + while (!IsListEmpty(IdleList)) + { + DPRINT1("USBH_HubCompleteQueuedPortIdleIrps: IdleList not Empty. FIXME. \n"); + DbgBreakPoint(); + } +} + +VOID +NTAPI +USBH_FlushPortPwrList(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PLIST_ENTRY Entry; + ULONG Port; + + DPRINT("USBH_FlushPortPwrList ... \n"); + + InterlockedIncrement((PLONG)&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + if (!HubExtension->HubDescriptor->bNumberOfPorts) + { + goto Exit; + } + + Port = 0; + + do + { + PortDevice = HubExtension->PortData[Port].DeviceObject; + + if (!PortDevice) + { + goto NextPort; + } + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + InterlockedExchange((PLONG)&PortExtension->StateBehindD2, 0); + + while (TRUE) + { + Entry = ExInterlockedRemoveHeadList(&PortExtension->PortPowerList, + &PortExtension->PortPowerListSpinLock); + + if (!Entry) + { + break; + } + + DPRINT1("USBH_FlushPortPwrList: PortPowerList FIXME. \n"); + DbgBreakPoint(); + } + + NextPort: + ++Port; + } + while (Port < HubExtension->HubDescriptor->bNumberOfPorts); + +Exit: + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement((PLONG)&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } +} + +VOID +NTAPI +USBH_HubCompletePortIdleIrps(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN NTSTATUS NtStatus) +{ + LIST_ENTRY IdleList; + + DPRINT("USBH_HubCompletePortIdleIrps ... \n"); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + USBH_HubQueuePortIdleIrps(HubExtension, &IdleList); + + USBH_HubCompleteQueuedPortIdleIrps(HubExtension, + &IdleList, + NtStatus); + + USBH_FlushPortPwrList(HubExtension); + } +} + +VOID +NTAPI +USBH_HubCancelIdleIrp(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP IdleIrp) +{ + DPRINT("USBH_HubCancelIdleIrp ... \n"); + + IoCancelIrp(IdleIrp); + + if (InterlockedExchange(&HubExtension->IdleRequestLock, 1)) + { + IoFreeIrp(IdleIrp); + } +} + +BOOLEAN +NTAPI +USBH_CheckIdleAbort(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN BOOLEAN IsWait, + IN BOOLEAN IsExtCheck) +{ + PDEVICE_OBJECT PdoDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSBHUB_PORT_DATA PortData; + ULONG Port; + BOOLEAN Result; + + DPRINT("USBH_CheckIdleAbort: ... \n"); + + Result = FALSE; + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + if (IsWait == TRUE) + { + KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + } + + Port = 0; + + if (HubExtension->HubDescriptor->bNumberOfPorts) + { + PortData = HubExtension->PortData; + + while (TRUE) + { + PdoDevice = PortData[Port].DeviceObject; + + if (PdoDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + + if (PortExtension->PoRequestCounter) + { + break; + } + } + + ++Port; + + if (Port >= HubExtension->HubDescriptor->bNumberOfPorts) + { + goto ExtCheck; + } + } + + Result = TRUE; + } + else + { + +ExtCheck: + + if (IsExtCheck == TRUE && + HubExtension->HubDescriptor->bNumberOfPorts) + { + PortData = HubExtension->PortData; + + Port = 0; + + do + { + PdoDevice = PortData[Port].DeviceObject; + + if (PdoDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + InterlockedExchange(&PortExtension->StateBehindD2, 0); + } + + ++Port; + } + while (Port < HubExtension->HubDescriptor->bNumberOfPorts); + } + } + + if (IsWait == TRUE) + { + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + } + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + return Result; +} + +VOID +NTAPI +USBH_FdoWaitWakeIrpCompletion(IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus) +{ + DPRINT("USBH_FdoWaitWakeIrpCompletion ... \n"); +} + +NTSTATUS +NTAPI +USBH_FdoSubmitWaitWakeIrp(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + POWER_STATE PowerState; + NTSTATUS Status; + PIRP Irp = NULL; + KIRQL Irql; + + DPRINT("USBH_FdoSubmitWaitWakeIrp: ... \n"); + + PowerState.SystemState = HubExtension->SystemWake; + HubExtension->HubFlags |= USBHUB_FDO_FLAG_PENDING_WAKE_IRP; + + InterlockedIncrement(&HubExtension->PendingRequestCount); + InterlockedExchange(&HubExtension->FdoWaitWakeLock, 0); + + Status = PoRequestPowerIrp(HubExtension->LowerPDO, + IRP_MN_WAIT_WAKE, + PowerState, + USBH_FdoWaitWakeIrpCompletion, + HubExtension, + &Irp); + + IoAcquireCancelSpinLock(&Irql); + + if (Status == STATUS_PENDING) + { + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP) + { + HubExtension->PendingWakeIrp = Irp; + DPRINT("USBH_FdoSubmitWaitWakeIrp: PendingWakeIrp - %p\n", + HubExtension->PendingWakeIrp); + } + } + else + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_PENDING_WAKE_IRP; + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + } + + IoReleaseCancelSpinLock(Irql); + + return Status; +} + +VOID +NTAPI +USBH_FdoIdleNotificationCallback(IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_PORT_DATA PortData; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PIRP Irp = NULL; + PIRP IdleIrp; + POWER_STATE PowerState; + KEVENT Event; + ULONG Port; + PIO_STACK_LOCATION IoStack; + PUSB_IDLE_CALLBACK_INFO CallbackInfo; + BOOLEAN IsReady; + KIRQL OldIrql; + NTSTATUS Status; + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + + DPRINT("USBH_FdoIdleNotificationCallback: HubExtension - %p, HubFlags - %p\n", + HubExtension, + HubExtension->HubFlags); + + IsReady = TRUE; + + if (HubExtension->HubFlags & (USBHUB_FDO_FLAG_ENUM_POST_RECOVER | + USBHUB_FDO_FLAG_WAKEUP_START | + USBHUB_FDO_FLAG_DEVICE_REMOVED | + USBHUB_FDO_FLAG_STATE_CHANGING | + USBHUB_FDO_FLAG_ESD_RECOVERING | + USBHUB_FDO_FLAG_DEVICE_FAILED | + USBHUB_FDO_FLAG_DEVICE_STOPPING)) + { + DbgBreakPoint(); + return; + } + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_GOING_IDLE; + + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_PENDING_WAKE_IRP)) + { + Status = USBH_FdoSubmitWaitWakeIrp(HubExtension); + + if (Status != STATUS_PENDING) + { + DPRINT("Status != STATUS_PENDING. DbgBreakPoint()\n"); + DbgBreakPoint(); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE; + return; + } + } + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + Port = 0; + + if (HubExtension->HubDescriptor->bNumberOfPorts == 0) + { + if ((HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) || + (USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) != TRUE)) + { + goto IdleHub; + } + } + else + { + PortData = HubExtension->PortData; + + while (TRUE) + { + PortDevice = PortData[Port].DeviceObject; + + if (PortDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + IdleIrp = PortExtension->IdleNotificationIrp; + + if (!IdleIrp) + { + break; + } + + IoStack = IoGetCurrentIrpStackLocation(IdleIrp); + + CallbackInfo = (PUSB_IDLE_CALLBACK_INFO)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + if (!CallbackInfo) + { + break; + } + + if (!CallbackInfo->IdleCallback) + { + break; + } + + if (PortExtension->PendingSystemPoRequest) + { + break; + } + + if (InterlockedCompareExchange(&PortExtension->StateBehindD2, + 1, + 0)) + { + break; + } + + DPRINT("USBH_FdoIdleNotificationCallback: IdleContext - %p\n", + CallbackInfo->IdleContext); + + CallbackInfo->IdleCallback(CallbackInfo->IdleContext); + + if (PortExtension->CurrentPowerState.DeviceState == PowerDeviceD0) + { + break; + } + } + + ++Port; + + if (Port >= HubExtension->HubDescriptor->bNumberOfPorts) + { + if ((HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) || + (USBH_CheckIdleAbort(HubExtension, FALSE, FALSE) != TRUE)) + { + goto IdleHub; + } + } + } + } + + IsReady = FALSE; + +IdleHub: + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + if (!IsReady || + (HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_SUSPENDED)) + { + DPRINT1("USBH_FdoIdleNotificationCallback: HubFlags - %p\n", + HubExtension->HubFlags); + + HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED | + USBHUB_FDO_FLAG_GOING_IDLE); + + //Aborting Idle for Hub + IoAcquireCancelSpinLock(&OldIrql); + + if (HubExtension->PendingIdleIrp) + { + Irp = HubExtension->PendingIdleIrp; + HubExtension->PendingIdleIrp = NULL; + } + + IoReleaseCancelSpinLock(OldIrql); + + if (Irp) + { + USBH_HubCancelIdleIrp(HubExtension, Irp); + } + + DbgBreakPoint(); + USBH_HubCompletePortIdleIrps(HubExtension, STATUS_CANCELLED); + } + else + { + PowerState.DeviceState = HubExtension->DeviceWake; + + KeWaitForSingleObject(&HubExtension->IdleSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_GOING_IDLE; + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DO_SUSPENSE; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + DPRINT("USBH_FdoIdleNotificationCallback: LowerPdo - %p\n", + HubExtension->LowerPDO); + + DPRINT("USBH_FdoIdleNotificationCallback: PowerState.DeviceState - %x\n", + PowerState.DeviceState); + + Status = PoRequestPowerIrp(HubExtension->LowerPDO, + IRP_MN_SET_POWER, + PowerState, + USBH_HubSetDWakeCompletion, + &Event, + 0); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + } + } +} + +VOID +NTAPI +USBH_CompletePortIdleIrpsWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + PUSBHUB_IDLE_PORT_CONTEXT IdlePortContext; + NTSTATUS NtStatus; + NTSTATUS Status; + BOOLEAN IsFlush = FALSE; + + DPRINT("USBH_CompletePortIdleIrpsWorker ... \n"); + + IdlePortContext = (PUSBHUB_IDLE_PORT_CONTEXT)Context; + NtStatus = IdlePortContext->Status; + + USBH_HubCompleteQueuedPortIdleIrps(HubExtension, + &IdlePortContext->PwrList, + NtStatus); + + DPRINT1("USBH_CompletePortIdleIrpsWorker: USBH_RegQueryFlushPortPowerIrpsFlag() UNIMPLEMENTED. FIXME. \n"); + Status = 0xC0000000;// USBH_RegQueryFlushPortPowerIrpsFlag(&IsFlush); + + if (NT_SUCCESS(Status)) + { + if (IsFlush) + { + USBH_FlushPortPwrList(HubExtension); + } + } +} + +VOID +NTAPI +USBH_IdleCompletePowerHubWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer; + + DPRINT("USBH_IdleCompletePowerHubWorker ... \n"); + + if (HubExtension && + HubExtension->CurrentPowerState.DeviceState != PowerDeviceD0 && + HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED) + { + USBH_HubSetD0(HubExtension); + } + + HubWorkItemBuffer = (PUSBHUB_IDLE_HUB_CONTEXT)Context; + + USBH_HubCompletePortIdleIrps(HubExtension, HubWorkItemBuffer->Status); + +} + +NTSTATUS +NTAPI +USBH_FdoIdleNotificationRequestComplete(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + NTSTATUS NtStatus; + LONG IdleIrp; + KIRQL Irql; + NTSTATUS Status; + PUSBHUB_IO_WORK_ITEM HubIoWorkItem; + + IoAcquireCancelSpinLock(&Irql); + + HubExtension = (PUSBHUB_FDO_EXTENSION)Context; + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST; + + IdleIrp = InterlockedExchange((PLONG)&HubExtension->PendingIdleIrp, 0); + DPRINT("USBH_FdoIdleNotificationRequestComplete: IdleIrp - %p\n", IdleIrp); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, EVENT_INCREMENT, FALSE); + } + + IoReleaseCancelSpinLock(Irql); + + NtStatus = Irp->IoStatus.Status; + DPRINT("USBH_FdoIdleNotificationRequestComplete: NtStatus - %p\n", NtStatus); + + if (!NT_SUCCESS(NtStatus) && + NtStatus != STATUS_POWER_STATE_INVALID && + !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) && + !(HubExtension->HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPED)) + { + DPRINT("USBH_FdoIdleNotificationRequestComplete: DeviceState - %x\n", + HubExtension->CurrentPowerState.DeviceState); + + if (HubExtension->CurrentPowerState.DeviceState == PowerDeviceD0) + { + PUSBHUB_IDLE_PORT_CONTEXT HubWorkItemBuffer; + + Status = USBH_AllocateWorkItem(HubExtension, + &HubIoWorkItem, + USBH_CompletePortIdleIrpsWorker, + sizeof(USBHUB_IDLE_PORT_CONTEXT), + (PVOID *)&HubWorkItemBuffer, + DelayedWorkQueue); + + if (NT_SUCCESS(Status)) + { + HubWorkItemBuffer->Status = NtStatus; + + USBH_HubQueuePortIdleIrps(HubExtension, + &HubWorkItemBuffer->PwrList); + + USBH_QueueWorkItem(HubExtension, HubIoWorkItem); + } + } + else + { + PUSBHUB_IDLE_HUB_CONTEXT HubWorkItemBuffer; + + Status = USBH_AllocateWorkItem(HubExtension, + &HubIoWorkItem, + USBH_IdleCompletePowerHubWorker, + sizeof(USBHUB_IDLE_HUB_CONTEXT), + (PVOID *)&HubWorkItemBuffer, + DelayedWorkQueue); + + if (NT_SUCCESS(Status)) + { + HubWorkItemBuffer->Status = NtStatus; + USBH_QueueWorkItem(HubExtension, HubIoWorkItem); + } + } + } + + if (IdleIrp || + InterlockedExchange((PLONG)&HubExtension->IdleRequestLock, 1)) + { + DPRINT("USBH_FdoIdleNotificationRequestComplete: Irp - %p\n", Irp); + IoFreeIrp(Irp); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBH_FdoSubmitIdleRequestIrp(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + NTSTATUS Status; + ULONG HubFlags; + PDEVICE_OBJECT LowerPDO; + PIRP Irp; + PIO_STACK_LOCATION IoStack; + KIRQL Irql; + + DPRINT("USBH_FdoSubmitIdleRequestIrp: HubExtension - %p, PendingIdleIrp - %p\n", + HubExtension, + HubExtension->PendingIdleIrp); + + if (HubExtension->PendingIdleIrp) + { + Status = STATUS_DEVICE_BUSY; + KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE); + return Status; + } + + HubFlags = HubExtension->HubFlags; + + if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING || + HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) + { + HubExtension->HubFlags = HubFlags & ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST; + KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE); + return STATUS_DEVICE_REMOVED; + } + + LowerPDO = HubExtension->LowerPDO; + + HubExtension->IdleCallbackInfo.IdleCallback = USBH_FdoIdleNotificationCallback; + HubExtension->IdleCallbackInfo.IdleContext = HubExtension; + + Irp = IoAllocateIrp(LowerPDO->StackSize, 0); + + if (!Irp) + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST; + Status = STATUS_INSUFFICIENT_RESOURCES; + + KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE); + return Status; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + + IoStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(USB_IDLE_CALLBACK_INFO); + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION; + IoStack->Parameters.DeviceIoControl.Type3InputBuffer = &HubExtension->IdleCallbackInfo; + + IoSetCompletionRoutine(Irp, + USBH_FdoIdleNotificationRequestComplete, + HubExtension, + TRUE, + TRUE, + TRUE); + + InterlockedIncrement(&HubExtension->PendingRequestCount); + InterlockedExchange(&HubExtension->IdleRequestLock, 0); + + HubExtension->HubFlags &= ~(USBHUB_FDO_FLAG_DEVICE_SUSPENDED | + USBHUB_FDO_FLAG_GOING_IDLE); + + Status = IoCallDriver(HubExtension->LowerPDO, Irp); + + IoAcquireCancelSpinLock(&Irql); + + if (Status == STATUS_PENDING && + HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST) + { + HubExtension->PendingIdleIrp = Irp; + } + + IoReleaseCancelSpinLock(Irql); + + KeSetEvent(&HubExtension->IdleEvent, EVENT_INCREMENT, FALSE); + + return Status; +} + +VOID +NTAPI +USBH_CheckHubIdle(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PDEVICE_OBJECT PdoDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSBHUB_PORT_DATA PortData; + ULONG HubFlags; + ULONG Port; + KIRQL Irql; + BOOLEAN IsHubIdle = FALSE; + BOOLEAN IsAllPortsIdle; + + DPRINT("USBH_CheckHubIdle: FIXME !!! HubExtension - %p\n", HubExtension); + +return; //HACK: delete it line after fixing Power Manager!!! + + KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql); + + if (HubExtension->HubFlags & USBHUB_FDO_FLAG_CHECK_IDLE_LOCK) + { + KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql); + return; + } + + HubExtension->HubFlags |= USBHUB_FDO_FLAG_CHECK_IDLE_LOCK; + KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql); + + if (USBH_GetRootHubExtension(HubExtension)->SystemPowerState.SystemState != PowerSystemWorking) + { + KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK; + KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql); + return; + } + + HubFlags = HubExtension->HubFlags; + DPRINT("USBH_CheckHubIdle: HubFlags - %p\n", HubFlags); + + if (HubFlags & USBHUB_FDO_FLAG_DEVICE_STARTED && + HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION) + { + if (!(HubFlags & USBHUB_FDO_FLAG_NOT_ENUMERATED) && + !(HubFlags & USBHUB_FDO_FLAG_ENUM_POST_RECOVER) && + !(HubFlags & USBHUB_FDO_FLAG_DEVICE_FAILED) && + !(HubFlags & USBHUB_FDO_FLAG_DEVICE_STOPPING) && + !(HubFlags & USBHUB_FDO_FLAG_DEVICE_REMOVED) && + !(HubFlags & USBHUB_FDO_FLAG_STATE_CHANGING) && + !(HubFlags & USBHUB_FDO_FLAG_WAKEUP_START) && + !(HubFlags & USBHUB_FDO_FLAG_ESD_RECOVERING)) + { + if (HubExtension->ResetRequestCount) + { + HubExtension->HubFlags |= USBHUB_FDO_FLAG_DEFER_CHECK_IDLE; + } + else + { + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_DEFER_CHECK_IDLE; + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + IoAcquireCancelSpinLock(&Irql); + + IsAllPortsIdle = TRUE; + + Port = 0; + + if (HubExtension->HubDescriptor->bNumberOfPorts) + { + PortData = HubExtension->PortData; + + while (TRUE) + { + PdoDevice = PortData[Port].DeviceObject; + + if (PdoDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PdoDevice->DeviceExtension; + + if (!PortExtension->IdleNotificationIrp) + { + DPRINT("USBH_CheckHubIdle: PortExtension - %p\n", PortExtension); + break; + } + } + + ++Port; + + if (Port >= HubExtension->HubDescriptor->bNumberOfPorts) + { + goto HubIdleCheck; + } + } + + IsAllPortsIdle = FALSE; + } + else + { + HubIdleCheck: + if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST)) + { + KeResetEvent(&HubExtension->IdleEvent); + HubExtension->HubFlags |= USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST; + IsHubIdle = TRUE; + } + } + + IoReleaseCancelSpinLock(Irql); + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + DPRINT("USBH_CheckHubIdle: IsAllPortsIdle - %x, IsHubIdle - %x\n", + IsAllPortsIdle, + IsHubIdle); + + if (IsAllPortsIdle && IsHubIdle) + { + USBH_FdoSubmitIdleRequestIrp(HubExtension); + } + } + } + } + + KeAcquireSpinLock(&HubExtension->CheckIdleSpinLock, &Irql); + HubExtension->HubFlags &= ~USBHUB_FDO_FLAG_CHECK_IDLE_LOCK; + KeReleaseSpinLock(&HubExtension->CheckIdleSpinLock, Irql); +} + +VOID +NTAPI +USBH_CheckIdleWorker(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context) +{ + DPRINT("USBH_CheckIdleWorker: ... \n"); + USBH_CheckHubIdle(HubExtension); +} + +VOID +NTAPI +USBH_CheckIdleDeferred(IN PUSBHUB_FDO_EXTENSION HubExtension) +{ + PUSBHUB_IO_WORK_ITEM HubIoWorkItem; + NTSTATUS Status; + + DPRINT("USBH_CheckIdleDeferred: HubExtension - %p\n", HubExtension); + + Status = USBH_AllocateWorkItem(HubExtension, + &HubIoWorkItem, + USBH_CheckIdleWorker, + 0, + NULL, + DelayedWorkQueue); + + DPRINT("USBH_CheckIdleDeferred: HubIoWorkItem - %p\n", HubIoWorkItem); + + if (NT_SUCCESS(Status)) + { + USBH_QueueWorkItem(HubExtension, HubIoWorkItem); + } +} + +VOID +NTAPI +USBH_PdoSetCapabilities(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension) +{ + PUSBHUB_FDO_EXTENSION HubExtension; + ULONG State; + SYSTEM_POWER_STATE SystemPowerState; + PDEVICE_POWER_STATE pDeviceState; + + DPRINT("USBH_PdoSetCapabilities ... \n"); + + HubExtension = PortExtension->HubExtension; + + PortExtension->Capabilities.Size = 64; + PortExtension->Capabilities.Version = 1; + + PortExtension->Capabilities.Removable = 1; + PortExtension->Capabilities.Address = PortExtension->PortNumber; + + if (PortExtension->SerialNumber) + { + PortExtension->Capabilities.UniqueID = 1; + } + else + { + PortExtension->Capabilities.UniqueID = 0; + } + + PortExtension->Capabilities.RawDeviceOK = 0; + + RtlCopyMemory(PortExtension->Capabilities.DeviceState, + HubExtension->DeviceState, + (PowerSystemMaximum + 2) * sizeof(POWER_STATE)); + + PortExtension->Capabilities.DeviceState[1] = PowerDeviceD0; + + if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOTE_WAKEUP) + { + PortExtension->Capabilities.DeviceWake = PowerDeviceD2; + + PortExtension->Capabilities.DeviceD1 = 1; + PortExtension->Capabilities.DeviceD2 = 1; + + PortExtension->Capabilities.WakeFromD0 = 1; + PortExtension->Capabilities.WakeFromD1 = 1; + PortExtension->Capabilities.WakeFromD2 = 1; + + pDeviceState = &PortExtension->Capabilities.DeviceState[2]; + + State = 2; + + do + { + SystemPowerState = State++; + + if (PortExtension->Capabilities.SystemWake < SystemPowerState) + { + *pDeviceState = PowerDeviceD3; + } + else + { + *pDeviceState = PowerDeviceD2; + } + + ++pDeviceState; + } + while (State <= 5); + } + else + { + PortExtension->Capabilities.DeviceWake = PowerDeviceD0; + PortExtension->Capabilities.DeviceState[2] = PowerDeviceD3; + PortExtension->Capabilities.DeviceState[3] = PowerDeviceD3; + PortExtension->Capabilities.DeviceState[4] = PowerDeviceD3; + PortExtension->Capabilities.DeviceState[5] = PowerDeviceD3; + } +} + +NTSTATUS +NTAPI +USBH_ProcessDeviceInformation(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension) +{ + PUSB_INTERFACE_DESCRIPTOR Pid; + PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; + NTSTATUS Status; + + DPRINT("USBH_ProcessDeviceInformation ... \n"); + + ConfigDescriptor = NULL; + + RtlZeroMemory(&PortExtension->InterfaceDescriptor, + sizeof(PortExtension->InterfaceDescriptor)); + + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_HUB_DEVICE; + + Status = USBH_GetConfigurationDescriptor(PortExtension->Common.SelfDevice, + &ConfigDescriptor); + + if (!NT_SUCCESS(Status)) + { + if (ConfigDescriptor) + { + ExFreePool(ConfigDescriptor); + } + + return Status; + } + + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOTE_WAKEUP; + + if (ConfigDescriptor->bmAttributes & 0x20) + { + /* device configuration supports remote wakeup */ + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOTE_WAKEUP; + } + + USBPORT_DumpingDeviceDescriptor(&PortExtension->DeviceDescriptor); + USBPORT_DumpingConfiguration(ConfigDescriptor); + + //DPRINT("USBH_ProcessDeviceInformation: Class - %x, SubClass - %x, Protocol - %x\n", + // PortExtension->DeviceDescriptor.bDeviceClass, + // PortExtension->DeviceDescriptor.bDeviceSubClass, + // PortExtension->DeviceDescriptor.bDeviceProtocol); + + //DPRINT("USBH_ProcessDeviceInformation: bNumConfigurations - %x, bNumInterfaces - %x\n", + // PortExtension->DeviceDescriptor.bNumConfigurations, + // ConfigDescriptor->bNumInterfaces); + + + /* Enumeration of USB Composite Devices (msdn): + 1) The device class field of the device descriptor (bDeviceClass) must contain a value of zero, + or the class (bDeviceClass), subclass (bDeviceSubClass), and protocol (bDeviceProtocol) + fields of the device descriptor must have the values 0xEF, 0x02 and 0x01 respectively, + as explained in USB Interface Association Descriptor. + 2) The device must have multiple interfaces + 3) The device must have a single configuration. + */ + + if (((PortExtension->DeviceDescriptor.bDeviceClass == USB_DEVICE_CLASS_RESERVED) || + (PortExtension->DeviceDescriptor.bDeviceClass == USBC_DEVICE_CLASS_MISCELLANEOUS && + PortExtension->DeviceDescriptor.bDeviceSubClass == 0x02 && + PortExtension->DeviceDescriptor.bDeviceProtocol == 0x01)) && + (ConfigDescriptor->bNumInterfaces > 1) && + (PortExtension->DeviceDescriptor.bNumConfigurations < 2)) + { + DPRINT("USBH_ProcessDeviceInformation: Multi-Interface configuration\n"); + //DbgBreakPoint(); + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_MULTI_INTERFACE; + + if (ConfigDescriptor) + { + ExFreePool(ConfigDescriptor); + } + + return Status; + } + + Pid = USBD_ParseConfigurationDescriptorEx(ConfigDescriptor, + ConfigDescriptor, + -1, + -1, + -1, + -1, + -1); + if (Pid) + { + RtlCopyMemory(&PortExtension->InterfaceDescriptor, + Pid, + sizeof(PortExtension->InterfaceDescriptor)); + + if (Pid->bInterfaceClass == USB_DEVICE_CLASS_HUB) + { + PortExtension->PortPdoFlags |= (USBHUB_PDO_FLAG_HUB_DEVICE | + USBHUB_PDO_FLAG_REMOTE_WAKEUP); + } + } + else + { + Status = STATUS_UNSUCCESSFUL; + } + + if (ConfigDescriptor) + { + ExFreePool(ConfigDescriptor); + } + + return Status; +} + +BOOLEAN +NTAPI +USBH_CheckDeviceIDUnique(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT idVendor, + IN USHORT idProduct, + IN PVOID SerialNumber, + IN USHORT SN_DescriptorLength) +{ + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + ULONG Port; + SIZE_T NumberBytes; + + DPRINT("USBH_CheckDeviceIDUnique: idVendor - 0x%04X, idProduct - 0x%04X\n", + idVendor, + idProduct); + + Port = 0; + + if (!HubExtension->HubDescriptor->bNumberOfPorts) + { + return TRUE; + } + + while (TRUE) + { + PortDevice = HubExtension->PortData[Port].DeviceObject; + + if (PortDevice) + { + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + if (PortExtension->DeviceDescriptor.idVendor == idVendor && + PortExtension->DeviceDescriptor.idProduct == idProduct && + PortExtension->SN_DescriptorLength == SN_DescriptorLength) + { + if (PortExtension->SerialNumber) + { + NumberBytes = RtlCompareMemory(PortExtension->SerialNumber, + SerialNumber, + SN_DescriptorLength); + + if (NumberBytes == SN_DescriptorLength) + { + break; + } + } + } + } + + ++Port; + + if (Port >= HubExtension->HubDescriptor->bNumberOfPorts) + { + return TRUE; + } + } + + return FALSE; +} + +BOOLEAN +NTAPI +USBH_ValidateSerialNumberString(IN PUSHORT SerialNumberString) +{ + USHORT Symbol; + + DPRINT("USBH_ValidateSerialNumberString: ... \n"); + + for (Symbol = *SerialNumberString; ; Symbol = *SerialNumberString) + { + if (!Symbol) + { + return TRUE; + } + + if (Symbol < 0x0020 || Symbol > 0x007F || Symbol == 0x002C) // ',' + { + break; + } + + ++SerialNumberString; + } + + return 0; +} + +NTSTATUS +NTAPI +USBH_CheckDeviceLanguage(IN PDEVICE_OBJECT DeviceObject, + IN USHORT LanguageId) +{ + PUSB_STRING_DESCRIPTOR Descriptor; + NTSTATUS Status; + ULONG NumSymbols; + ULONG ix = 0; + PWCHAR pSymbol; + ULONG Length; + + DPRINT("USBH_CheckDeviceLanguage: LanguageId - 0x%04X\n", LanguageId); + + Descriptor = ExAllocatePoolWithTag(NonPagedPool, 0xFF, USB_HUB_TAG); + + if (!Descriptor) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Descriptor, 0xFF); + + Status = USBH_SyncGetStringDescriptor(DeviceObject, + 0, + 0, + Descriptor, + 0xFF, + &Length, + TRUE); + + if (NT_SUCCESS(Status)) + { + if (Length >= 2) + { + NumSymbols = (Length - 2) >> 1; + } + else + { + NumSymbols = 0; + } + + pSymbol = Descriptor->bString; + + if (NumSymbols > 0) + { + while (*pSymbol != (WCHAR)LanguageId) + { + ++pSymbol; + ++ix; + + if (ix >= NumSymbols) + { + ExFreePool(Descriptor); + return STATUS_NOT_SUPPORTED; + } + } + + Status = STATUS_SUCCESS; + } + } + + ExFreePool(Descriptor); + + return Status; +} + +NTSTATUS +NTAPI +USBH_GetSerialNumberString(IN PDEVICE_OBJECT DeviceObject, + IN LPWSTR * OutSerialNumber, + IN PUSHORT OutDescriptorLength, + IN USHORT LanguageId, + IN UCHAR Index) +{ + PUSB_STRING_DESCRIPTOR Descriptor; + NTSTATUS Status; + LPWSTR SerialNumberBuffer = NULL; + + DPRINT("USBH_GetSerialNumberString: ... \n"); + + *OutSerialNumber = NULL; + *OutDescriptorLength = 0; + + Descriptor = ExAllocatePoolWithTag(NonPagedPool, 0xFF, USB_HUB_TAG); + + if (!Descriptor) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Descriptor, 0xFF); + + Status = USBH_CheckDeviceLanguage(DeviceObject, LanguageId); + + if (!NT_SUCCESS(Status)) + { + ExFreePool(Descriptor); + return Status; + } + + Status = USBH_SyncGetStringDescriptor(DeviceObject, + Index, + LanguageId, + Descriptor, + 0xFF, + 0, + TRUE); + + if (NT_SUCCESS(Status) && Descriptor->bLength > 2) + { + SerialNumberBuffer = ExAllocatePoolWithTag(PagedPool, + Descriptor->bLength, + USB_HUB_TAG); + + if (SerialNumberBuffer) + { + RtlZeroMemory(SerialNumberBuffer, Descriptor->bLength); + + RtlCopyMemory(SerialNumberBuffer, + Descriptor->bString, + Descriptor->bLength - 2); + + *OutSerialNumber = SerialNumberBuffer; + *OutDescriptorLength = Descriptor->bLength; + } + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + ExFreePool(Descriptor); + + return Status; +} + +NTSTATUS +NTAPI +USBH_CreateDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN USB_PORT_STATUS UsbPortStatus, + IN ULONG IsWait) +{ + ULONG PdoNumber = 0; + WCHAR CharDeviceName[64]; + UNICODE_STRING DeviceName; + PDEVICE_OBJECT DeviceObject = NULL; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PUSB_DEVICE_HANDLE DeviceHandle; + LPWSTR SerialNumberBuffer; + BOOLEAN IsHsDevice; + BOOLEAN IsLsDevice; + BOOLEAN IgnoringHwSerial = FALSE; + NTSTATUS Status; + UNICODE_STRING DestinationString; + + DPRINT("USBH_CreateDevice: Port - %x, UsbPortStatus - %p\n", + Port, + UsbPortStatus.AsUSHORT); + + do + { + swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", PdoNumber); + RtlInitUnicodeString(&DeviceName, CharDeviceName); + + Status = IoCreateDevice(HubExtension->Common.SelfDevice->DriverObject, + sizeof(USBHUB_PORT_PDO_EXTENSION), + &DeviceName, + FILE_DEVICE_USB, + 0, + FALSE, + &DeviceObject); + + ++PdoNumber; + } + while (Status == STATUS_OBJECT_NAME_COLLISION); + + if (!NT_SUCCESS(Status)) + { + HubExtension->PortData[Port-1].DeviceObject = DeviceObject; + return Status; + } + + DeviceObject->StackSize = HubExtension->RootHubPdo2->StackSize; + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)DeviceObject->DeviceExtension; + + DPRINT("USBH_CreateDevice: PortDevice - %p, <%wZ>\n", DeviceObject, &DeviceName); + DPRINT("USBH_CreateDevice: PortExtension - %p\n", PortExtension); + + RtlZeroMemory(PortExtension, sizeof(USBHUB_PORT_PDO_EXTENSION)); + + PortExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_PORT; + PortExtension->Common.SelfDevice = DeviceObject; + + PortExtension->HubExtension = HubExtension; + PortExtension->RootHubExtension = HubExtension; + + PortExtension->PortNumber = Port; + PortExtension->CurrentPowerState.DeviceState = PowerDeviceD0; + PortExtension->IgnoringHwSerial = FALSE; + + KeInitializeSpinLock(&PortExtension->PortTimeoutSpinLock); + + InitializeListHead(&PortExtension->PortPowerList); + KeInitializeSpinLock(&PortExtension->PortPowerListSpinLock); + + PortExtension->PoRequestCounter = 0; + PortExtension->PendingSystemPoRequest = 0; + PortExtension->PendingDevicePoRequest = 0; + PortExtension->StateBehindD2 = 0; + + SerialNumberBuffer = NULL; + + IsHsDevice = UsbPortStatus.HsDeviceAttached; // High-speed Device Attached + IsLsDevice = UsbPortStatus.LsDeviceAttached; // Low-Speed Device Attached + + if (IsLsDevice == 0) + { + if (IsHsDevice) + { + PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_HIGH_SPEED; + } + } + else + { + PortExtension->PortPdoFlags = USBHUB_PDO_FLAG_PORT_LOW_SPEED; + } + + /* Initialize PortExtension->InstanceID */ + RtlInitUnicodeString(&DestinationString, (PCWSTR)&PortExtension->InstanceID); + DestinationString.MaximumLength = 4 * sizeof(WCHAR); + Status = RtlIntegerToUnicodeString(Port, 10, &DestinationString); + + DeviceObject->Flags |= DO_POWER_PAGABLE; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_CreateDevice: IoCreateDevice() failed - %p\n", Status); + goto ErrorExit; + } + + Status = USBD_CreateDeviceEx(HubExtension, + &PortExtension->DeviceHandle, + UsbPortStatus, + Port); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_CreateDevice: USBD_CreateDeviceEx() failed - %p\n", Status); + goto ErrorExit; + } + + Status = USBH_SyncResetPort(HubExtension, Port); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_CreateDevice: USBH_SyncResetPort() failed - %p\n", Status); + goto ErrorExit; + } + + if (IsWait) + { + USBH_Wait(50); + } + + Status = USBD_InitializeDeviceEx(HubExtension, + PortExtension->DeviceHandle, + (PUCHAR)&PortExtension->DeviceDescriptor, + sizeof(USB_DEVICE_DESCRIPTOR), + (PUCHAR)&PortExtension->ConfigDescriptor, + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_CreateDevice: USBD_InitializeDeviceEx() failed - %p\n", Status); + PortExtension->DeviceHandle = NULL; + goto ErrorExit; + } + + DPRINT1("USBH_RegQueryDeviceIgnoreHWSerNumFlag UNIMPLEMENTED. FIXME. \n"); + //Status = USBH_RegQueryDeviceIgnoreHWSerNumFlag(PortExtension->DeviceDescriptor.idVendor, + // PortExtension->DeviceDescriptor.idProduct, + // &IgnoringHwSerial); + + if (TRUE)//Status == STATUS_OBJECT_NAME_NOT_FOUND) + { + IgnoringHwSerial = FALSE; + } + + if (IgnoringHwSerial) + { + PortExtension->IgnoringHwSerial = TRUE; + } + + if (PortExtension->DeviceDescriptor.iSerialNumber && + !PortExtension->IgnoringHwSerial) + { + InterlockedExchange((PLONG)&PortExtension->SerialNumber, 0); + + USBH_GetSerialNumberString(PortExtension->Common.SelfDevice, + &SerialNumberBuffer, + &PortExtension->SN_DescriptorLength, + 0x0409, + PortExtension->DeviceDescriptor.iSerialNumber); + + if (SerialNumberBuffer) + { + if (!USBH_ValidateSerialNumberString((PUSHORT)SerialNumberBuffer)) + { + ExFreePool(SerialNumberBuffer); + SerialNumberBuffer = NULL; + } + + if (SerialNumberBuffer && + !USBH_CheckDeviceIDUnique(HubExtension, + PortExtension->DeviceDescriptor.idVendor, + PortExtension->DeviceDescriptor.idProduct, + SerialNumberBuffer, + PortExtension->SN_DescriptorLength)) + { + ExFreePool(SerialNumberBuffer); + SerialNumberBuffer = NULL; + } + } + + InterlockedExchange((PLONG)&PortExtension->SerialNumber, + (LONG)SerialNumberBuffer); + } + + Status = USBH_ProcessDeviceInformation(PortExtension); + + USBH_PdoSetCapabilities(PortExtension); + + if (NT_SUCCESS(Status)) + { + goto Exit; + } + +ErrorExit: + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_INIT_PORT_FAILED; + + DeviceHandle = (PUSB_DEVICE_HANDLE)InterlockedExchange((PLONG)&PortExtension->DeviceHandle, + 0); + + if (DeviceHandle) + { + USBD_RemoveDeviceEx(HubExtension, DeviceHandle, 0); + } + + SerialNumberBuffer = (LPWSTR)InterlockedExchange((PLONG)&PortExtension->SerialNumber, + 0); + + if (SerialNumberBuffer) + { + ExFreePool(SerialNumberBuffer); + } + +Exit: + + HubExtension->PortData[Port-1].DeviceObject = DeviceObject; + return Status; +} + +NTSTATUS +NTAPI +USBH_ResetDevice(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN BOOLEAN IsKeepDeviceData, + IN BOOLEAN IsWait) +{ + NTSTATUS Status; + PUSBHUB_PORT_DATA PortData; + PDEVICE_OBJECT PortDevice; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + LONG NewDeviceHandle; + LONG Handle; + LONG OldDeviceHandle; + PUSB_DEVICE_HANDLE * DeviceHandle; + USBHUB_PORT_STATUS PortStatus; + + DPRINT("USBH_ResetDevice: HubExtension - %p, Port - %x, IsKeepDeviceData - %x, IsWait - %x\n", + HubExtension, + Port, + IsKeepDeviceData, + IsWait); + + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + if (!NT_SUCCESS(Status) || + !(PortStatus.UsbPortStatus.ConnectStatus)) + { + return STATUS_UNSUCCESSFUL; + } + + InterlockedIncrement(&HubExtension->PendingRequestCount); + + KeWaitForSingleObject(&HubExtension->ResetDeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + PortData = &HubExtension->PortData[Port-1]; + + PortDevice = PortData->DeviceObject; + + if (!PortDevice) + { + Status = STATUS_INVALID_PARAMETER; + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + return Status; + } + + PortExtension = (PUSBHUB_PORT_PDO_EXTENSION)PortDevice->DeviceExtension; + + DeviceHandle = &PortExtension->DeviceHandle; + OldDeviceHandle = InterlockedExchange((PLONG)&PortExtension->DeviceHandle, 0); + + if (OldDeviceHandle) + { + if (!(PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_REMOVING_PORT_PDO)) + { + Status = USBD_RemoveDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)OldDeviceHandle, + IsKeepDeviceData); + + PortExtension->PortPdoFlags |= USBHUB_PDO_FLAG_REMOVING_PORT_PDO; + } + } + else + { + OldDeviceHandle = 0; + } + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + Status = USBH_SyncResetPort(HubExtension, Port); + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + Status = USBH_SyncGetPortStatus(HubExtension, + Port, + &PortStatus, + sizeof(USBHUB_PORT_STATUS)); + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + Status = USBD_CreateDeviceEx(HubExtension, + DeviceHandle, + PortStatus.UsbPortStatus, + Port); + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + Status = USBH_SyncResetPort(HubExtension, Port); + + if (IsWait) + { + USBH_Wait(50); + } + + if (!NT_SUCCESS(Status)) + { + goto ErrorExit; + } + + Status = USBD_InitializeDeviceEx(HubExtension, + *DeviceHandle, + &PortExtension->DeviceDescriptor.bLength, + sizeof(PortExtension->DeviceDescriptor), + &PortExtension->ConfigDescriptor.bLength, + sizeof(PortExtension->ConfigDescriptor)); + + if (NT_SUCCESS(Status)) + { + if (IsKeepDeviceData) + { + Status = USBD_RestoreDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)OldDeviceHandle, + *DeviceHandle); + + if (!NT_SUCCESS(Status)) + { + Handle = InterlockedExchange((PLONG)DeviceHandle, 0); + + USBD_RemoveDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)Handle, + 0); + + USBH_SyncDisablePort(HubExtension, Port); + + Status = STATUS_NO_SUCH_DEVICE; + } + } + else + { + PortExtension->PortPdoFlags &= ~USBHUB_PDO_FLAG_REMOVING_PORT_PDO; + } + + goto Exit; + } + + *DeviceHandle = NULL; + +ErrorExit: + + NewDeviceHandle = InterlockedExchange((PLONG)DeviceHandle, OldDeviceHandle); + + if (NewDeviceHandle) + { + Status = USBD_RemoveDeviceEx(HubExtension, + (PUSB_DEVICE_HANDLE)NewDeviceHandle, + 0); + } + +Exit: + + KeReleaseSemaphore(&HubExtension->ResetDeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + if (!InterlockedDecrement(&HubExtension->PendingRequestCount)) + { + KeSetEvent(&HubExtension->PendingRequestEvent, + EVENT_INCREMENT, + FALSE); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_PdoDispatch(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + UCHAR MajorFunction; + BOOLEAN IsCompleteIrp; + ULONG ControlCode; + NTSTATUS Status; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + MajorFunction = IoStack->MajorFunction; + + switch (MajorFunction) + { + case IRP_MJ_CREATE: + case IRP_MJ_CLOSE: + DPRINT("USBH_PdoDispatch: IRP_MJ_CREATE / IRP_MJ_CLOSE (%d)\n", + MajorFunction); + Status = STATUS_SUCCESS; + USBH_CompleteIrp(Irp, Status); + break; + + case IRP_MJ_DEVICE_CONTROL: + ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + DPRINT("USBH_PdoDispatch: IRP_MJ_DEVICE_CONTROL ControlCode - %x\n", + ControlCode); + + if (ControlCode == 0X2D0C10)//IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER + { + Status = STATUS_NOT_SUPPORTED; + USBH_CompleteIrp(Irp, Status); + break; + } + + if (ControlCode == 0x2F0003)//IOCTL_KS_PROPERTY + { + DPRINT1("USBH_PdoDispatch: IOCTL_KS_PROPERTY FIXME. \n"); + DbgBreakPoint(); + Status = STATUS_NOT_SUPPORTED; + USBH_CompleteIrp(Irp, Status); + break; + } + + Status = Irp->IoStatus.Status; + USBH_CompleteIrp(Irp, Status); + break; + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + Status = USBH_PdoInternalControl(PortExtension, Irp); + break; + + case IRP_MJ_PNP: + Status = USBH_PdoPnP(PortExtension, + Irp, + IoStack->MinorFunction, + &IsCompleteIrp); + + if (IsCompleteIrp) + { + USBH_CompleteIrp(Irp, Status); + } + + break; + + case IRP_MJ_POWER: + Status = USBH_PdoPower(PortExtension, Irp, IoStack->MinorFunction); + break; + + case IRP_MJ_SYSTEM_CONTROL: + DPRINT1("USBH_PdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n"); + Status = STATUS_NOT_SUPPORTED;//USBH_PortSystemControl(PortExtension, Irp); + break; + + default: + DPRINT("USBH_PdoDispatch: Unhandled MajorFunction - %d\n", MajorFunction); + Status = Irp->IoStatus.Status; + USBH_CompleteIrp(Irp, Status); + break; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_FdoDispatch(IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + UCHAR MajorFunction; + NTSTATUS Status; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + + DPRINT("USBH_FdoDispatch: HubExtension - %p, Irp - %p, MajorFunction - %d\n", + HubExtension, + Irp, + IoStack->MajorFunction); + + MajorFunction = IoStack->MajorFunction; + + switch (MajorFunction) + { + case IRP_MJ_CREATE: + case IRP_MJ_CLOSE: + USBH_CompleteIrp(Irp, STATUS_SUCCESS); + break; + + case IRP_MJ_DEVICE_CONTROL: + Status = USBH_DeviceControl(HubExtension, Irp); + break; + + case IRP_MJ_PNP: + Status = USBH_FdoPnP(HubExtension, Irp, IoStack->MinorFunction); + break; + + case IRP_MJ_POWER: + Status = USBH_FdoPower(HubExtension, Irp, IoStack->MinorFunction); + break; + + case IRP_MJ_SYSTEM_CONTROL: + DPRINT1("USBH_FdoDispatch: USBH_SystemControl() UNIMPLEMENTED. FIXME\n"); + //Status USBH_SystemControl(HubExtension, Irp); + break; + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + default: + Status = USBH_PassIrp(HubExtension->LowerDevice, Irp); + break; + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_AddDevice(IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT LowerPDO) +{ + PDEVICE_OBJECT DeviceObject; + NTSTATUS Status; + PUSBHUB_FDO_EXTENSION HubExtension; + PDEVICE_OBJECT LowerDevice; + + DPRINT("USBH_AddDevice: DriverObject - %p, LowerPDO - %p\n", + DriverObject, + LowerPDO); + + DeviceObject = NULL; + + Status = IoCreateDevice(DriverObject, + sizeof(USBHUB_FDO_EXTENSION), + NULL, + 0x8600, + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, + &DeviceObject); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("USBH_AddDevice: IoCreateDevice() fail\n"); + + if (DeviceObject) + { + IoDeleteDevice(DeviceObject); + } + + return Status; + } + + DPRINT("USBH_AddDevice: DeviceObject - %p\n", DeviceObject); + + HubExtension = (PUSBHUB_FDO_EXTENSION)DeviceObject->DeviceExtension; + RtlZeroMemory(HubExtension, sizeof(USBHUB_FDO_EXTENSION)); + + HubExtension->Common.ExtensionType = USBH_EXTENSION_TYPE_HUB; + + LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, LowerPDO); + + if (!LowerDevice) + { + DPRINT1("USBH_AddDevice: IoAttachDeviceToDeviceStack() fail\n"); + + if (DeviceObject) + { + IoDeleteDevice(DeviceObject); + } + + return STATUS_UNSUCCESSFUL; + } + + DPRINT("USBH_AddDevice: LowerDevice - %p\n", LowerDevice); + + HubExtension->Common.SelfDevice = DeviceObject; + + HubExtension->LowerPDO = LowerPDO; + HubExtension->LowerDevice = LowerDevice; + + KeInitializeSemaphore(&HubExtension->IdleSemaphore, 1, 1); + + DeviceObject->Flags |= DO_POWER_PAGABLE; + DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + DPRINT("USBH_AddDevice: call IoWMIRegistrationControl() UNIMPLEMENTED. FIXME. \n"); + + return Status; +} + +VOID +NTAPI +USBH_DriverUnload(IN PDRIVER_OBJECT DriverObject) +{ + DPRINT("USBH_DriverUnload: UNIMPLEMENTED\n"); + + if (GenericUSBDeviceString) + { + ExFreePool(GenericUSBDeviceString); + GenericUSBDeviceString = NULL; + } +} + +NTSTATUS +NTAPI +USBH_HubDispatch(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PCOMMON_DEVICE_EXTENSION DeviceExtension; + ULONG ExtensionType; + NTSTATUS Status; + + + DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + ExtensionType = DeviceExtension->ExtensionType; + + if (ExtensionType == USBH_EXTENSION_TYPE_HUB) + { + DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n", + DeviceObject, + Irp); + + Status = USBH_FdoDispatch((PUSBHUB_FDO_EXTENSION)DeviceExtension, Irp); + } + else if (ExtensionType == USBH_EXTENSION_TYPE_PORT) + { + PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); + UCHAR MajorFunction = IoStack->MajorFunction; + BOOLEAN IsDprint = TRUE; + + if (MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) + { + ULONG ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + + if (ControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB) + { + IsDprint = FALSE; + } + } + + if (IsDprint) + { + DPRINT("USBH_HubDispatch: DeviceObject - %p, Irp - %p\n", + DeviceObject, + Irp); + } + + Status = USBH_PdoDispatch((PUSBHUB_PORT_PDO_EXTENSION)DeviceExtension, Irp); + } + else + { + DPRINT1("USBH_HubDispatch: Unknown ExtensionType - %x\n", ExtensionType); + DbgBreakPoint(); + } + + return Status; +} + +NTSTATUS +NTAPI +USBH_RegQueryGenericUSBDeviceString(PVOID USBDeviceString) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + + DPRINT("USBH_RegQueryGenericUSBDeviceString ... \n"); + + QueryTable[0].QueryRoutine = USBH_GetConfigValue; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].Name = L"GenericUSBDeviceString"; + QueryTable[0].EntryContext = USBDeviceString; + QueryTable[0].DefaultType = REG_NONE; + QueryTable[0].DefaultData = 0; + QueryTable[0].DefaultLength = 0; + + return RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, + L"usbflags", + QueryTable, + NULL, + NULL); +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + DPRINT("USBHUB: DriverEntry - %wZ\n", RegistryPath); + + DriverObject->DriverExtension->AddDevice = USBH_AddDevice; + DriverObject->DriverUnload = USBH_DriverUnload; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = USBH_HubDispatch; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBH_HubDispatch; + + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBH_HubDispatch; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBH_HubDispatch; + + DriverObject->MajorFunction[IRP_MJ_PNP] = USBH_HubDispatch; + DriverObject->MajorFunction[IRP_MJ_POWER] = USBH_HubDispatch; + DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBH_HubDispatch; + + USBH_RegQueryGenericUSBDeviceString(&GenericUSBDeviceString); + + return STATUS_SUCCESS; +} + diff --git a/reactos/drivers/usb/usbhub_new/usbhub.h b/reactos/drivers/usb/usbhub_new/usbhub.h new file mode 100644 index 00000000000..8b826601202 --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/usbhub.h @@ -0,0 +1,643 @@ +#ifndef _USBHUB_H_ +#define _USBHUB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "..\usbmport.h" + +#define USB_HUB_TAG 'BUHU' + +#define USBH_EXTENSION_TYPE_HUB 0x01 +#define USBH_EXTENSION_TYPE_PORT 0x02 +#define USBH_EXTENSION_TYPE_PARENT 0x04 +#define USBH_EXTENSION_TYPE_FUNCTION 0x08 + +#define USBHUB_FDO_FLAG_DEVICE_STARTED (1 << 0) // 0x00000001 +#define USBHUB_FDO_FLAG_DEVICE_STOPPING (1 << 2) // 0x00000004 +#define USBHUB_FDO_FLAG_DEVICE_FAILED (1 << 3) // 0x00000008 +#define USBHUB_FDO_FLAG_REMOTE_WAKEUP (1 << 4) // 0x00000010 +#define USBHUB_FDO_FLAG_DEVICE_STOPPED (1 << 5) // 0x00000020 +#define USBHUB_FDO_FLAG_HUB_BUSY (1 << 6) // 0x00000040 +#define USBHUB_FDO_FLAG_PENDING_WAKE_IRP (1 << 7) // 0x00000080 +#define USBHUB_FDO_FLAG_RESET_PORT_LOCK (1 << 8) // 0x00000100 +#define USBHUB_FDO_FLAG_ESD_RECOVERING (1 << 9) // 0x00000200 +#define USBHUB_FDO_FLAG_SET_D0_STATE (1 << 10) // 0x00000400 +#define USBHUB_FDO_FLAG_NOT_D0_STATE (1 << 11) // 0x00000800 +#define USBHUB_FDO_FLAG_WAIT_IDLE_REQUEST (1 << 12) // 0x00001000 +#define USBHUB_FDO_FLAG_STATE_CHANGING (1 << 13) // 0x00002000 +#define USBHUB_FDO_FLAG_DEVICE_REMOVED (1 << 14) // 0x00004000 +#define USBHUB_FDO_FLAG_USB20_HUB (1 << 15) // 0x00008000 +#define USBHUB_FDO_FLAG_DEFER_CHECK_IDLE (1 << 16) // 0x00010000 +#define USBHUB_FDO_FLAG_WAKEUP_START (1 << 17) // 0x00020000 +#define USBHUB_FDO_FLAG_MULTIPLE_TTS (1 << 18) // 0x00040000 // High-speed Operating Hub with Multiple TTs +#define USBHUB_FDO_FLAG_ENUM_POST_RECOVER (1 << 19) // 0x00080000 +#define USBHUB_FDO_FLAG_DO_ENUMERATION (1 << 20) // 0x00100000 +#define USBHUB_FDO_FLAG_CHECK_IDLE_LOCK (1 << 21) // 0x00200000 +#define USBHUB_FDO_FLAG_HIBERNATE_STATE (1 << 22) // 0x00400000 +#define USBHUB_FDO_FLAG_NOT_ENUMERATED (1 << 23) // 0x00800000 +#define USBHUB_FDO_FLAG_DO_SUSPENSE (1 << 24) // 0x01000000 +#define USBHUB_FDO_FLAG_GOING_IDLE (1 << 25) // 0x02000000 +#define USBHUB_FDO_FLAG_DEVICE_SUSPENDED (1 << 26) // 0x04000000 +#define USBHUB_FDO_FLAG_WITEM_INIT (1 << 27) // 0x08000000 + +#define USBHUB_PDO_FLAG_HUB_DEVICE (1 << 0) // 0x00000001 +#define USBHUB_PDO_FLAG_MULTI_INTERFACE (1 << 1) // 0x00000002 +#define USBHUB_PDO_FLAG_INIT_PORT_FAILED (1 << 2) // 0x00000004 +#define USBHUB_PDO_FLAG_PORT_LOW_SPEED (1 << 3) // 0x00000008 +#define USBHUB_PDO_FLAG_REMOTE_WAKEUP (1 << 4) // 0x00000010 +#define USBHUB_PDO_FLAG_WAIT_WAKE (1 << 5) // 0x00000020 +#define USBHUB_PDO_FLAG_NOT_CONNECTED (1 << 6) // 0x00000040 +#define USBHUB_PDO_FLAG_DELETE_PENDING (1 << 7) // 0x00000080 +#define USBHUB_PDO_FLAG_POWER_D3 (1 << 8) // 0x00000100 +#define USBHUB_PDO_FLAG_DEVICE_STARTED (1 << 9) // 0x00000200 +#define USBHUB_PDO_FLAG_HS_USB1_DUALMODE (1 << 10) // 0x00000400 +#define USBHUB_PDO_FLAG_REG_DEV_INTERFACE (1 << 11) // 0x00000800 // SymbolicLink +#define USBHUB_PDO_FLAG_PORT_RESTORE_FAIL (1 << 12) // 0x00001000 +#define USBHUB_PDO_FLAG_POWER_D1_OR_D2 (1 << 13) // 0x00002000 +#define USBHUB_PDO_FLAG_OVERCURRENT_PORT (1 << 14) // 0x00004000 +#define USBHUB_PDO_FLAG_REMOVING_PORT_PDO (1 << 15) // 0x00008000 +#define USBHUB_PDO_FLAG_INSUFFICIENT_PWR (1 << 16) // 0x00010000 +#define USBHUB_PDO_FLAG_ALLOC_BNDW_FAILED (1 << 18) // 0x00040000 +#define USBHUB_PDO_FLAG_PORT_RESSETING (1 << 19) // 0x00080000 +#define USBHUB_PDO_FLAG_IDLE_NOTIFICATION (1 << 22) // 0x00400000 +#define USBHUB_PDO_FLAG_PORT_HIGH_SPEED (1 << 23) // 0x00800000 + +#define USBHUB_ENUM_FLAG_DEVICE_PRESENT 0x01 +#define USBHUB_ENUM_FLAG_GHOST_DEVICE 0x02 + +/* Hub Class Feature Selectors */ + +#define USBHUB_FEATURE_USBHUB_FEATURE_C_HUB_LOCAL_POWER 0 +#define USBHUB_FEATURE_C_HUB_OVER_CURRENT 1 + +#define USBHUB_FEATURE_PORT_CONNECTION 0 +#define USBHUB_FEATURE_PORT_ENABLE 1 +#define USBHUB_FEATURE_PORT_SUSPEND 2 +#define USBHUB_FEATURE_PORT_OVER_CURRENT 3 +#define USBHUB_FEATURE_PORT_RESET 4 +#define USBHUB_FEATURE_PORT_POWER 8 +#define USBHUB_FEATURE_PORT_LOW_SPEED 9 +#define USBHUB_FEATURE_C_PORT_CONNECTION 16 +#define USBHUB_FEATURE_C_PORT_ENABLE 17 +#define USBHUB_FEATURE_C_PORT_SUSPEND 18 +#define USBHUB_FEATURE_C_PORT_OVER_CURRENT 19 +#define USBHUB_FEATURE_C_PORT_RESET 20 +#define USBHUB_FEATURE_PORT_TEST 21 +#define USBHUB_FEATURE_PORT_INDICATOR 22 + +extern PVOID GenericUSBDeviceString; + +typedef struct _USBHUB_PORT_DATA { + USBHUB_PORT_STATUS PortStatus; + PDEVICE_OBJECT DeviceObject; + USB_CONNECTION_STATUS ConnectionStatus; + ULONG PortAttributes; +} USBHUB_PORT_DATA, *PUSBHUB_PORT_DATA; + +typedef struct _USBHUB_FDO_EXTENSION *PUSBHUB_FDO_EXTENSION; + +typedef VOID +(NTAPI * PUSBHUB_WORKER_ROUTINE)( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context); + +typedef struct _USBHUB_IO_WORK_ITEM { + ULONG Reserved; + LIST_ENTRY HubWorkItemLink; + LONG HubWorkerQueued; + PIO_WORKITEM HubWorkItem; + WORK_QUEUE_TYPE HubWorkItemType; + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_WORKER_ROUTINE HubWorkerRoutine; + PVOID HubWorkItemBuffer; +} USBHUB_IO_WORK_ITEM, *PUSBHUB_IO_WORK_ITEM; + +typedef struct _COMMON_DEVICE_EXTENSION { + ULONG ExtensionType; + PDEVICE_OBJECT SelfDevice; +} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION; + +typedef struct _USBHUB_FDO_EXTENSION { + COMMON_DEVICE_EXTENSION Common; + PDEVICE_OBJECT LowerPDO; + PDEVICE_OBJECT LowerDevice; + PDEVICE_OBJECT RootHubPdo; + PDEVICE_OBJECT RootHubPdo2; + KEVENT LowerDeviceEvent; + ULONG HubFlags; + USB_BUS_INTERFACE_HUB_V5 BusInterface; + USB_BUS_INTERFACE_USBDI_V2 BusInterfaceUSBDI; + DEVICE_POWER_STATE DeviceState[POWER_SYSTEM_MAXIMUM]; + SYSTEM_POWER_STATE SystemWake; + DEVICE_POWER_STATE DeviceWake; + POWER_STATE CurrentPowerState; + POWER_STATE SystemPowerState; + ULONG MaxPower; + USB_DEVICE_DESCRIPTOR HubDeviceDescriptor; + USHORT Port; + PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor; + PUSB_HUB_DESCRIPTOR HubDescriptor; + PUSBHUB_PORT_DATA PortData; + USBD_CONFIGURATION_HANDLE ConfigHandle; + USBD_PIPE_INFORMATION PipeInfo; + PIRP SCEIrp; + PIRP ResetPortIrp; + PVOID SCEBitmap; + ULONG SCEBitmapLength; + KEVENT RootHubNotificationEvent; + struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST SCEWorkerUrb; + KEVENT StatusChangeEvent; + KSEMAPHORE IdleSemaphore; + KSPIN_LOCK RelationsWorkerSpinLock; + LIST_ENTRY PdoList; + LONG PendingRequestCount; + KEVENT PendingRequestEvent; + KSEMAPHORE ResetDeviceSemaphore; + PRKEVENT pResetPortEvent; + KSEMAPHORE HubPortSemaphore; + LONG ResetRequestCount; + KEVENT ResetEvent; + PIRP PendingIdleIrp; + PIRP PendingWakeIrp; + LONG FdoWaitWakeLock; + LIST_ENTRY WorkItemList; + KSPIN_LOCK WorkItemSpinLock; + KSPIN_LOCK CheckIdleSpinLock; + KEVENT IdleEvent; + LONG IdleRequestLock; + ULONG RequestErrors; + KSEMAPHORE HubSemaphore; + PUSBHUB_IO_WORK_ITEM WorkItemToQueue; + USB_IDLE_CALLBACK_INFO IdleCallbackInfo; + USBHUB_PORT_STATUS PortStatus; + PIRP PowerIrp; +} USBHUB_FDO_EXTENSION, *PUSBHUB_FDO_EXTENSION; + +typedef struct _USBHUB_PORT_PDO_EXTENSION { + COMMON_DEVICE_EXTENSION Common; + ULONG PortPdoFlags; + ULONG EnumFlags; + UNICODE_STRING SymbolicLinkName; + WCHAR InstanceID[4]; + PUSBHUB_FDO_EXTENSION HubExtension; + PUSBHUB_FDO_EXTENSION RootHubExtension; + PUSB_DEVICE_HANDLE DeviceHandle; + USHORT PortNumber; + USHORT SN_DescriptorLength; + BOOL IgnoringHwSerial; + LPWSTR SerialNumber; // serial number string + USB_DEVICE_DESCRIPTOR DeviceDescriptor; + USB_DEVICE_DESCRIPTOR OldDeviceDescriptor; + USB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USHORT Reserved1; + PIRP IdleNotificationIrp; + POWER_STATE CurrentPowerState; + DEVICE_CAPABILITIES Capabilities; + ULONG MaxPower; + PVOID BndwTimeoutContext; + KSPIN_LOCK PortTimeoutSpinLock; + LIST_ENTRY PortLink; + LONG PoRequestCounter; + LONG PendingSystemPoRequest; + LONG PendingDevicePoRequest; + LONG StateBehindD2; + PIRP PdoWaitWakeIrp; + LIST_ENTRY PortPowerList; + KSPIN_LOCK PortPowerListSpinLock; +} USBHUB_PORT_PDO_EXTENSION, *PUSBHUB_PORT_PDO_EXTENSION; + +typedef struct _USBHUB_URB_TIMEOUT_CONTEXT { + PIRP Irp; + KEVENT UrbTimeoutEvent; + KDPC UrbTimeoutDPC; + KTIMER UrbTimeoutTimer; + KSPIN_LOCK UrbTimeoutSpinLock; + BOOL IsNormalCompleted; +} USBHUB_URB_TIMEOUT_CONTEXT, *PUSBHUB_URB_TIMEOUT_CONTEXT; + +typedef struct _USBHUB_STATUS_CHANGE_CONTEXT { + ULONG Reserved; + BOOL RequestErrors; + PUSBHUB_FDO_EXTENSION HubExtension; +} USBHUB_STATUS_CHANGE_CONTEXT, *PUSBHUB_STATUS_CHANGE_CONTEXT; + +typedef struct _USBHUB_IDLE_HUB_CONTEXT { + ULONG Reserved; + NTSTATUS Status; +} USBHUB_IDLE_HUB_CONTEXT, *PUSBHUB_IDLE_HUB_CONTEXT; + +typedef struct _USBHUB_IDLE_PORT_CONTEXT { + ULONG Reserved; + LIST_ENTRY PwrList; + NTSTATUS Status; +} USBHUB_IDLE_PORT_CONTEXT, *PUSBHUB_IDLE_PORT_CONTEXT; + +typedef struct _USBHUB_IDLE_PORT_CANCEL_CONTEXT { + ULONG Reserved; + PIRP Irp; +} USBHUB_IDLE_PORT_CANCEL_CONTEXT, *PUSBHUB_IDLE_PORT_CANCEL_CONTEXT; + +typedef struct _USBHUB_RESET_PORT_CONTEXT { + ULONG Reserved; + PUSBHUB_PORT_PDO_EXTENSION PortExtension; + PIRP Irp; +} USBHUB_RESET_PORT_CONTEXT, *PUSBHUB_RESET_PORT_CONTEXT; + +/* debug.c */ + +VOID +NTAPI +USBPORT_DumpingDeviceDescriptor( + IN PUSB_DEVICE_DESCRIPTOR DeviceDescriptor); + +VOID +NTAPI +USBPORT_DumpingConfiguration( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor); + +VOID +NTAPI +USBPORT_DumpingIDs( + IN PVOID Id); + +/* ioctl.c */ + +NTSTATUS +NTAPI +USBH_DeviceControl( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp); + +NTSTATUS +NTAPI +USBH_PdoInternalControl( + IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp); + +/* pnp.c */ + +NTSTATUS +NTAPI +USBH_PdoRemoveDevice( + IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBH_FdoPnP( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN UCHAR Minor); + +NTSTATUS +NTAPI +USBH_PdoPnP( + IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp, + IN UCHAR Minor, + OUT BOOLEAN * IsCompleteIrp); + +/* power.c */ + +VOID +NTAPI +USBH_CompletePowerIrp( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN NTSTATUS NtStatus); + +NTSTATUS +NTAPI +USBH_HubSetD0( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBH_FdoPower( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp, + IN UCHAR Minor); + +NTSTATUS +NTAPI +USBH_PdoPower( + IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PIRP Irp, + IN UCHAR Minor); + +VOID +NTAPI +USBH_HubCompletePortWakeIrps( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN NTSTATUS NtStatus); + +VOID +NTAPI +USBH_HubCancelWakeIrp( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP Irp); + +VOID +NTAPI +USBH_IdleCancelPowerHubWorker( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PVOID Context); + +/* usbhub.c */ + +NTSTATUS +NTAPI +USBH_Wait( + IN ULONG Milliseconds); + +VOID +NTAPI +USBH_CompleteIrp( + IN PIRP Irp, + IN NTSTATUS CompleteStatus); + +NTSTATUS +NTAPI +USBH_PassIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +PUSBHUB_PORT_PDO_EXTENSION +NTAPI +PdoExt( + IN PDEVICE_OBJECT DeviceObject); + +NTSTATUS +NTAPI +USBH_WriteFailReasonID( + IN PDEVICE_OBJECT DeviceObject, + IN ULONG Data); + +NTSTATUS +NTAPI +USBH_SetPdoRegistryParameter( + IN PDEVICE_OBJECT DeviceObject, + IN PCWSTR SourceString, + IN PVOID Data, + IN ULONG DataSize, + IN ULONG Type, + IN ULONG DevInstKeyType); + +NTSTATUS +NTAPI +USBH_SyncSubmitUrb( + IN PDEVICE_OBJECT DeviceObject, + IN PURB Urb); + +NTSTATUS +NTAPI +USBH_FdoSyncSubmitUrb( + IN PDEVICE_OBJECT FdoDevice, + IN PURB Urb); + +NTSTATUS +NTAPI +USBH_SyncResetPort( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port); + +NTSTATUS +NTAPI +USBH_GetDeviceType( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE DeviceHandle, + OUT USB_DEVICE_TYPE * OutDeviceType); + +PUSBHUB_FDO_EXTENSION +NTAPI +USBH_GetRootHubExtension( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBH_SyncGetRootHubPdo( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PDEVICE_OBJECT * OutPdo1, + IN OUT PDEVICE_OBJECT * OutPdo2); + +NTSTATUS +NTAPI +USBH_SyncGetHubCount( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PULONG OutHubCount); + +PUSB_DEVICE_HANDLE +NTAPI +USBH_SyncGetDeviceHandle( + IN PDEVICE_OBJECT DeviceObject); + +NTSTATUS +NTAPI +USBH_GetDeviceDescriptor( + IN PDEVICE_OBJECT DeviceObject, + IN PUSB_DEVICE_DESCRIPTOR HubDeviceDescriptor); + +NTSTATUS +NTAPI +USBH_GetConfigurationDescriptor( + IN PDEVICE_OBJECT DeviceObject, + IN PUSB_CONFIGURATION_DESCRIPTOR * pConfigurationDescriptor); + +NTSTATUS +NTAPI +USBH_SyncGetHubDescriptor( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBH_SyncGetStringDescriptor( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR Index, + IN USHORT LanguageId, + IN PUSB_STRING_DESCRIPTOR Descriptor, + IN ULONG NumberOfBytes, + IN PULONG OutLength, + IN BOOLEAN IsValidateLength); + +NTSTATUS +NTAPI +USBH_SyncGetPortStatus( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN PUSBHUB_PORT_STATUS PortStatus, + IN ULONG Length); + +NTSTATUS +NTAPI +USBH_SyncClearPortStatus( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN USHORT RequestValue); + +NTSTATUS +NTAPI +USBH_SyncPowerOnPorts( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBH_SyncDisablePort( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port); + +BOOLEAN +NTAPI +USBH_HubIsBusPowered( + IN PDEVICE_OBJECT DeviceObject, + IN PUSB_CONFIGURATION_DESCRIPTOR HubConfigDescriptor); + +NTSTATUS +NTAPI +USBH_SubmitStatusChangeTransfer( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBD_CreateDeviceEx( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE * OutDeviceHandle, + IN USB_PORT_STATUS UsbPortStatus, + IN USHORT Port); + +NTSTATUS +NTAPI +USBD_RemoveDeviceEx( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE DeviceHandle, + IN ULONG Flags); + +NTSTATUS +NTAPI +USBD_InitializeDeviceEx( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_DEVICE_HANDLE DeviceHandle, + IN PUCHAR DeviceDescriptorBuffer, + IN ULONG DeviceDescriptorBufferLength, + IN PUCHAR ConfigDescriptorBuffer, + IN ULONG ConfigDescriptorBufferLength); + +VOID +NTAPI +USBHUB_SetDeviceHandleData( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PDEVICE_OBJECT UsbDevicePdo, + IN PVOID DeviceHandle); + +VOID +NTAPI +USBHUB_FlushAllTransfers( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBD_GetDeviceInformationEx( + IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSB_NODE_CONNECTION_INFORMATION_EX Info, + IN ULONG Length, + IN PUSB_DEVICE_HANDLE DeviceHandle); + +NTSTATUS +NTAPI +USBD_RestoreDeviceEx( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN OUT PUSB_DEVICE_HANDLE OldDeviceHandle, + IN OUT PUSB_DEVICE_HANDLE NewDeviceHandle); + +NTSTATUS +NTAPI +USBH_AllocateWorkItem( + IN PUSBHUB_FDO_EXTENSION HubExtension, + OUT PUSBHUB_IO_WORK_ITEM * OutHubIoWorkItem, + IN PVOID WorkerRoutine, + IN SIZE_T BufferLength, + OUT PVOID * OutHubWorkItemBuffer, + IN WORK_QUEUE_TYPE Type); + +VOID +NTAPI +USBH_QueueWorkItem( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem); + +VOID +NTAPI +USBH_FreeWorkItem( + IN PUSBHUB_IO_WORK_ITEM HubIoWorkItem); + +NTSTATUS +NTAPI +USBD_RegisterRootHubCallBack( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBD_UnRegisterRootHubCallBack( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +VOID +NTAPI +USBH_HubCancelIdleIrp( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN PIRP IdleIrp); + +BOOLEAN +NTAPI +USBH_CheckIdleAbort( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN BOOLEAN IsWait, + IN BOOLEAN IsExtCheck); + +VOID +NTAPI +USBH_CheckHubIdle( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +VOID +NTAPI +USBH_CheckIdleDeferred( + IN PUSBHUB_FDO_EXTENSION HubExtension); + +NTSTATUS +NTAPI +USBH_CheckDeviceLanguage( + IN PDEVICE_OBJECT DeviceObject, + IN USHORT LanguageId); + +NTSTATUS +NTAPI +USBH_CreateDevice( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN USB_PORT_STATUS UsbPortStatus, + IN ULONG IsWait); + +NTSTATUS +NTAPI +USBH_ResetDevice( + IN PUSBHUB_FDO_EXTENSION HubExtension, + IN USHORT Port, + IN BOOLEAN IsKeepDeviceData, + IN BOOLEAN IsWait); + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath); + +#endif /* _USBHUB_H_ */ diff --git a/reactos/drivers/usb/usbhub_new/usbhub.rc b/reactos/drivers/usb/usbhub_new/usbhub.rc new file mode 100644 index 00000000000..e5d995562ce --- /dev/null +++ b/reactos/drivers/usb/usbhub_new/usbhub.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Hub Driver for USB" +#define REACTOS_STR_INTERNAL_NAME "usbhub" +#define REACTOS_STR_ORIGINAL_FILENAME "usbhub.sys" +#include diff --git a/reactos/drivers/usb/usbmport.h b/reactos/drivers/usb/usbmport.h new file mode 100644 index 00000000000..35b7ac1dea1 --- /dev/null +++ b/reactos/drivers/usb/usbmport.h @@ -0,0 +1,682 @@ +#ifndef USBMPORT_H__ +#define USBMPORT_H__ + +/* 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_CLOSED 4 +#define USBPORT_ENDPOINT_NOT_HANDLED 5 + +typedef struct _USBPORT_RESOURCES { + ULONG TypesResources; // 1 | 2 | 4 (Port | Interrupt | Memory) + 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; + UCHAR Reserved1; + 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 RH_STATUS_SUCCESS 0 + +/* Miniport */ + +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 */ + +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, + PULONG); + +typedef MPSTATUS +(NTAPI *PHCI_RH_GET_HUB_STATUS)( + PVOID, + PULONG); + +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 */ + +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 */ + +typedef ULONG +(NTAPI *PUSBPORT_DBG_PRINT)( + PVOID, + ULONG, + PCH, + ULONG, + ULONG, + ULONG, + ULONG, + ULONG, + ULONG); + +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, + ULONG, + 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, + PVOID, + PVOID, + ULONG, + ULONG, + ULONG); + +typedef PVOID +(NTAPI *PUSBPORT_GET_MAPPED_VIRTUAL_ADDRESS)( + PVOID, + PVOID, + PVOID); + +typedef ULONG +(NTAPI *PUSBPORT_REQUEST_ASYNC_CALLBACK)( + PVOID, + ULONG, + PVOID, + SIZE_T, + ULONG); + +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 */ + +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_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 BufferVA; + ULONG 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); + +/* Hub port status and port status change bits. + See USB 2.0 spec Table 11-19 and Table 11-20. +*/ + +typedef union _USB_PORT_STATUS { + struct { + USHORT ConnectStatus : 1; // Current Connect Status + USHORT EnableStatus : 1; // Port Enabled/Disabled + USHORT SuspendStatus : 1; + USHORT OverCurrent : 1; + USHORT ResetStatus : 1; + USHORT Reserved1 : 3; + USHORT PowerStatus : 1; + USHORT LsDeviceAttached : 1; // Low-Speed Device Attached + USHORT HsDeviceAttached : 1; // High-speed Device Attached + USHORT TestMode : 1; // Port Test Mode + USHORT IndicatorControl : 1; // Port Indicator Control + USHORT Reserved2 : 3; + }; + USHORT AsUSHORT; +} USB_PORT_STATUS; + +typedef union _USB_PORT_STATUS_CHANGE { + struct { + USHORT ConnectStatusChange : 1; + USHORT EnableStatusChange : 1; + USHORT SuspendStatusChange : 1; + USHORT OverCurrentChange : 1; + USHORT ResetStatusChange : 1; + USHORT Reserved3 : 3; + USHORT PowerStatusChange : 1; + USHORT LsDeviceAttachedChange : 1; + USHORT HsDeviceAttachedChange : 1; + USHORT TestModeChange : 1; + USHORT IndicatorControlChange : 1; + USHORT Reserved4 : 3; + }; + USHORT AsUSHORT; +} 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_LOCAL_POWER 0x00000001 +#define HUB_STATUS_OVERCURRENT 0x00000002 +#define HUB_STATUS_CHANGE_LOCAL_POWER 0x00010000 +#define HUB_STATUS_CHANGE_OVERCURRENT 0x00020000 + +/* Additional USB Class Codes from USB.org */ + +#define USBC_DEVICE_CLASS_CDC_DATA 0x0A +#define USBC_DEVICE_CLASS_SMART_CARD 0x0B +#define USBC_DEVICE_CLASS_CONTENT_SECURITY 0x0D +#define USBC_DEVICE_CLASS_VIDEO 0x0E +#define USBC_DEVICE_CLASS_PERSONAL_HEALTHCARE 0x0F +#define USBC_DEVICE_CLASS_AUDIO_VIDEO 0x10 +#define USBC_DEVICE_CLASS_BILLBOARD 0x11 +#define USBC_DEVICE_CLASS_TYPE_C_BRIDGE 0x12 +#define USBC_DEVICE_CLASS_WIRELESS_Diagnostic 0xDC +#define USBC_DEVICE_CLASS_WIRELESS_CONTROLLER 0xE0 +#define USBC_DEVICE_CLASS_MISCELLANEOUS 0xEF +#define USBC_DEVICE_CLASS_APPLICATION_SPECIFIC 0xFE + +#endif /* USBMPORT_H__ */ diff --git a/reactos/drivers/usb/usbohci_new/CMakeLists.txt b/reactos/drivers/usb/usbohci_new/CMakeLists.txt new file mode 100644 index 00000000000..dc1e8faf1a5 --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/CMakeLists.txt @@ -0,0 +1,15 @@ + +list(APPEND SOURCE + roothub.c + usbohci.c + usbohci.h) + +add_library(usbohci SHARED + ${SOURCE} + guid.c + usbohci.rc) + +set_module_type(usbohci kernelmodedriver) +add_importlibs(usbohci usbport ntoskrnl hal usbd) +add_pch(usbohci usbohci.h SOURCE) +add_cd_file(TARGET usbohci DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/usb/usbohci_new/dbg_ohci.h b/reactos/drivers/usb/usbohci_new/dbg_ohci.h new file mode 100644 index 00000000000..273fe56e3f3 --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/dbg_ohci.h @@ -0,0 +1,29 @@ +#ifndef DBG_OHCI_H__ +#define DBG_OHCI_H__ + +#if DBG + + #ifndef NDEBUG_OHCI_TRACE + #define DPRINT_OHCI(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_OHCI __noop + #else + #define DPRINT_OHCI(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #endif + #endif + +#else /* not DBG */ + + #if defined(_MSC_VER) + #define DPRINT_OHCI __noop + #else + #define DPRINT_OHCI(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #endif /* _MSC_VER */ + +#endif /* not DBG */ + +#endif /* DBG_OHCI_H__ */ diff --git a/reactos/drivers/usb/usbohci_new/guid.c b/reactos/drivers/usb/usbohci_new/guid.c new file mode 100644 index 00000000000..50a60369ff3 --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/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/usbohci_new/hardware.h b/reactos/drivers/usb/usbohci_new/hardware.h new file mode 100644 index 00000000000..e86f7e4c206 --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/hardware.h @@ -0,0 +1,294 @@ +#define OHCI_NUMBER_OF_INTERRUPTS 32 +#define OHCI_MAX_PORT_COUNT 15 +#define ED_EOF -1 +#define MAXIMUM_OVERHEAD 210 + +/* Controller states */ +#define OHCI_HC_STATE_RESET 0 +#define OHCI_HC_STATE_RESUME 1 +#define OHCI_HC_STATE_OPERATIONAL 2 +#define OHCI_HC_STATE_SUSPEND 3 + +/* Endpoint Descriptor Control */ +#define OHCI_ED_DATA_FLOW_DIRECTION_FROM_TD 0 +#define OHCI_ED_DATA_FLOW_DIRECTION_OUT 1 +#define OHCI_ED_DATA_FLOW_DIRECTION_IN 2 + +#define OHCI_ENDPOINT_FULL_SPEED 0 +#define OHCI_ENDPOINT_LOW_SPEED 1 + +#define OHCI_ENDPOINT_GENERAL_FORMAT 0 +#define OHCI_ENDPOINT_ISOCHRONOUS_FORMAT 1 + +/* Transfer Descriptor Control */ +#define OHCI_TD_INTERRUPT_IMMEDIATE 0 +#define OHCI_TD_INTERRUPT_NONE 7 + +#define OHCI_TD_DIRECTION_PID_SETUP 0 +#define OHCI_TD_DIRECTION_PID_OUT 1 +#define OHCI_TD_DIRECTION_PID_IN 2 +#define OHCI_TD_DIRECTION_PID_RESERVED 3 + +#define OHCI_TD_CONDITION_NO_ERROR 0x00 +#define OHCI_TD_CONDITION_CRC_ERROR 0x01 +#define OHCI_TD_CONDITION_BIT_STUFFING 0x02 +#define OHCI_TD_CONDITION_TOGGLE_MISMATCH 0x03 +#define OHCI_TD_CONDITION_STALL 0x04 +#define OHCI_TD_CONDITION_NO_RESPONSE 0x05 +#define OHCI_TD_CONDITION_PID_CHECK_FAILURE 0x06 +#define OHCI_TD_CONDITION_UNEXPECTED_PID 0x07 +#define OHCI_TD_CONDITION_DATA_OVERRUN 0x08 +#define OHCI_TD_CONDITION_DATA_UNDERRUN 0x09 +#define OHCI_TD_CONDITION_BUFFER_OVERRUN 0x0C +#define OHCI_TD_CONDITION_BUFFER_UNDERRUN 0x0D +#define OHCI_TD_CONDITION_NOT_ACCESSED 0x0E + +typedef union _OHCI_TRANSFER_CONTROL { + struct { + ULONG Reserved : 18; + ULONG BufferRounding : 1; + ULONG DirectionPID : 2; + ULONG DelayInterrupt : 3; + ULONG DataToggle : 2; + ULONG ErrorCount : 2; + ULONG ConditionCode : 4; + }; + ULONG AsULONG; +} OHCI_TRANSFER_CONTROL, *POHCI_TRANSFER_CONTROL; + +typedef struct _OHCI_TRANSFER_DESCRIPTOR { // must be aligned to a 16-byte boundary + OHCI_TRANSFER_CONTROL Control; + PVOID CurrentBuffer; // physical address of the next memory location + PULONG NextTD; // pointer to the next TD on the list of TDs + PVOID BufferEnd; // physical address of the last byte +} OHCI_TRANSFER_DESCRIPTOR, *POHCI_TRANSFER_DESCRIPTOR; + +C_ASSERT(sizeof(OHCI_TRANSFER_DESCRIPTOR) == 16); + +typedef union _OHCI_ISO_TRANSFER_CONTROL { + struct { + ULONG StartingFrame : 16; + ULONG Reserved1 : 5; + ULONG DelayInterrupt : 3; + ULONG FrameCount : 3; + ULONG Reserved2 : 1; + ULONG ConditionCode : 4; + }; + ULONG AsULONG; +} OHCI_ISO_TRANSFER_CONTROL, *POHCI_ISO_TRANSFER_CONTROL; + +typedef struct _OHCI_ISO_TRANSFER_DESCRIPTOR { // must be aligned to a 32-byte boundary + OHCI_ISO_TRANSFER_CONTROL Control; + PVOID BufferPage0; // physical page number of the 1 byte of the data buffer + PULONG NextTD; // pointer to the next Isochronous TD on the queue of Isochronous TDs + PVOID BufferEnd; // physical address of the last byte in the buffer + USHORT Offset[8]; // for determine size and start addr. iso packet | PacketStatusWord - completion code +} OHCI_ISO_TRANSFER_DESCRIPTOR, *POHCI_ISO_TRANSFER_DESCRIPTOR; + +C_ASSERT(sizeof(OHCI_ISO_TRANSFER_DESCRIPTOR) == 32); + +typedef union _OHCI_ENDPOINT_CONTROL { + struct { + ULONG FunctionAddress : 7; + ULONG EndpointNumber : 4; + ULONG Direction : 2; + ULONG Speed : 1; + ULONG sKip : 1; + ULONG Format : 1; + ULONG MaximumPacketSize : 11; + ULONG Reserved : 5; + }; + ULONG AsULONG; +} OHCI_ENDPOINT_CONTROL, *POHCI_ENDPOINT_CONTROL; + +typedef struct _OHCI_ENDPOINT_DESCRIPTOR { // must be aligned to a 16-byte boundary + OHCI_ENDPOINT_CONTROL EndpointControl; + ULONG_PTR TailPointer; // if TailP and HeadP are different, then the list contains a TD to be processed + ULONG_PTR HeadPointer; // physical pointer to the next TD to be processed for this endpoint + ULONG_PTR NextED; // entry points to the next ED on the list +} OHCI_ENDPOINT_DESCRIPTOR, *POHCI_ENDPOINT_DESCRIPTOR; + +C_ASSERT(sizeof(OHCI_ENDPOINT_DESCRIPTOR) == 16); + +typedef struct _OHCI_HCCA { // must be located on a 256-byte boundary + POHCI_ENDPOINT_DESCRIPTOR InterrruptTable[OHCI_NUMBER_OF_INTERRUPTS]; + USHORT FrameNumber; + USHORT Pad1; + ULONG DoneHead; + UCHAR reserved_hc[116]; + UCHAR Pad[4]; +} OHCI_HCCA, *POHCI_HCCA; + +C_ASSERT(sizeof(OHCI_HCCA) == 256); + +typedef union _OHCI_REG_CONTROL { + struct { + ULONG ControlBulkServiceRatio : 2; + ULONG PeriodicListEnable : 1; + ULONG IsochronousEnable : 1; + ULONG ControlListEnable : 1; + ULONG BulkListEnable : 1; + ULONG HostControllerFunctionalState : 2; + ULONG InterruptRouting : 1; + ULONG RemoteWakeupConnected : 1; + ULONG RemoteWakeupEnable : 1; + ULONG Reserved : 21; + }; + ULONG AsULONG; +} OHCI_REG_CONTROL, *POHCI_REG_CONTROL; + +typedef union _OHCI_REG_COMMAND_STATUS { + struct { + ULONG HostControllerReset : 1; + ULONG ControlListFilled : 1; + ULONG BulkListFilled : 1; + ULONG OwnershipChangeRequest : 1; + ULONG Reserved1 : 12; + ULONG SchedulingOverrunCount : 1; + ULONG Reserved2 : 15; + }; + ULONG AsULONG; +} OHCI_REG_COMMAND_STATUS, *POHCI_REG_COMMAND_STATUS; + +typedef union _OHCI_REG_INTERRUPT_STATUS { + struct { + ULONG SchedulingOverrun : 1; + ULONG WritebackDoneHead : 1; + ULONG StartofFrame : 1; + ULONG ResumeDetected : 1; + ULONG UnrecoverableError : 1; + ULONG FrameNumberOverflow : 1; + ULONG RootHubStatusChange : 1; + ULONG Reserved1 : 23; + ULONG OwnershipChange : 1; + ULONG Reserved2 : 1; //NULL + }; + ULONG AsULONG; +} OHCI_REG_INTERRUPT_STATUS, *POHCI_REG_INTERRUPT_STATUS; + +typedef union _OHCI_REG_INTERRUPT_ENABLE_DISABLE { + struct { + ULONG SchedulingOverrun : 1; + ULONG WritebackDoneHead : 1; + ULONG StartofFrame : 1; + ULONG ResumeDetected : 1; + ULONG UnrecoverableError : 1; + ULONG FrameNumberOverflow : 1; + ULONG RootHubStatusChange : 1; + ULONG Reserved1 : 23; + ULONG OwnershipChange : 1; + ULONG MasterInterruptEnable : 1; + }; + ULONG AsULONG; +} OHCI_REG_INTERRUPT_ENABLE_DISABLE, *POHCI_REG_INTERRUPT_ENABLE_DISABLE; + +typedef union _OHCI_REG_FRAME_INTERVAL { + struct { + ULONG FrameInterval : 14; + ULONG Reserved : 2; + ULONG FSLargestDataPacket : 15; + ULONG FrameIntervalToggle : 1; + }; + ULONG AsULONG; +} OHCI_REG_FRAME_INTERVAL, *POHCI_REG_FRAME_INTERVAL; + +typedef union _OHCI_REG_RH_DESCRIPTORA { + struct { + ULONG NumberDownstreamPorts : 8; + ULONG PowerSwitchingMode : 1; + ULONG NoPowerSwitching : 1; + ULONG DeviceType : 1; + ULONG OverCurrentProtectionMode : 1; + ULONG NoOverCurrentProtection : 1; + ULONG Reserved : 11; + ULONG PowerOnToPowerGoodTime : 8; + }; + ULONG AsULONG; +} OHCI_REG_RH_DESCRIPTORA, *POHCI_REG_RH_DESCRIPTORA; + +typedef union _OHCI_REG_RH_STATUS { + union { + struct { // read + ULONG LocalPowerStatus : 1; + ULONG OverCurrentIndicator : 1; + ULONG Reserved10 : 13; + ULONG DeviceRemoteWakeupEnable : 1; + ULONG LocalPowerStatusChange : 1; + ULONG OverCurrentIndicatorChangeR : 1; + ULONG Reserved20 : 14; + }; + struct { // write + ULONG ClearGlobalPower : 1; + ULONG Reserved11 : 14; + ULONG SetRemoteWakeupEnable : 1; + ULONG SetGlobalPower : 1; + ULONG OverCurrentIndicatorChangeW : 1; + ULONG Reserved22 : 13; + ULONG ClearRemoteWakeupEnable : 1; + }; + }; + ULONG AsULONG; +} OHCI_REG_RH_STATUS, *POHCI_REG_RH_STATUS; + +typedef union _OHCI_REG_RH_PORT_STATUS { + struct { + union { // 0 byte + // read + UCHAR CurrentConnectStatus : 1; + UCHAR PortEnableStatus : 1; + UCHAR PortSuspendStatus : 1; + UCHAR PortOverCurrentIndicator : 1; + UCHAR PortResetStatus : 1; + UCHAR Reserved1r : 3; + // write + UCHAR ClearPortEnable : 1; + UCHAR SetPortEnable : 1; + UCHAR SetPortSuspend : 1; + UCHAR ClearSuspendStatus : 1; + UCHAR SetPortReset : 1; + UCHAR Reserved1w : 3; + }; + union { // 1 byte + // read + UCHAR PortPowerStatus : 1; + UCHAR LowSpeedDeviceAttached : 1; + UCHAR Reserved2r : 6; + // write + UCHAR SetPortPower : 1; + UCHAR ClearPortPower : 1; + UCHAR Reserved2w : 6; + }; + USHORT ConnectStatusChange : 1; + USHORT PortEnableStatusChange : 1; + USHORT PortSuspendStatusChange : 1; + USHORT PortOverCurrentIndicatorChange : 1; + USHORT PortResetStatusChange : 1; + USHORT Reserved3 : 11; + }; + ULONG AsULONG; +} OHCI_REG_RH_PORT_STATUS, *POHCI_REG_RH_PORT_STATUS; + +typedef struct _OHCI_OPERATIONAL_REGISTERS { + ULONG HcRevision; + OHCI_REG_CONTROL HcControl; // +4 + OHCI_REG_COMMAND_STATUS HcCommandStatus; // +8 + OHCI_REG_INTERRUPT_STATUS HcInterruptStatus; // +12 0x0C + OHCI_REG_INTERRUPT_ENABLE_DISABLE HcInterruptEnable; // +16 0x10 + OHCI_REG_INTERRUPT_ENABLE_DISABLE HcInterruptDisable; // +20 0x14 + ULONG HcHCCA; // +24 0x18 + ULONG HcPeriodCurrentED; // +28 0x1C + ULONG HcControlHeadED; // +32 0x20 + ULONG HcControlCurrentED; // +36 0x24 + ULONG HcBulkHeadED; // +40 0x28 + ULONG HcBulkCurrentED; // +44 0x2C + ULONG HcDoneHead; // +48 0x30 + OHCI_REG_FRAME_INTERVAL HcFmInterval; // +52 0x34 + ULONG HcFmRemaining; // +56 0x38 + ULONG HcFmNumber; // +60 0x3C + ULONG HcPeriodicStart; // +64 0x40 + ULONG HcLSThreshold; // +68 0x44 + OHCI_REG_RH_DESCRIPTORA HcRhDescriptorA; // +72 0x48 + ULONG HcRhDescriptorB; // +76 0x4C + OHCI_REG_RH_STATUS HcRhStatus; // +80 0x50 + OHCI_REG_RH_PORT_STATUS HcRhPortStatus[OHCI_MAX_PORT_COUNT]; // +84 0x54 ... 144 0x90 +} OHCI_OPERATIONAL_REGISTERS, *POHCI_OPERATIONAL_REGISTERS; diff --git a/reactos/drivers/usb/usbohci_new/roothub.c b/reactos/drivers/usb/usbohci_new/roothub.c new file mode 100644 index 00000000000..f9148db7445 --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/roothub.c @@ -0,0 +1,471 @@ +#include "usbohci.h" + +#define NDEBUG +#include + +ULONG +NTAPI +OHCI_ReadRhDescriptorA(IN POHCI_EXTENSION OhciExtension) +{ + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + ULONG DescriptorA; + ULONG ix = 0; + + OperationalRegs = OhciExtension->OperationalRegs; + + DPRINT("OHCI_ReadRhDescriptorA: OhciExtension - %p\n", OhciExtension); + + do + { + DescriptorA = READ_REGISTER_ULONG(&OperationalRegs->HcRhDescriptorA.AsULONG); + + if (DescriptorA && !(DescriptorA & 0xFFE0F0)) // Reserved bits + break; + + DPRINT1("OHCI_ReadRhDescriptorA: ix - %p\n", ix); + + KeStallExecutionProcessor(5); + + ++ix; + } + while (ix < 10); + + return DescriptorA; +} + +VOID +NTAPI +OHCI_RH_GetRootHubData(IN PVOID ohciExtension, + IN PVOID rootHubData) +{ + POHCI_EXTENSION OhciExtension; + PUSBPORT_ROOT_HUB_DATA RootHubData; + OHCI_REG_RH_DESCRIPTORA DescriptorA; + UCHAR PowerOnToPowerGoodTime; + USHORT HubCharacteristics; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_GetRootHubData: OhciExtension - %p, rootHubData - %p\n", + OhciExtension, + rootHubData); + + RootHubData = (PUSBPORT_ROOT_HUB_DATA)rootHubData; + DescriptorA.AsULONG = OHCI_ReadRhDescriptorA(OhciExtension); + + RootHubData->NumberOfPorts = DescriptorA.NumberDownstreamPorts; + + PowerOnToPowerGoodTime = DescriptorA.PowerOnToPowerGoodTime; + if (PowerOnToPowerGoodTime <= 25) + { + PowerOnToPowerGoodTime = 25; + } + RootHubData->PowerOnToPowerGood = PowerOnToPowerGoodTime; + + HubCharacteristics = (DescriptorA.AsULONG >> 8) & 0xFFFC; + RootHubData->HubCharacteristics = HubCharacteristics; + + if (DescriptorA.PowerSwitchingMode) + { + RootHubData->HubCharacteristics = (HubCharacteristics & 0xFFFD) | 1; + } + + RootHubData->HubControlCurrent = 0; +} + +MPSTATUS +NTAPI +OHCI_RH_GetStatus(IN PVOID ohciExtension, + IN PUSHORT Status) +{ + DPRINT("OHCI_RH_GetStatus: \n"); + *Status = 1; + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_GetPortStatus(IN PVOID ohciExtension, + IN USHORT Port, + IN PULONG PortStatus) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + ULONG portStatus; + ULONG ix = 0; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_GetPortStatus: OhciExtension - %p, Port - %x, PortStatus - %p\n", + OhciExtension, + Port, + *PortStatus); + + OperationalRegs = ((POHCI_EXTENSION)OhciExtension)->OperationalRegs; + + do + { + portStatus = READ_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG); + + //DPRINT("OHCI_RH_GetPortStatus: &portreg - %p\n", + // &OperationalRegs->HcRhPortStatus[Port-1].AsULONG); + + if ( portStatus && !(portStatus & 0xFFE0FCE0) ) + break; + + KeStallExecutionProcessor(5); + + ++ix; + } + while ( ix < 10 ); + + *PortStatus = portStatus; + + DPRINT("OHCI_RH_GetPortStatus: OhciExtension - %p, Port - %x, PortStatus - %p\n", + OhciExtension, + Port, + *PortStatus); + + if (0)//Port == 1) + { + DPRINT("HcRevision - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcRevision)); + DPRINT("HcControl - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG)); + DPRINT("HcCommandStatus - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcCommandStatus.AsULONG)); + DPRINT("HcInterruptStatus - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcInterruptStatus.AsULONG)); + DPRINT("HcInterruptEnable - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG)); + DPRINT("HcInterruptDisable - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcInterruptDisable.AsULONG)); + DPRINT("HcHCCA - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcHCCA)); + DPRINT("HcPeriodCurrentED - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcPeriodCurrentED)); + DPRINT("HcControlHeadED - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcControlHeadED)); + DPRINT("HcControlCurrentED - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcControlCurrentED)); + DPRINT("HcBulkHeadED - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcBulkHeadED)); + DPRINT("HcBulkCurrentED - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcBulkCurrentED)); + DPRINT("HcDoneHead - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcDoneHead)); + DPRINT("HcFmInterval - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcFmInterval.AsULONG)); + DPRINT("HcFmRemaining - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcFmRemaining)); + DPRINT("HcFmNumber - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcFmNumber)); + DPRINT("HcPeriodicStart - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart)); + DPRINT("HcLSThreshold - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcLSThreshold)); + DPRINT("HcRhDescriptorA - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcRhDescriptorA.AsULONG)); + DPRINT("HcRhDescriptorB - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcRhDescriptorB)); + DPRINT("HcRhStatus - %p\n", READ_REGISTER_ULONG(&OperationalRegs->HcRhStatus.AsULONG)); + } + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_GetHubStatus(IN PVOID ohciExtension, + IN PULONG HubStatus) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_GetHubStatus: ohciExtension - %p, HubStatus - %x\n", + ohciExtension, + HubStatus); + + OperationalRegs = OhciExtension->OperationalRegs; + + *HubStatus &= ~0x10001; + *HubStatus ^= (READ_REGISTER_ULONG(&OperationalRegs->HcRhStatus.AsULONG) ^ + *HubStatus) & 0x20002; + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortReset(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_SetFeaturePortReset: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x10); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortPower(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_SetFeaturePortPower: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x100); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortEnable(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_SetFeaturePortEnable: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 2); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortSuspend(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_SetFeaturePortSuspend: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 4); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortEnable(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortEnable: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 1); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortPower(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortPower: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x200); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortSuspend(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortSuspend: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 8); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortEnableChange(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortEnableChange: ohciExtension - %p, Port - %x\n", + ohciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x20000); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortConnectChange(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortConnectChange: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x10000); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortResetChange(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortResetChange: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x100000); + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortSuspendChange(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortSuspendChange: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x40000); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortOvercurrentChange(IN PVOID ohciExtension, + IN USHORT Port) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT("OHCI_RH_ClearFeaturePortOvercurrentChange: OhciExtension - %p, Port - %x\n", + OhciExtension, + Port); + + OperationalRegs = OhciExtension->OperationalRegs; + + if (Port) + { + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhPortStatus[Port-1].AsULONG, + 0x80000); + } + else + { + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhStatus.AsULONG, + 0x20000); + } + + return 0; +} + +VOID +NTAPI +OHCI_RH_DisableIrq(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension = (POHCI_EXTENSION)ohciExtension; + DPRINT("OHCI_RH_DisableIrq: OhciExtension - %p\n", OhciExtension); + + WRITE_REGISTER_ULONG(&OhciExtension->OperationalRegs->HcInterruptDisable.AsULONG, + 0x40); +} + +VOID +NTAPI +OHCI_RH_EnableIrq(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension = (POHCI_EXTENSION)ohciExtension; + DPRINT("OHCI_RH_EnableIrq: OhciExtension - %p\n", OhciExtension); + + WRITE_REGISTER_ULONG(&OhciExtension->OperationalRegs->HcInterruptEnable.AsULONG, + 0x40); +} diff --git a/reactos/drivers/usb/usbohci_new/usbohci.c b/reactos/drivers/usb/usbohci_new/usbohci.c new file mode 100644 index 00000000000..b337f5044b3 --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/usbohci.c @@ -0,0 +1,2456 @@ +#include "usbohci.h" + +//#define NDEBUG +#include + +#define NDEBUG_OHCI_TRACE +#include "dbg_ohci.h" + +USBPORT_REGISTRATION_PACKET RegPacket; + +VOID +NTAPI +OHCI_EnableList(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + ULONG TransferType; + OHCI_REG_COMMAND_STATUS CommandStatus; + + DPRINT_OHCI("OHCI_EnableList: ... \n"); + + OperationalRegs = OhciExtension->OperationalRegs; + + CommandStatus.AsULONG = 0; + + if (READ_REGISTER_ULONG((PULONG)&OperationalRegs->HcControlHeadED)) + { + CommandStatus.ControlListFilled = 1; + } + + if (READ_REGISTER_ULONG((PULONG)&OperationalRegs->HcBulkHeadED)) + { + CommandStatus.BulkListFilled = 1; + } + + TransferType = OhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_BULK) + { + CommandStatus.BulkListFilled = 1; + } + else if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + CommandStatus.ControlListFilled = 1; + } + + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommandStatus.AsULONG, + CommandStatus.AsULONG); +} + +VOID +NTAPI +OHCI_InsertEndpointInSchedule(IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_STATIC_ED HeadED; + POHCI_HCD_ED ED; + POHCI_HCD_ED PrevED; + PLIST_ENTRY HeadLink; + + DPRINT_OHCI("OHCI_InsertEndpointInSchedule: OhciEndpoint - %p\n", + OhciEndpoint); + + ED = OhciEndpoint->HcdED; + + HeadED = OhciEndpoint->HeadED; + HeadLink = &HeadED->Link; + + if (IsListEmpty(HeadLink)) + { + InsertHeadList(HeadLink, &ED->HcdEDLink); + + if (HeadED->Type & 0x20) // ControlTransfer or BulkTransfer + { + ED->HwED.NextED = READ_REGISTER_ULONG(HeadED->pNextED); + WRITE_REGISTER_ULONG(HeadED->pNextED, ED->PhysicalAddress); + } + else + { + ED->HwED.NextED = *HeadED->pNextED; + *HeadED->pNextED = ED->PhysicalAddress; + } + } + else + { + PrevED = CONTAINING_RECORD(HeadLink->Blink, + OHCI_HCD_ED, + HcdEDLink); + + InsertTailList(HeadLink, &ED->HcdEDLink); + + ED->HwED.NextED = 0; + PrevED->HwED.NextED = ED->PhysicalAddress; + } +} + +POHCI_HCD_ED +NTAPI +OHCI_InitializeED(IN POHCI_ENDPOINT OhciEndpoint, + IN POHCI_HCD_ED ED, + IN POHCI_HCD_TD FirstTD, + IN ULONG_PTR EdPA) +{ + OHCI_ENDPOINT_CONTROL EndpointControl; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + + DPRINT_OHCI("OHCI_InitializeED: OhciEndpoint - %p, ED - %p, FirstTD - %p, EdPA - %p\n", + OhciEndpoint, + ED, + FirstTD, + EdPA); + + RtlZeroMemory(ED, sizeof(OHCI_HCD_ED)); + + ED->PhysicalAddress = EdPA; + + EndpointProperties = &OhciEndpoint->EndpointProperties; + + ED->HwED.EndpointControl.FunctionAddress = EndpointProperties->DeviceAddress; + ED->HwED.EndpointControl.EndpointNumber = EndpointProperties->EndpointAddress; + + EndpointControl = ED->HwED.EndpointControl; + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + EndpointControl.Direction = OHCI_ED_DATA_FLOW_DIRECTION_FROM_TD; + } + else if (EndpointProperties->Direction) + { + EndpointControl.Direction = OHCI_ED_DATA_FLOW_DIRECTION_OUT; + } + else + { + EndpointControl.Direction = OHCI_ED_DATA_FLOW_DIRECTION_IN; + } + + ED->HwED.EndpointControl = EndpointControl; + + if (EndpointProperties->DeviceSpeed == UsbLowSpeed) + { + ED->HwED.EndpointControl.Speed = OHCI_ENDPOINT_LOW_SPEED; + } + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + ED->HwED.EndpointControl.Format = OHCI_ENDPOINT_ISOCHRONOUS_FORMAT; + } + else + { + ED->HwED.EndpointControl.sKip = 1; + } + + ED->HwED.EndpointControl.MaximumPacketSize = EndpointProperties->TotalMaxPacketSize; + + ED->HwED.TailPointer = (ULONG_PTR)FirstTD->PhysicalAddress; + ED->HwED.HeadPointer = (ULONG_PTR)FirstTD->PhysicalAddress; + + FirstTD->Flags |= OHCI_HCD_TD_FLAG_ALLOCATED; + + OhciEndpoint->HcdTailP = FirstTD; + OhciEndpoint->HcdHeadP = FirstTD; + + return ED; +} + +MPSTATUS +NTAPI +OHCI_OpenControlEndpoint(IN POHCI_EXTENSION OhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_HCD_TD TdVA; + POHCI_HCD_TD TdPA; + POHCI_HCD_ED ED; + ULONG TdCount; + + DPRINT_OHCI("OHCI_OpenControlEndpoint: ... \n"); + + ED = (POHCI_HCD_ED)EndpointProperties->BufferVA; + + OhciEndpoint->FirstTD = (POHCI_HCD_TD)((ULONG_PTR)ED + sizeof(OHCI_HCD_ED)); + OhciEndpoint->HeadED = &OhciExtension->ControlStaticED; + + TdCount = (EndpointProperties->BufferLength - sizeof(OHCI_HCD_ED)) / + sizeof(OHCI_HCD_TD); + + OhciEndpoint->MaxTransferDescriptors = TdCount; + + if (TdCount > 0) + { + TdVA = OhciEndpoint->FirstTD; + TdPA = (POHCI_HCD_TD) + ((ULONG_PTR)EndpointProperties->BufferPA + + sizeof(OHCI_HCD_ED)); + + do + { + DPRINT_OHCI("OHCI_OpenControlEndpoint: InitTD. TdVA - %p, TdPA - %p\n", + TdVA, + TdPA); + + RtlZeroMemory(TdVA, sizeof(OHCI_HCD_TD)); + + TdVA->PhysicalAddress = (ULONG_PTR)TdPA; + TdVA->Flags = 0; + TdVA->OhciTransfer = NULL; + + ++TdVA; + ++TdPA; + --TdCount; + } + while (TdCount > 0); + } + + OhciEndpoint->HcdED = OHCI_InitializeED(OhciEndpoint, + ED, + OhciEndpoint->FirstTD, + EndpointProperties->BufferPA); + + OhciEndpoint->HcdED->Flags = OHCI_HCD_ED_FLAG_RESET_ON_HALT | 1; + + OHCI_InsertEndpointInSchedule(OhciEndpoint); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_OpenBulkEndpoint(IN POHCI_EXTENSION OhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_HCD_ED ED; + POHCI_HCD_TD TdVA; + POHCI_HCD_TD TdPA; + ULONG TdCount; + + DPRINT_OHCI("OHCI_OpenBulkEndpoint: ... \n"); + + ED = (POHCI_HCD_ED)EndpointProperties->BufferVA; + + OhciEndpoint->FirstTD = (POHCI_HCD_TD)((ULONG_PTR)ED + sizeof(OHCI_HCD_ED)); + OhciEndpoint->HeadED = &OhciExtension->BulkStaticED; + + TdCount = (EndpointProperties->BufferLength - sizeof(OHCI_HCD_ED)) / + sizeof(OHCI_HCD_TD); + + OhciEndpoint->MaxTransferDescriptors = TdCount; + + if (TdCount > 0) + { + TdVA = OhciEndpoint->FirstTD; + + TdPA = (POHCI_HCD_TD)((ULONG_PTR)EndpointProperties->BufferPA + + sizeof(OHCI_HCD_ED)); + + do + { + DPRINT_OHCI("OHCI_OpenBulkEndpoint: InitTD. TdVA - %p, TdPA - %p\n", + TdVA, + TdPA); + + RtlZeroMemory(TdVA, sizeof(OHCI_HCD_TD)); + + TdVA->PhysicalAddress = (ULONG_PTR)TdPA; + TdVA->Flags = 0; + TdVA->OhciTransfer = NULL; + + ++TdVA; + ++TdPA; + --TdCount; + } + while (TdCount > 0); + } + + + OhciEndpoint->HcdED = OHCI_InitializeED(OhciEndpoint, + ED, + OhciEndpoint->FirstTD, + EndpointProperties->BufferPA); + + OHCI_InsertEndpointInSchedule(OhciEndpoint); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_OpenInterruptEndpoint(IN POHCI_EXTENSION OhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN POHCI_ENDPOINT OhciEndpoint) +{ + UCHAR Index[8]; + UCHAR Period; + ULONG PeriodIdx = 0; + POHCI_HCD_ED ED; + ULONG ScheduleOffset; + POHCI_HCD_TD TdVA; + POHCI_HCD_TD TdPA; + ULONG TdCount; + + DPRINT_OHCI("OHCI_OpenInterruptEndpoint: ... \n"); + + ED = (POHCI_HCD_ED)EndpointProperties->BufferVA; + + OhciEndpoint->FirstTD = (POHCI_HCD_TD)((ULONG_PTR)ED + sizeof(OHCI_HCD_ED)); + + Index[0] = (1 << 0) - 1; + Index[1] = (1 << 1) - 1; + Index[2] = (1 << 2) - 1; + Index[3] = (1 << 3) - 1; + Index[4] = (1 << 4) - 1; + Index[5] = (1 << 5) - 1; + Index[6] = (1 << 5) - 1; + Index[7] = (1 << 5) - 1; + + Period = EndpointProperties->Period; + + while (!(Period & 1)) + { + ++PeriodIdx; + Period >>= 1; + } + + ScheduleOffset = EndpointProperties->ScheduleOffset; + DPRINT_OHCI("OHCI_OpenInterruptEndpoint: InitTD. Index[PeriodIdx] - %x, ScheduleOffset - %x\n", + Index[PeriodIdx], + ScheduleOffset); + + OhciEndpoint->HeadED = &OhciExtension->IntStaticED[Index[PeriodIdx] + + ScheduleOffset]; + + //OhciEndpoint->HeadED->UsbBandwidth += EndpointProperties->UsbBandwidth; + + TdCount = (EndpointProperties->BufferLength - sizeof(OHCI_HCD_ED)) / + sizeof(OHCI_HCD_TD); + + OhciEndpoint->MaxTransferDescriptors = TdCount; + + if (TdCount > 0) + { + TdVA = OhciEndpoint->FirstTD; + TdPA = (POHCI_HCD_TD)((ULONG_PTR)EndpointProperties->BufferPA + + sizeof(OHCI_HCD_ED)); + + do + { + DPRINT_OHCI("OHCI_OpenInterruptEndpoint: InitTD. TdVA - %p, TdPA - %p\n", + TdVA, + TdPA); + + RtlZeroMemory(TdVA, sizeof(OHCI_HCD_TD)); + + TdVA->PhysicalAddress = (ULONG_PTR)TdPA; + TdVA->Flags = 0; + TdVA->OhciTransfer = NULL; + + ++TdVA; + ++TdPA; + --TdCount; + } + while (TdCount > 0); + + } + + OhciEndpoint->HcdED = OHCI_InitializeED(OhciEndpoint, + ED, + OhciEndpoint->FirstTD, + EndpointProperties->BufferPA); + + OHCI_InsertEndpointInSchedule(OhciEndpoint); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_OpenIsoEndpoint(IN POHCI_EXTENSION OhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN POHCI_ENDPOINT OhciEndpoint) +{ + DPRINT1("OHCI_OpenIsoEndpoint: UNIMPLEMENTED. FIXME\n"); + return 6; +} + +MPSTATUS +NTAPI +OHCI_OpenEndpoint(IN PVOID ohciExtension, + IN PVOID endpointParameters, + IN PVOID ohciEndpoint) +{ + POHCI_EXTENSION OhciExtension; + POHCI_ENDPOINT OhciEndpoint; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG TransferType; + ULONG Result; + + DPRINT_OHCI("OHCI_OpenEndpoint: ... \n"); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + EndpointProperties = (PUSBPORT_ENDPOINT_PROPERTIES)endpointParameters; + + RtlCopyMemory(&OhciEndpoint->EndpointProperties, + endpointParameters, + sizeof(USBPORT_ENDPOINT_PROPERTIES)); + + InitializeListHead(&OhciEndpoint->TDList); + + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + Result = OHCI_OpenIsoEndpoint(OhciExtension, + EndpointProperties, + OhciEndpoint); + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + Result = OHCI_OpenControlEndpoint(OhciExtension, + EndpointProperties, + OhciEndpoint); + break; + + case USBPORT_TRANSFER_TYPE_BULK: + Result = OHCI_OpenBulkEndpoint(OhciExtension, + EndpointProperties, + OhciEndpoint); + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + Result = OHCI_OpenInterruptEndpoint(OhciExtension, + EndpointProperties, + OhciEndpoint); + break; + + default: + Result = 6; + break; + } + + return Result; +} + +MPSTATUS +NTAPI +OHCI_ReopenEndpoint(IN PVOID ohciExtension, + IN PVOID endpointParameters, + IN PVOID ohciEndpoint) +{ + POHCI_ENDPOINT OhciEndpoint; + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + POHCI_HCD_ED ED; + + DPRINT_OHCI("OHCI_ReopenEndpoint: ... \n"); + + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + EndpointProperties = (PUSBPORT_ENDPOINT_PROPERTIES)endpointParameters; + + ED = OhciEndpoint->HcdED; + + RtlCopyMemory(&OhciEndpoint->EndpointProperties, + EndpointProperties, + sizeof(USBPORT_ENDPOINT_PROPERTIES)); + + ED->HwED.EndpointControl.FunctionAddress = + OhciEndpoint->EndpointProperties.DeviceAddress; + + ED->HwED.EndpointControl.MaximumPacketSize = + OhciEndpoint->EndpointProperties.TotalMaxPacketSize; + + return 0; +} + +VOID +NTAPI +OHCI_QueryEndpointRequirements(IN PVOID ohciExtension, + IN PVOID endpointParameters, + IN PULONG EndpointRequirements) +{ + PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties; + ULONG TransferType; + + DPRINT_OHCI("OHCI_QueryEndpointRequirements: ... \n"); + + EndpointProperties = (PUSBPORT_ENDPOINT_PROPERTIES)endpointParameters; + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + DPRINT_OHCI("OHCI_QueryEndpointRequirements: IsoTransfer\n"); + *((PULONG)EndpointRequirements + 1) = 0x10000; + *EndpointRequirements = sizeof(OHCI_HCD_ED) + + 0x40 * sizeof(OHCI_HCD_TD); + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + DPRINT_OHCI("OHCI_QueryEndpointRequirements: ControlTransfer\n"); + *((PULONG)EndpointRequirements + 1) = 0x10000; + *EndpointRequirements = sizeof(OHCI_HCD_ED) + + 0x26 * sizeof(OHCI_HCD_TD); + break; + + case USBPORT_TRANSFER_TYPE_BULK: + DPRINT_OHCI("OHCI_QueryEndpointRequirements: BulkTransfer\n"); + *((PULONG)EndpointRequirements + 1) = 0x40000; + *EndpointRequirements = sizeof(OHCI_HCD_ED) + + 0x44 * sizeof(OHCI_HCD_TD); + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + DPRINT_OHCI("OHCI_QueryEndpointRequirements: InterruptTransfer\n"); + *((PULONG)EndpointRequirements + 1) = 0x1000; + *EndpointRequirements = sizeof(OHCI_HCD_ED) + + 4 * sizeof(OHCI_HCD_TD); + break; + + default: + DPRINT1("OHCI_QueryEndpointRequirements: Unknown TransferType - %x\n", + TransferType); + DbgBreakPoint(); + break; + } +} + +VOID +NTAPI +OHCI_CloseEndpoint(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN BOOLEAN IsDoDisablePeriodic) +{ +#if DBG + DPRINT1("OHCI_Unload: Not supported\n"); +#endif + return; +} + +MPSTATUS +NTAPI +OHCI_TakeControlHC(IN POHCI_EXTENSION OhciExtension) +{ + DPRINT1("OHCI_TakeControlHC: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +OHCI_StartController(IN PVOID ohciExtension, + IN PUSBPORT_RESOURCES Resources) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + OHCI_REG_INTERRUPT_ENABLE_DISABLE Interrupts; + OHCI_REG_RH_STATUS HcRhStatus; + OHCI_REG_FRAME_INTERVAL FrameInterval; + OHCI_REG_CONTROL Control; + PVOID ScheduleStartVA; + PVOID ScheduleStartPA; + UCHAR HeadIndex; + POHCI_ENDPOINT_DESCRIPTOR StaticED; + ULONG_PTR SchedulePA; + POHCI_HCCA OhciHCCA; + LARGE_INTEGER SystemTime; + LARGE_INTEGER CurrentTime; + ULONG ix; + ULONG jx; + MPSTATUS MPStatus = 0; + + DPRINT_OHCI("OHCI_StartController: ohciExtension - %p, Resources - %p\n", + ohciExtension, + Resources); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + /* HC on-chip operational registers */ + OperationalRegs = (POHCI_OPERATIONAL_REGISTERS)Resources->ResourceBase; + OhciExtension->OperationalRegs = OperationalRegs; + + MPStatus = OHCI_TakeControlHC(OhciExtension); + + if (MPStatus != 0) + { + DPRINT1("OHCI_StartController: OHCI_TakeControlHC return MPStatus - %x\n", + MPStatus); + + return MPStatus; + } + + OhciExtension->HcResourcesVA = (ULONG_PTR)Resources->StartVA; + OhciExtension->HcResourcesPA = (ULONG_PTR)Resources->StartPA; + + DPRINT_OHCI("OHCI_StartController: HcResourcesVA - %p, HcResourcesPA - %p\n", + OhciExtension->HcResourcesVA, + OhciExtension->HcResourcesPA); + + ScheduleStartVA = (PVOID)((ULONG_PTR)Resources->StartVA + sizeof(OHCI_HCCA)); + ScheduleStartPA = (PVOID)((ULONG_PTR)Resources->StartPA + sizeof(OHCI_HCCA)); + + OhciExtension->ScheduleStartVA = ScheduleStartVA; + OhciExtension->ScheduleStartPA = ScheduleStartPA; + + StaticED = (POHCI_ENDPOINT_DESCRIPTOR)ScheduleStartVA; + SchedulePA = (ULONG_PTR)ScheduleStartPA; + + ix = 0; + + for (ix = 0; ix < 63; ix++) // FIXME 63 == 32+16+8+4+2+1 (Endpoint Poll Interval (ms)) + { + if (ix == 0) + { + HeadIndex = ED_EOF; + StaticED->NextED = 0; + } + else + { + HeadIndex = ((ix - 1) >> 1); + ASSERT(HeadIndex >= 0 && HeadIndex < 31); + StaticED->NextED = OhciExtension->IntStaticED[HeadIndex].PhysicalAddress; + } + + StaticED->EndpointControl.sKip = 1; + StaticED->TailPointer = 0; + StaticED->HeadPointer = 0; + + OhciExtension->IntStaticED[ix].HwED = StaticED; + OhciExtension->IntStaticED[ix].PhysicalAddress = SchedulePA; + OhciExtension->IntStaticED[ix].HeadIndex = HeadIndex; + OhciExtension->IntStaticED[ix].pNextED = &StaticED->NextED; + + InitializeListHead(&OhciExtension->IntStaticED[ix].Link); + + StaticED += 1; + SchedulePA += sizeof(OHCI_ENDPOINT_DESCRIPTOR); + } + + OhciHCCA = (POHCI_HCCA)OhciExtension->HcResourcesVA; + DPRINT_OHCI("OHCI_InitializeSchedule: OhciHCCA - %p\n", OhciHCCA); + + for (ix = 0, jx = 31; ix < 32; ix++, jx++) + { + static UCHAR Balance[32] = + {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, + 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31}; + + OhciHCCA->InterrruptTable[Balance[ix]] = + (POHCI_ENDPOINT_DESCRIPTOR)(OhciExtension->IntStaticED[jx].PhysicalAddress); + + OhciExtension->IntStaticED[jx].pNextED = + (PULONG)&OhciHCCA->InterrruptTable[Balance[ix]]; + + OhciExtension->IntStaticED[jx].HccaIndex = Balance[ix]; + } + + DPRINT_OHCI("OHCI_InitializeSchedule: ix - %x\n", ix); + + InitializeListHead(&OhciExtension->ControlStaticED.Link); + + OhciExtension->ControlStaticED.HeadIndex = ED_EOF; + OhciExtension->ControlStaticED.Type = OHCI_NUMBER_OF_INTERRUPTS + 1; + OhciExtension->ControlStaticED.pNextED = &OperationalRegs->HcControlHeadED; + + InitializeListHead(&OhciExtension->BulkStaticED.Link); + + OhciExtension->BulkStaticED.HeadIndex = ED_EOF; + OhciExtension->BulkStaticED.Type = OHCI_NUMBER_OF_INTERRUPTS + 2; + OhciExtension->BulkStaticED.pNextED = &OperationalRegs->HcBulkHeadED; + + FrameInterval.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcFmInterval.AsULONG); + + if ((FrameInterval.FrameInterval) < ((12000 - 1) - 120) || + (FrameInterval.FrameInterval) > ((12000 - 1) + 120)) // FIXME 10% + { + FrameInterval.FrameInterval = (12000 - 1); + } + + FrameInterval.FrameIntervalToggle = 1; + FrameInterval.FSLargestDataPacket = + ((FrameInterval.FrameInterval - MAXIMUM_OVERHEAD) * 6) / 7; + + OhciExtension->FrameInterval = FrameInterval; + + DPRINT_OHCI("OHCI_StartController: FrameInterval - %p\n", + FrameInterval.AsULONG); + + /* reset */ + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommandStatus.AsULONG, + 1); + + KeStallExecutionProcessor(25); + + Control.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG); + Control.HostControllerFunctionalState = OHCI_HC_STATE_RESET; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG, + Control.AsULONG); + + KeQuerySystemTime(&CurrentTime); + CurrentTime.QuadPart += 5000000; // 0.5 sec + + while (TRUE) + { + WRITE_REGISTER_ULONG(&OperationalRegs->HcFmInterval.AsULONG, + OhciExtension->FrameInterval.AsULONG); + + FrameInterval.AsULONG = + READ_REGISTER_ULONG(&OperationalRegs->HcFmInterval.AsULONG); + + KeQuerySystemTime(&SystemTime); + + if (SystemTime.QuadPart >= CurrentTime.QuadPart) + { + MPStatus = 7; + break; + } + + if (FrameInterval.AsULONG == OhciExtension->FrameInterval.AsULONG) + { + MPStatus = 0; + break; + } + } + + if (MPStatus != 0) + { + DPRINT_OHCI("OHCI_StartController: frame interval not set\n"); + return MPStatus; + } + + WRITE_REGISTER_ULONG(&OperationalRegs->HcPeriodicStart, + (OhciExtension->FrameInterval.FrameInterval * 9) / 10); //90% + + WRITE_REGISTER_ULONG(&OperationalRegs->HcHCCA, + OhciExtension->HcResourcesPA); + + Interrupts.AsULONG = 0; + + Interrupts.SchedulingOverrun = 1; + Interrupts.WritebackDoneHead = 1; + Interrupts.UnrecoverableError = 1; + Interrupts.FrameNumberOverflow = 1; + Interrupts.OwnershipChange = 1; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + Interrupts.AsULONG); + + Control.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG); + + Control.ControlBulkServiceRatio = 0; // FIXME (1 : 1) + Control.PeriodicListEnable = 1; + Control.IsochronousEnable = 1; + Control.ControlListEnable = 1; + Control.BulkListEnable = 1; + Control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG, + Control.AsULONG); + + HcRhStatus.AsULONG = 0; + HcRhStatus.SetGlobalPower = 1; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcRhStatus.AsULONG, + HcRhStatus.AsULONG); + + return 0; +} + +VOID +NTAPI +OHCI_StopController(IN PVOID ohciExtension, + IN BOOLEAN IsDoDisableInterrupts) +{ + DPRINT1("OHCI_StopController: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +OHCI_SuspendController(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + OHCI_REG_CONTROL Control; + OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptReg; + + DPRINT("OHCI_SuspendController: ... \n"); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OperationalRegs = OhciExtension->OperationalRegs; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptDisable.AsULONG, + 0xFFFFFFFF); + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptStatus.AsULONG, + 0xFFFFFFFF); + + Control.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG); + + Control.HostControllerFunctionalState = OHCI_HC_STATE_SUSPEND; + Control.RemoteWakeupEnable = 1; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG, + Control.AsULONG); + + InterruptReg.AsULONG = 0; + InterruptReg.ResumeDetected = 1; + InterruptReg.UnrecoverableError = 1; + InterruptReg.RootHubStatusChange = 1; + InterruptReg.MasterInterruptEnable = 1; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + InterruptReg.AsULONG); +} + +MPSTATUS +NTAPI +OHCI_ResumeController(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + POHCI_HCCA HcHCCA; + OHCI_REG_CONTROL control; + OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptReg; + + DPRINT("OHCI_ResumeController \n"); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OperationalRegs = OhciExtension->OperationalRegs; + + control.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG); + + if (control.HostControllerFunctionalState != OHCI_HC_STATE_SUSPEND) + { + return 7; + } + + HcHCCA = (POHCI_HCCA)OhciExtension->HcResourcesVA; + HcHCCA->Pad1 = 0; + + control.HostControllerFunctionalState = OHCI_HC_STATE_OPERATIONAL; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG, + control.AsULONG); + + InterruptReg.AsULONG = 0; + + InterruptReg.SchedulingOverrun = 1; + InterruptReg.WritebackDoneHead = 1; + InterruptReg.UnrecoverableError = 1; + InterruptReg.FrameNumberOverflow = 1; + InterruptReg.OwnershipChange = 1; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + InterruptReg.AsULONG); + + WRITE_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG, + control.AsULONG); + + return 0; +} + +BOOLEAN +NTAPI +OHCI_HardwarePresent(IN POHCI_EXTENSION OhciExtension, + IN BOOLEAN IsInvalidateController) +{ + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + BOOLEAN Result = FALSE; + + //DPRINT_OHCI("OHCI_HardwarePresent: IsInvalidateController - %x\n", + // IsInvalidateController); + + OperationalRegs = OhciExtension->OperationalRegs; + + if (READ_REGISTER_ULONG(&OperationalRegs->HcCommandStatus.AsULONG) == -1) + { + if (IsInvalidateController) + { + RegPacket.UsbPortInvalidateController(OhciExtension, 2); + } + + Result = FALSE; + } + else + { + Result = TRUE; + } + + return Result; +} + +BOOLEAN +NTAPI +OHCI_InterruptService(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptReg; + OHCI_REG_INTERRUPT_STATUS IntStatus; + POHCI_HCCA HcHCCA; + BOOLEAN Result = FALSE; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + + DPRINT_OHCI("OHCI_InterruptService: OhciExtension - %p\n", + OhciExtension); + + OperationalRegs = OhciExtension->OperationalRegs; + + Result = OHCI_HardwarePresent(OhciExtension, FALSE); + + if (!Result) + { + return FALSE; + } + + InterruptReg.AsULONG = + READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG); + + IntStatus.AsULONG = InterruptReg.AsULONG & + READ_REGISTER_ULONG(&OperationalRegs->HcInterruptStatus.AsULONG); + + if (IntStatus.AsULONG && InterruptReg.MasterInterruptEnable) + { + if (IntStatus.UnrecoverableError) + { + DbgBreakPoint(); + } + + if (IntStatus.FrameNumberOverflow) + { + HcHCCA = (POHCI_HCCA)OhciExtension->HcResourcesVA; + + DPRINT("OHCI_InterruptService: FrameNumberOverflow. HcHCCA->FrameNumber - %p\n", + HcHCCA->FrameNumber); + + OhciExtension->FrameHighPart += 0x10000 - + ((HcHCCA->FrameNumber ^ OhciExtension->FrameHighPart) & 0x8000); + } + + Result = TRUE; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptDisable.AsULONG, + 0x80000000); + } + + return Result; +} + +VOID +NTAPI +OHCI_InterruptDpc(IN PVOID ohciExtension, + IN BOOLEAN IsDoEnableInterrupts) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + OHCI_REG_INTERRUPT_STATUS IntStatus; + POHCI_HCCA HcHCCA; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OperationalRegs = OhciExtension->OperationalRegs; + + DPRINT_OHCI("OHCI_InterruptDpc: OhciExtension - %p, IsDoEnableInterrupts - %p\n", + OhciExtension, + IsDoEnableInterrupts); + + IntStatus.AsULONG = + READ_REGISTER_ULONG(&OperationalRegs->HcInterruptStatus.AsULONG); + + if (IntStatus.RootHubStatusChange) + { + DPRINT_OHCI("OHCI_InterruptDpc: RootHubStatusChange\n"); + RegPacket.UsbPortInvalidateRootHub(OhciExtension); + } + + if (IntStatus.WritebackDoneHead) + { + DPRINT_OHCI("OHCI_InterruptDpc: WritebackDoneHead\n"); + + HcHCCA = (POHCI_HCCA)OhciExtension->HcResourcesVA; + HcHCCA->DoneHead = 0; + + RegPacket.UsbPortInvalidateEndpoint(OhciExtension, 0); + } + + if (IntStatus.StartofFrame) + { + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptDisable.AsULONG, + 4); + } + + if (IntStatus.ResumeDetected) + { + ASSERT(FALSE); + } + + if (IntStatus.UnrecoverableError) + { + ASSERT(FALSE); + } + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptStatus.AsULONG, + IntStatus.AsULONG); + + if (IsDoEnableInterrupts) + { + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + 0x80000000); + } +} + +ULONG +NTAPI +OHCI_MapTransferToTD(IN POHCI_EXTENSION OhciExtension, + IN ULONG MaxPacketSize, + IN OUT ULONG TransferedLen, + IN POHCI_TRANSFER OhciTransfer, + IN POHCI_HCD_TD TD, + IN PUSBPORT_SCATTER_GATHER_LIST SGList) +{ + PUSBPORT_SCATTER_GATHER_ELEMENT SgElement; + ULONG SgIdx = 0; + ULONG SgRemain; + ULONG LengthThisTd; + ULONG_PTR BufferEnd; + ULONG Offset; + ULONG TransferLength; + ULONG Buffer; + + DPRINT_OHCI("OHCI_MapTransferToTD: TransferedLen - %x\n", TransferedLen); + + if (SGList->SgElementCount > 0) + { + SgElement = &SGList->SgElement[0]; + + do + { + if (TransferedLen >= SgElement->SgOffset && + TransferedLen < SgElement->SgOffset + SgElement->SgTransferLength) + { + break; + } + + ++SgIdx; + + SgElement += 1; + } + while (SgIdx < SGList->SgElementCount); + } + + DPRINT_OHCI("OHCI_MapTransferToTD: SgIdx - %x, SgCount - %x\n", + SgIdx, + SGList->SgElementCount); + + ASSERT(SgIdx < SGList->SgElementCount); + + if (SGList->Flags & 1) + { + ASSERT(FALSE); + } + + Offset = TransferedLen - SGList->SgElement[SgIdx].SgOffset; + Buffer = SGList->SgElement[SgIdx].SgPhysicalAddress.LowPart + Offset; + + SgRemain = SGList->SgElementCount - SgIdx; + + if (SgRemain == 1) + { + LengthThisTd = OhciTransfer->TransferParameters->TransferBufferLength - + TransferedLen - + Offset; + + BufferEnd = SGList->SgElement[SgIdx].SgPhysicalAddress.LowPart + + LengthThisTd; + } + else if (SgRemain == 2) + { + LengthThisTd = OhciTransfer->TransferParameters->TransferBufferLength - + TransferedLen; + + BufferEnd = SGList->SgElement[SgIdx + 1].SgPhysicalAddress.LowPart + + SGList->SgElement[SgIdx + 1].SgTransferLength; + } + else + { + TransferLength = SGList->SgElement[SgIdx].SgTransferLength + + SGList->SgElement[SgIdx+1].SgTransferLength - + Offset; + + BufferEnd = SGList->SgElement[SgIdx + 1].SgPhysicalAddress.LowPart + + SGList->SgElement[SgIdx + 1].SgTransferLength; + + LengthThisTd = MaxPacketSize * (TransferLength / MaxPacketSize); + + if (TransferLength > LengthThisTd) + { + BufferEnd -= (TransferLength - LengthThisTd); + } + } + + TD->HwTD.gTD.CurrentBuffer = (PVOID)Buffer; + TD->HwTD.gTD.BufferEnd = (PVOID)(BufferEnd - 1); + TD->TransferLen = LengthThisTd; + + return TransferedLen + LengthThisTd; +} + +POHCI_HCD_TD +NTAPI +OHCI_AllocateTD(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_HCD_TD TD; + ULONG MaxTDs; + ULONG ix; + + DPRINT_OHCI("OHCI_AllocateTD: ... \n"); + + MaxTDs = OhciEndpoint->MaxTransferDescriptors; + + if (MaxTDs == 0) + { + return (POHCI_HCD_TD)-1; + } + + TD = OhciEndpoint->FirstTD; + + ix = 0; + + while (TD->Flags & OHCI_HCD_TD_FLAG_ALLOCATED) + { + ++ix; + TD += 1; + + if (ix >= MaxTDs) + { + return (POHCI_HCD_TD)-1; + } + } + + TD->Flags |= OHCI_HCD_TD_FLAG_ALLOCATED; + + return TD; +} + +ULONG +NTAPI +OHCI_RemainTDs(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_HCD_TD TD; + ULONG MaxTDs; + ULONG Result; + + DPRINT_OHCI("OHCI_RemainTDs: ... \n"); + + MaxTDs = OhciEndpoint->MaxTransferDescriptors; + + if (MaxTDs == 0) + { + return 0; + } + + TD = (POHCI_HCD_TD)OhciEndpoint->FirstTD; + + Result = 0; + + do + { + if (!(TD->Flags & OHCI_HCD_TD_FLAG_ALLOCATED)) + { + ++Result; + } + + TD += 1; + --MaxTDs; + } + while (MaxTDs > 0); + + return Result; +} + +ULONG +NTAPI +OHCI_ControlTransfer(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN POHCI_TRANSFER OhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SGList) +{ + POHCI_HCD_TD FirstTD; + POHCI_HCD_TD FirstTdPA; + POHCI_HCD_TD TD; + POHCI_HCD_TD NextTD; + POHCI_HCD_TD LastTd; + ULONG_PTR SetupPacket; + ULONG MaxTDs; + ULONG TransferedLen; + UCHAR DataToggle; + ULONG MaxPacketSize; + + DPRINT_OHCI("OHCI_ControlTransfer: ... \n"); + + MaxTDs = OHCI_RemainTDs(OhciExtension, OhciEndpoint); + + if (SGList->SgElementCount + 2 > MaxTDs) + { + return 1; + } + + FirstTD = OhciEndpoint->HcdTailP; + + FirstTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE; + FirstTD->HwTD.gTD.CurrentBuffer = NULL; + FirstTD->HwTD.gTD.BufferEnd = NULL; + FirstTD->HwTD.gTD.NextTD = 0; + + RtlCopyMemory(&FirstTD->HwTD.SetupPacket, + &TransferParameters->SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + FirstTD->HwTD.Padded[0] = 0; + FirstTD->HwTD.Padded[1] = 0; + + FirstTD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED; + FirstTD->OhciTransfer = OhciTransfer; + FirstTD->NextHcdTD = NULL; + + FirstTD->HwTD.gTD.Control.AsULONG = 0; + FirstTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE; + FirstTD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED; + FirstTD->HwTD.gTD.Control.DataToggle = 2; + + FirstTdPA = (POHCI_HCD_TD)FirstTD->PhysicalAddress; + SetupPacket = (ULONG_PTR)&FirstTdPA->HwTD.SetupPacket; + + FirstTD->HwTD.gTD.CurrentBuffer = (PVOID)SetupPacket; + FirstTD->HwTD.gTD.BufferEnd = (PVOID)(SetupPacket + + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET) - + 1); + + TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint); + ++OhciTransfer->PendingTDs; + + TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE; + TD->HwTD.gTD.CurrentBuffer = NULL; + TD->HwTD.gTD.BufferEnd = NULL; + TD->HwTD.gTD.NextTD = NULL; + + RtlZeroMemory(&TD->HwTD.SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + TD->HwTD.Padded[0] = 0; + TD->HwTD.Padded[1] = 0; + + TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED; + TD->OhciTransfer = OhciTransfer; + TD->NextHcdTD = NULL; + + FirstTD->HwTD.gTD.NextTD = (PULONG)(TD->PhysicalAddress); + FirstTD->NextHcdTD = TD; + + LastTd = FirstTD; + + if (TransferParameters->TransferBufferLength > 0) + { + DataToggle = 3; + TransferedLen = 0; + + do + { + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN; + } + else + { + TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT; + } + + TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE; + TD->HwTD.gTD.Control.DataToggle = DataToggle; + TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED; + + DataToggle = 0; + + MaxPacketSize = OhciEndpoint->EndpointProperties.TotalMaxPacketSize; + + TransferedLen = OHCI_MapTransferToTD(OhciExtension, + MaxPacketSize, + TransferedLen, + OhciTransfer, + TD, + SGList); + + LastTd = TD; + + TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint); + ++OhciTransfer->PendingTDs; + + TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE; + TD->HwTD.gTD.CurrentBuffer = NULL; + TD->HwTD.gTD.BufferEnd = NULL; + TD->HwTD.gTD.NextTD = NULL; + + RtlZeroMemory(&TD->HwTD.SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + TD->HwTD.Padded[0] = 0; + TD->HwTD.Padded[1] = 0; + + TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED; + TD->OhciTransfer = OhciTransfer; + TD->NextHcdTD = NULL; + + LastTd->HwTD.gTD.NextTD = (PVOID)TD->PhysicalAddress; + LastTd->NextHcdTD = TD; + } + while (TransferedLen < TransferParameters->TransferBufferLength); + } + + if (TransferParameters->TransferFlags & USBD_SHORT_TRANSFER_OK) + { + LastTd->HwTD.gTD.Control.DelayInterrupt |= 4; + OhciTransfer->Flags |= OHCI_HCD_TD_FLAG_ALLOCATED; + } + + TD->HwTD.gTD.Control.AsULONG = 0; + TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED; + TD->HwTD.gTD.Control.DataToggle = 3; + TD->HwTD.gTD.CurrentBuffer = NULL; + TD->HwTD.gTD.BufferEnd = NULL; + + TD->Flags |= OHCI_HCD_TD_FLAG_CONTROLL; + TD->TransferLen = 0; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.gTD.Control.BufferRounding = FALSE; + TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT; + } + else + { + TD->HwTD.gTD.Control.BufferRounding = TRUE; + TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN; + } + + NextTD = OHCI_AllocateTD(OhciExtension, OhciEndpoint); + ++OhciTransfer->PendingTDs; + + TD->HwTD.gTD.NextTD = (PULONG)(NextTD->PhysicalAddress); + TD->NextHcdTD = NextTD; + + NextTD->HwTD.gTD.NextTD = NULL; + NextTD->NextHcdTD = NULL; + + OhciTransfer->NextTD = NextTD; + OhciEndpoint->HcdTailP = NextTD; + OhciEndpoint->HcdED->HwED.TailPointer = (ULONG_PTR)NextTD->PhysicalAddress; + + OHCI_EnableList(OhciExtension, OhciEndpoint); + + return 0; +} + +ULONG +NTAPI +OHCI_BulkOrInterruptTransfer(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN POHCI_TRANSFER OhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SGList) +{ + POHCI_HCD_TD TD; + POHCI_HCD_TD PrevTD; + ULONG TransferedLen; + ULONG MaxTDs; + ULONG MaxPacketSize; + + DPRINT_OHCI("OHCI_BulkOrInterruptTransfer: ... \n"); + + MaxTDs = OHCI_RemainTDs(OhciExtension, OhciEndpoint); + + if (SGList->SgElementCount > MaxTDs) + { + return 1; + } + + TD = OhciEndpoint->HcdTailP; + + TransferedLen = 0; + + do + { + TD->HwTD.gTD.Control.AsULONG = 0; + TD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_NONE; + TD->HwTD.gTD.Control.ConditionCode = OHCI_TD_CONDITION_NOT_ACCESSED; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + TD->HwTD.gTD.Control.BufferRounding = FALSE; + TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_IN; + } + else + { + TD->HwTD.gTD.Control.BufferRounding = TRUE; + TD->HwTD.gTD.Control.DirectionPID = OHCI_TD_DIRECTION_PID_OUT; + } + + TD->HwTD.gTD.CurrentBuffer = NULL; + TD->HwTD.gTD.NextTD = NULL; + TD->HwTD.gTD.BufferEnd = NULL; + + RtlZeroMemory(&TD->HwTD.SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + TD->HwTD.Padded[0] = 0; + TD->HwTD.Padded[1] = 0; + + TD->Flags |= OHCI_HCD_TD_FLAG_PROCESSED; + TD->OhciTransfer = OhciTransfer; + TD->NextHcdTD = NULL; + + if (TransferParameters->TransferBufferLength) + { + MaxPacketSize = OhciEndpoint->EndpointProperties.TotalMaxPacketSize; + + TransferedLen = OHCI_MapTransferToTD(OhciExtension, + MaxPacketSize, + TransferedLen, + OhciTransfer, + TD, + SGList); + } + else + { + ASSERT(SGList->SgElementCount == 0); + + TD->HwTD.gTD.CurrentBuffer = NULL; + TD->HwTD.gTD.BufferEnd = NULL; + + TD->TransferLen = 0; + } + + PrevTD = TD; + + TD = OHCI_AllocateTD(OhciExtension, OhciEndpoint); + ++OhciTransfer->PendingTDs; + + PrevTD->HwTD.gTD.NextTD = (PULONG)TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + } + while (TransferedLen < TransferParameters->TransferBufferLength); + + if (TransferParameters->TransferFlags & USBD_SHORT_TRANSFER_OK) + { + PrevTD->HwTD.gTD.Control.BufferRounding = TRUE; + OhciTransfer->Flags |= 1; + } + + PrevTD->HwTD.gTD.Control.DelayInterrupt = OHCI_TD_INTERRUPT_IMMEDIATE; + PrevTD->HwTD.gTD.NextTD = (PULONG)TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + + TD->HwTD.gTD.NextTD = NULL; + TD->NextHcdTD = NULL; + + OhciTransfer->NextTD = TD; + OhciEndpoint->HcdTailP = TD; + + OhciEndpoint->HcdED->HwED.TailPointer = (ULONG_PTR)TD->PhysicalAddress; + + OHCI_EnableList(OhciExtension, OhciEndpoint); + + return 0; +} + +MPSTATUS +NTAPI +OHCI_SubmitTransfer(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN PVOID transferParameters, + IN PVOID ohciTransfer, + IN PVOID sgList) +{ + POHCI_EXTENSION OhciExtension; + POHCI_ENDPOINT OhciEndpoint; + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + POHCI_TRANSFER OhciTransfer; + PUSBPORT_SCATTER_GATHER_LIST SGList; + ULONG TransferType; + + DPRINT_OHCI("OHCI_SubmitTransfer: ... \n"); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + TransferParameters = (PUSBPORT_TRANSFER_PARAMETERS)transferParameters; + OhciTransfer = (POHCI_TRANSFER)ohciTransfer; + SGList = (PUSBPORT_SCATTER_GATHER_LIST)sgList; + + RtlZeroMemory(OhciTransfer, sizeof(OHCI_TRANSFER)); + + OhciTransfer->TransferParameters = TransferParameters; + OhciTransfer->OhciEndpoint = OhciEndpoint; + + TransferType = OhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + return OHCI_ControlTransfer(OhciExtension, + OhciEndpoint, + TransferParameters, + OhciTransfer, + SGList); + } + + if (TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + return OHCI_BulkOrInterruptTransfer(OhciExtension, + OhciEndpoint, + TransferParameters, + OhciTransfer, + SGList); + } + + return 1; +} + +MPSTATUS +NTAPI +OHCI_SubmitIsoTransfer(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN PVOID transferParameters, + IN PVOID ohciTransfer, + IN PVOID isoParameters) +{ + DPRINT1("OHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +OHCI_ProcessDoneTD(IN POHCI_EXTENSION OhciExtension, + IN POHCI_HCD_TD TD, + IN BOOLEAN IsPortComplete) +{ + POHCI_TRANSFER OhciTransfer; + POHCI_ENDPOINT OhciEndpoint; + ULONG_PTR Buffer; + ULONG_PTR BufferEnd; + ULONG Length; + + DPRINT_OHCI("OHCI_ProcessDoneTD: ... \n"); + + OhciTransfer = TD->OhciTransfer; + OhciEndpoint = OhciTransfer->OhciEndpoint; + + --OhciTransfer->PendingTDs; + + Buffer = (ULONG_PTR)TD->HwTD.gTD.CurrentBuffer; + BufferEnd = (ULONG_PTR)TD->HwTD.gTD.BufferEnd; + + if (TD->Flags & 0x10) + { + TD->HwTD.gTD.Control.ConditionCode = 0; + } + else + { + if (TD->HwTD.gTD.CurrentBuffer) + { + if (TD->TransferLen) + { + Length = (((Buffer ^ BufferEnd) & 0xFFFFF000) != 0 ? 0x1000 : 0) + + (BufferEnd & 0xFFF) + 1 - (Buffer & 0xFFF); + + TD->TransferLen -= Length; + } + } + + if (TD->HwTD.gTD.Control.DirectionPID != OHCI_TD_DIRECTION_PID_SETUP) + { + OhciTransfer->TransferLen += TD->TransferLen; + } + + if (TD->HwTD.gTD.Control.ConditionCode) + { + OhciTransfer->USBDStatus = USBD_STATUS_HALTED | + TD->HwTD.gTD.Control.ConditionCode; + } + } + + TD->Flags = 0; + TD->HwTD.gTD.NextTD = NULL; + TD->OhciTransfer = NULL; + + TD->DoneLink.Flink = NULL; + TD->DoneLink.Blink = NULL; + + if (IsPortComplete && (OhciTransfer->PendingTDs == 0)) + { + RegPacket.UsbPortCompleteTransfer(OhciExtension, + OhciEndpoint, + OhciTransfer->TransferParameters, + OhciTransfer->USBDStatus, + OhciTransfer->TransferLen); + } +} + +VOID +NTAPI +OHCI_ProcessDoneIsoTD(IN POHCI_EXTENSION OhciExtension, + IN POHCI_HCD_TD TD, + IN BOOLEAN IsPortComplete) +{ + DPRINT1("OHCI_ProcessDoneIsoTD: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +OHCI_AbortTransfer(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN PVOID ohciTransfer, + IN OUT PULONG CompletedLength) +{ + POHCI_EXTENSION OhciExtension; + POHCI_ENDPOINT OhciEndpoint; + POHCI_TRANSFER OhciTransfer; + POHCI_HCD_ED ED; + ULONG_PTR NextTdPA; + POHCI_HCD_TD NextTD; + POHCI_HCD_TD TD; + POHCI_HCD_TD PrevTD; + POHCI_HCD_TD LastTD; + POHCI_HCD_TD td = 0; + ULONG ix; + BOOLEAN IsIsoEndpoint = FALSE; + BOOLEAN IsProcessed = FALSE; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + OhciTransfer = (POHCI_TRANSFER)ohciTransfer; + + DPRINT("OHCI_AbortTransfer: ohciEndpoint - %p, ohciTransfer - %p\n", + OhciEndpoint, + OhciTransfer); + + if (OhciEndpoint->EndpointProperties.TransferType == + USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + IsIsoEndpoint = TRUE; + } + + ED = OhciEndpoint->HcdED; + + NextTdPA = ED->HwED.HeadPointer & 0xFFFFFFF0; // physical pointer to the next TD + + NextTD = RegPacket.UsbPortGetMappedVirtualAddress((PVOID)NextTdPA, + OhciExtension, + OhciEndpoint); + + if (NextTD->OhciTransfer == OhciTransfer) + { + LastTD = OhciTransfer->NextTD; + + ED->HwED.HeadPointer = LastTD->PhysicalAddress | + (ED->HwED.HeadPointer & 2); + + OhciEndpoint->HcdHeadP = LastTD; + + if (OhciEndpoint->MaxTransferDescriptors != 0) + { + TD = OhciEndpoint->FirstTD; + ix = 0; + + do + { + if (TD->OhciTransfer == OhciTransfer) + { + if (IsIsoEndpoint) + { + OHCI_ProcessDoneIsoTD(OhciExtension, TD, FALSE); + } + else + { + OHCI_ProcessDoneTD(OhciExtension, TD, FALSE); + } + } + + TD += 1; + ++ix; + } + while (ix < OhciEndpoint->MaxTransferDescriptors); + } + + *CompletedLength = OhciTransfer->TransferLen; + + return; + } + + TD = OhciEndpoint->HcdHeadP; + + if (TD != NextTD) + { + do + { + if (TD->OhciTransfer == ohciTransfer) + { + PrevTD = TD; + TD = TD->NextHcdTD; + + if (PrevTD == OhciEndpoint->HcdHeadP) + { + OhciEndpoint->HcdHeadP = TD; + } + + if (IsIsoEndpoint) + { + OHCI_ProcessDoneIsoTD(OhciExtension, PrevTD, FALSE); + } + else + { + OHCI_ProcessDoneTD(OhciExtension, PrevTD, FALSE); + } + + IsProcessed = TRUE; + } + else + { + TD = TD->NextHcdTD; + } + } + while (TD != NextTD); + + if (!IsProcessed) + { + TD = OhciEndpoint->HcdHeadP; + + LastTD = TD; + td = NULL; + + while (TD != OhciEndpoint->HcdTailP) + { + if (TD->OhciTransfer == OhciTransfer) + { + td = TD; + break; + } + + LastTD = TD; + + TD = TD->NextHcdTD; + } + + TD = td; + + do + { + if (TD == OhciEndpoint->HcdTailP) + { + break; + } + + PrevTD = TD; + TD = TD->NextHcdTD; + + if (IsIsoEndpoint) + { + OHCI_ProcessDoneIsoTD(OhciExtension, PrevTD, FALSE); + } + else + { + OHCI_ProcessDoneTD(OhciExtension, PrevTD, FALSE); + } + } + while (TD->OhciTransfer == OhciTransfer); + + LastTD->OhciTransfer->NextTD = TD; + LastTD->NextHcdTD = TD; + LastTD->HwTD.gTD.NextTD = (PULONG)TD->PhysicalAddress; + } + } + + *CompletedLength = OhciTransfer->TransferLen; + + if (OhciTransfer->TransferLen) + { + DPRINT("OHCI_AbortTransfer: *CompletedLength - %x\n", *CompletedLength); + } +} + +ULONG +NTAPI +OHCI_GetEndpointState(IN PVOID ohciExtension, + IN PVOID ohciEndpoint) +{ + POHCI_ENDPOINT OhciEndpoint; + POHCI_HCD_ED ED; + + DPRINT_OHCI("OHCI_GetEndpointState: ... \n"); + + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + ED = OhciEndpoint->HcdED; + + if (ED->Flags & 0x10) + { + return USBPORT_ENDPOINT_CLOSED; + } + + if (ED->HwED.EndpointControl.sKip) + { + return USBPORT_ENDPOINT_PAUSED; + } + + return USBPORT_ENDPOINT_ACTIVE; +} + +VOID +NTAPI +OHCI_RemoveEndpointFromSchedule(IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_HCD_ED ED; + POHCI_HCD_ED PreviousED; + POHCI_STATIC_ED HeadED; + + DPRINT_OHCI("OHCI_RemoveEndpointFromSchedule \n"); + + ED = OhciEndpoint->HcdED; + HeadED = OhciEndpoint->HeadED; + + if (&HeadED->Link == ED->HcdEDLink.Blink) + { + if (ED->Flags & 0x20) + { + WRITE_REGISTER_ULONG((PULONG)HeadED->pNextED, ED->HwED.NextED); + } + else + { + *HeadED->pNextED = ED->HwED.NextED; + } + } + else + { + PreviousED = CONTAINING_RECORD(ED->HcdEDLink.Blink, + OHCI_HCD_ED, + HcdEDLink); + + PreviousED->HwED.NextED = ED->HwED.NextED; + } + + RemoveEntryList(&ED->HcdEDLink); + + OhciEndpoint->HeadED = NULL; +} + +VOID +NTAPI +OHCI_SetEndpointState(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN ULONG EndpointState) +{ + POHCI_EXTENSION OhciExtension; + POHCI_ENDPOINT OhciEndpoint; + POHCI_HCD_ED ED; + + DPRINT_OHCI("OHCI_SetEndpointState: EndpointState - %x\n", + EndpointState); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + + ED = OhciEndpoint->HcdED; + + switch (EndpointState) + { + case USBPORT_ENDPOINT_PAUSED: + ED->HwED.EndpointControl.sKip = 1; + break; + + case USBPORT_ENDPOINT_ACTIVE: + ED->HwED.EndpointControl.sKip = 0; + OHCI_EnableList(OhciExtension, OhciEndpoint); + break; + + case USBPORT_ENDPOINT_CLOSED: + ED->HwED.EndpointControl.sKip = 1; + ED->Flags |= 0x10; + OHCI_RemoveEndpointFromSchedule(OhciEndpoint); + break; + + default: + ASSERT(FALSE); + break; + } +} + +VOID +NTAPI +OHCI_PollAsyncEndpoint(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint) +{ + POHCI_HCD_ED ED; + ULONG_PTR NextTdPA; + POHCI_HCD_TD NextTD; + POHCI_HCD_TD TD; + PLIST_ENTRY DoneList; + POHCI_TRANSFER OhciTransfer; + UCHAR ConditionCode; + BOOLEAN IsResetOnHalt = FALSE; + + DPRINT_OHCI("OHCI_PollAsyncEndpoint: OhciEndpoint - %p\n", OhciEndpoint); + + ED = OhciEndpoint->HcdED; + NextTdPA = ED->HwED.HeadPointer & 0xFFFFFFF0; // physical pointer to the next TD + + if (!NextTdPA) + { + DPRINT("OHCI_PollAsyncEndpoint: ED - %p\n", ED); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.EndpointControl - %p\n", ED->HwED.EndpointControl.AsULONG); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.TailPointer - %p\n", ED->HwED.TailPointer); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.NextED - %p\n", ED->HwED.NextED); + DbgBreakPoint(); + } + + NextTD = (POHCI_HCD_TD)RegPacket.UsbPortGetMappedVirtualAddress((PVOID)NextTdPA, + OhciExtension, + OhciEndpoint); + + if (ED->HwED.HeadPointer & 1) //Halted FIXME + { + DPRINT("OHCI_PollAsyncEndpoint: ED - %p\n", ED); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.EndpointControl - %p\n", ED->HwED.EndpointControl.AsULONG); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.TailPointer - %p\n", ED->HwED.TailPointer); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.NextED - %p\n", ED->HwED.NextED); + + IsResetOnHalt = (ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT) != 0; + DPRINT("OHCI_PollAsyncEndpoint: IsResetOnHalt - %x\n", IsResetOnHalt); + + TD = OhciEndpoint->HcdHeadP; + + while (TRUE) + { + DPRINT("OHCI_PollAsyncEndpoint: TD - %p, NextTD - %p\n", TD, NextTD); + + if (!TD) + { + DPRINT("OHCI_PollAsyncEndpoint: ED - %p\n", ED); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.EndpointControl - %p\n", ED->HwED.EndpointControl.AsULONG); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.TailPointer - %p\n", ED->HwED.TailPointer); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.HeadPointer - %p\n", ED->HwED.HeadPointer); + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.NextED - %p\n", ED->HwED.NextED); + DbgBreakPoint(); + } + + if (TD == NextTD) + { + goto HandleDoneList; + } + + OhciTransfer = TD->OhciTransfer; + ConditionCode = TD->HwTD.gTD.Control.ConditionCode; + + DPRINT("OHCI_PollAsyncEndpoint: TD - %p, ConditionCode - %x\n", + TD, + ConditionCode); + + switch (ConditionCode) + { + case OHCI_TD_CONDITION_NO_ERROR: + TD->Flags |= OHCI_HCD_TD_FLAG_DONE; + InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink); + break; + + case OHCI_TD_CONDITION_NOT_ACCESSED: + TD->Flags |= (OHCI_HCD_TD_FLAG_DONE | 0x10); + InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink); + break; + + case OHCI_TD_CONDITION_DATA_UNDERRUN: + DPRINT1("OHCI_TD_CONDITION_DATA_UNDERRUN. Transfer->Flags - %x\n", + OhciTransfer->Flags); + + if (OhciTransfer->Flags & 1) + { + IsResetOnHalt = 1; + TD->HwTD.gTD.Control.ConditionCode = 0; + + if (TD->Flags & OHCI_HCD_TD_FLAG_CONTROLL) + { + ASSERT(FALSE); + } + else + { + ASSERT(FALSE); + } + + TD->Flags |= OHCI_HCD_TD_FLAG_DONE; + InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink); + break; + } + + /* fall through */ + + default: + TD->Flags |= OHCI_HCD_TD_FLAG_DONE; + InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink); + + ED->HwED.HeadPointer = OhciTransfer->NextTD->PhysicalAddress | + (ED->HwED.HeadPointer & 0xF); + + NextTD = OhciTransfer->NextTD; + break; + } + + TD = TD->NextHcdTD; + } + } + + TD = OhciEndpoint->HcdHeadP; + + while (TD != NextTD) + { + TD->Flags |= OHCI_HCD_TD_FLAG_DONE; + InsertTailList(&OhciEndpoint->TDList, &TD->DoneLink); + TD = TD->NextHcdTD; + } + +HandleDoneList: + + TD = NextTD; + OhciEndpoint->HcdHeadP = NextTD; + + DoneList = &OhciEndpoint->TDList; + + while (!IsListEmpty(DoneList)) + { + TD = CONTAINING_RECORD(DoneList->Flink, + OHCI_HCD_TD, + DoneLink); + + RemoveHeadList(DoneList); + + if (TD->Flags & OHCI_HCD_TD_FLAG_DONE && + TD->Flags & OHCI_HCD_TD_FLAG_PROCESSED) + { + OHCI_ProcessDoneTD(OhciExtension, TD, TRUE); + } + } + + if (IsResetOnHalt) + { + ED->HwED.HeadPointer &= ~1; + DPRINT("OHCI_PollAsyncEndpoint: ED->HwED.HeadPointer - %p\n", + ED->HwED.HeadPointer); + } +} + +VOID +NTAPI +OHCI_PollIsoEndpoint(IN POHCI_EXTENSION OhciExtension, + IN POHCI_ENDPOINT OhciEndpoint) +{ + DPRINT1("OHCI_PollAsyncEndpoint: UNIMPLEMENTED. FIXME \n"); + ASSERT(FALSE); +} + +VOID +NTAPI +OHCI_PollEndpoint(IN PVOID ohciExtension, + IN PVOID ohciEndpoint) +{ + POHCI_EXTENSION OhciExtension; + POHCI_ENDPOINT OhciEndpoint; + ULONG TransferType; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + + DPRINT_OHCI("OHCI_PollEndpoint: OhciExtension - %p, Endpoint - %p\n", + OhciExtension, + OhciEndpoint); + + TransferType = OhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + OHCI_PollIsoEndpoint(OhciExtension, OhciEndpoint); + } + else + { + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + OHCI_PollAsyncEndpoint(OhciExtension, OhciEndpoint); + } + } +} + +VOID +NTAPI +OHCI_CheckController(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + OHCI_REG_CONTROL HcControl; + ULONG FmNumber; + USHORT FmDiff; + POHCI_HCCA HcHCCA; + + //DPRINT_OHCI("OHCI_CheckController: ...\n"); + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OperationalRegs = OhciExtension->OperationalRegs; + + if (!OHCI_HardwarePresent(OhciExtension, TRUE)) + { + return; + } + + HcControl.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcControl.AsULONG); + + if (HcControl.HostControllerFunctionalState != OHCI_HC_STATE_OPERATIONAL) + { + return; + } + + FmNumber = READ_REGISTER_ULONG(&OperationalRegs->HcFmNumber); + FmDiff = (USHORT)(FmNumber - OhciExtension->HcdFmNumber); + + if (FmNumber == 0 || FmDiff < 5) + { + return; + } + + HcHCCA = (POHCI_HCCA)OhciExtension->HcResourcesVA; + OhciExtension->HcdFmNumber = FmNumber; + + + if (HcHCCA->Pad1) + { + DPRINT1("OHCI_CheckController: HcHCCA->Pad1 - %x\n", + HcHCCA->Pad1); + + if (HcHCCA->Pad1 == 0xBAD1) + { + HcHCCA->Pad1 = 0xBAD2; + } + else if (HcHCCA->Pad1 == 0xBAD2) + { + HcHCCA->Pad1 = 0xBAD3; + RegPacket.UsbPortInvalidateController(OhciExtension, 1); + } + } + else + { + HcHCCA->Pad1 = 0xBAD1; + } +} + +ULONG +NTAPI +OHCI_Get32BitFrameNumber(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension; + POHCI_HCCA HcHCCA; + ULONG fm; + ULONG hp; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + HcHCCA = (POHCI_HCCA)OhciExtension->HcResourcesVA; + + hp = OhciExtension->FrameHighPart; + fm = HcHCCA->FrameNumber; + + DPRINT_OHCI("OHCI_Get32BitFrameNumber: hp - %x, fm - %p\n", hp, fm); + + return ((fm & 0x7FFF) | hp) + ((fm ^ hp) & 0x8000); +} + +VOID +NTAPI +OHCI_InterruptNextSOF(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension = (POHCI_EXTENSION)ohciExtension; + DPRINT_OHCI("OHCI_InterruptNextSOF: OhciExtension - %p\n", + OhciExtension); + + WRITE_REGISTER_ULONG(&OhciExtension->OperationalRegs->HcInterruptEnable.AsULONG, + 4); +} + +VOID +NTAPI +OHCI_EnableInterrupts(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + DPRINT_OHCI("OHCI_EnableInterrupts: OhciExtension - %p\n", + OhciExtension); + + OperationalRegs = OhciExtension->OperationalRegs; + + /* HcInterruptEnable.MIE - Master Interrupt Enable */ + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + 0x80000000); +} + +VOID +NTAPI +OHCI_DisableInterrupts(IN PVOID ohciExtension) +{ + POHCI_EXTENSION OhciExtension = (POHCI_EXTENSION)ohciExtension; + DPRINT_OHCI("OHCI_DisableInterrupts\n"); + + /* HcInterruptDisable.MIE - disables interrupt generation */ + WRITE_REGISTER_ULONG(&OhciExtension->OperationalRegs->HcInterruptDisable.AsULONG, + 0x80000000); +} + +VOID +NTAPI +OHCI_PollController(IN PVOID ohciExtension) +{ + DPRINT1("OHCI_PollController: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +OHCI_SetEndpointDataToggle(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN ULONG DataToggle) +{ + POHCI_ENDPOINT OhciEndpoint; + POHCI_HCD_ED ED; + + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + + DPRINT_OHCI("OHCI_SetEndpointDataToggle: Endpoint - %p, DataToggle - %x\n", + OhciEndpoint, + DataToggle); + + ED = OhciEndpoint->HcdED; + + if (DataToggle) + { + ED->HwED.HeadPointer |= 2; // toggleCarry + } + else + { + ED->HwED.HeadPointer &= ~2; + } +} + +ULONG +NTAPI +OHCI_GetEndpointStatus(IN PVOID ohciExtension, + IN PVOID ohciEndpoint) +{ + POHCI_ENDPOINT OhciEndpoint; + POHCI_HCD_ED ED; + ULONG EndpointStatus = 0; + + DPRINT_OHCI("OHCI_GetEndpointStatus: ... \n"); + + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + + ED = OhciEndpoint->HcdED; + + if ((ED->HwED.HeadPointer & 1) && // Halted + !(ED->Flags & OHCI_HCD_ED_FLAG_RESET_ON_HALT)) + { + EndpointStatus = 1; + } + + return EndpointStatus; +} + +VOID +NTAPI +OHCI_SetEndpointStatus(IN PVOID ohciExtension, + IN PVOID ohciEndpoint, + IN ULONG EndpointStatus) +{ + POHCI_EXTENSION OhciExtension; + POHCI_ENDPOINT OhciEndpoint; + POHCI_HCD_ED ED; + + OhciExtension = (POHCI_EXTENSION)ohciExtension; + OhciEndpoint = (POHCI_ENDPOINT)ohciEndpoint; + + DPRINT_OHCI("OHCI_SetEndpointStatus: Endpoint - %p, Status - %p\n", + OhciEndpoint, + EndpointStatus); + + if (EndpointStatus) + { + if (EndpointStatus == 1) + { + ASSERT(FALSE); + } + } + else + { + ED = OhciEndpoint->HcdED; + ED->HwED.HeadPointer &= ~1; // ~Halted + + OHCI_EnableList(OhciExtension, OhciEndpoint); + } +} + +VOID +NTAPI +OHCI_ResetController(IN PVOID ohciExtension) +{ + DPRINT1("OHCI_ResetController: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +OHCI_StartSendOnePacket(IN PVOID ohciExtension, + IN PVOID PacketParameters, + IN PVOID Data, + IN PULONG pDataLength, + IN PVOID BufferVA, + IN PVOID BufferPA, + IN ULONG BufferLength, + IN USBD_STATUS * pUSBDStatus) +{ + DPRINT1("OHCI_StartSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +OHCI_EndSendOnePacket(IN PVOID ohciExtension, + IN PVOID PacketParameters, + IN PVOID Data, + IN PULONG pDataLength, + IN PVOID BufferVA, + IN PVOID BufferPA, + IN ULONG BufferLength, + IN USBD_STATUS * pUSBDStatus) +{ + DPRINT1("OHCI_EndSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +OHCI_PassThru(IN PVOID ohciExtension, + IN PVOID passThruParameters, + IN ULONG ParameterLength, + IN PVOID pParameters) +{ + DPRINT1("OHCI_PassThru: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +OHCI_Unload(IN PVOID ohciExtension) +{ +#if DBG + DPRINT1("OHCI_Unload: Not supported\n"); +#endif + return; +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + NTSTATUS Status; + + DPRINT_OHCI("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n", + DriverObject, + RegistryPath); + + RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET)); + + RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_OHCI; + + RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT | + USB_MINIPORT_FLAGS_MEMORY_IO | + 8; + + RegPacket.MiniPortBusBandwidth = 12000; + + RegPacket.MiniPortExtensionSize = sizeof(OHCI_EXTENSION); + RegPacket.MiniPortEndpointSize = sizeof(OHCI_ENDPOINT); + RegPacket.MiniPortTransferSize = sizeof(OHCI_TRANSFER); + RegPacket.MiniPortResourcesSize = sizeof(OHCI_HC_RESOURCES); + + RegPacket.OpenEndpoint = OHCI_OpenEndpoint; + RegPacket.ReopenEndpoint = OHCI_ReopenEndpoint; + RegPacket.QueryEndpointRequirements = OHCI_QueryEndpointRequirements; + RegPacket.CloseEndpoint = OHCI_CloseEndpoint; + RegPacket.StartController = OHCI_StartController; + RegPacket.StopController = OHCI_StopController; + RegPacket.SuspendController = OHCI_SuspendController; + RegPacket.ResumeController = OHCI_ResumeController; + RegPacket.InterruptService = OHCI_InterruptService; + RegPacket.InterruptDpc = OHCI_InterruptDpc; + RegPacket.SubmitTransfer = OHCI_SubmitTransfer; + RegPacket.SubmitIsoTransfer = OHCI_SubmitIsoTransfer; + RegPacket.AbortTransfer = OHCI_AbortTransfer; + RegPacket.GetEndpointState = OHCI_GetEndpointState; + RegPacket.SetEndpointState = OHCI_SetEndpointState; + RegPacket.PollEndpoint = OHCI_PollEndpoint; + RegPacket.CheckController = OHCI_CheckController; + RegPacket.Get32BitFrameNumber = OHCI_Get32BitFrameNumber; + RegPacket.InterruptNextSOF = OHCI_InterruptNextSOF; + RegPacket.EnableInterrupts = OHCI_EnableInterrupts; + RegPacket.DisableInterrupts = OHCI_DisableInterrupts; + RegPacket.PollController = OHCI_PollController; + RegPacket.SetEndpointDataToggle = OHCI_SetEndpointDataToggle; + RegPacket.GetEndpointStatus = OHCI_GetEndpointStatus; + RegPacket.SetEndpointStatus = OHCI_SetEndpointStatus; + RegPacket.ResetController = OHCI_ResetController; + RegPacket.RH_GetRootHubData = OHCI_RH_GetRootHubData; + RegPacket.RH_GetStatus = OHCI_RH_GetStatus; + RegPacket.RH_GetPortStatus = OHCI_RH_GetPortStatus; + RegPacket.RH_GetHubStatus = OHCI_RH_GetHubStatus; + RegPacket.RH_SetFeaturePortReset = OHCI_RH_SetFeaturePortReset; + RegPacket.RH_SetFeaturePortPower = OHCI_RH_SetFeaturePortPower; + RegPacket.RH_SetFeaturePortEnable = OHCI_RH_SetFeaturePortEnable; + RegPacket.RH_SetFeaturePortSuspend = OHCI_RH_SetFeaturePortSuspend; + RegPacket.RH_ClearFeaturePortEnable = OHCI_RH_ClearFeaturePortEnable; + RegPacket.RH_ClearFeaturePortPower = OHCI_RH_ClearFeaturePortPower; + RegPacket.RH_ClearFeaturePortSuspend = OHCI_RH_ClearFeaturePortSuspend; + RegPacket.RH_ClearFeaturePortEnableChange = OHCI_RH_ClearFeaturePortEnableChange; + RegPacket.RH_ClearFeaturePortConnectChange = OHCI_RH_ClearFeaturePortConnectChange; + RegPacket.RH_ClearFeaturePortResetChange = OHCI_RH_ClearFeaturePortResetChange; + RegPacket.RH_ClearFeaturePortSuspendChange = OHCI_RH_ClearFeaturePortSuspendChange; + RegPacket.RH_ClearFeaturePortOvercurrentChange = OHCI_RH_ClearFeaturePortOvercurrentChange; + RegPacket.RH_DisableIrq = OHCI_RH_DisableIrq; + RegPacket.RH_EnableIrq = OHCI_RH_EnableIrq; + RegPacket.StartSendOnePacket = OHCI_StartSendOnePacket; + RegPacket.EndSendOnePacket = OHCI_EndSendOnePacket; + RegPacket.PassThru = OHCI_PassThru; + RegPacket.FlushInterrupts = OHCI_Unload; + + DriverObject->DriverUnload = (PDRIVER_UNLOAD)OHCI_Unload; + + Status = USBPORT_RegisterUSBPortDriver(DriverObject, 100, &RegPacket); + + DPRINT_OHCI("DriverEntry: USBPORT_RegisterUSBPortDriver return Status - %x\n", + Status); + + return Status; +} diff --git a/reactos/drivers/usb/usbohci_new/usbohci.h b/reactos/drivers/usb/usbohci_new/usbohci.h new file mode 100644 index 00000000000..63359a0842f --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/usbohci.h @@ -0,0 +1,240 @@ +#ifndef USBOHCI_H__ +#define USBOHCI_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "..\usbmport.h" +#include "hardware.h" + +extern USBPORT_REGISTRATION_PACKET RegPacket; + +#define OHCI_HCD_ED_FLAG_RESET_ON_HALT 0x00000008 + +#define OHCI_HCD_TD_FLAG_ALLOCATED 0x00000001 +#define OHCI_HCD_TD_FLAG_PROCESSED 0x00000002 +#define OHCI_HCD_TD_FLAG_CONTROLL 0x00000004 +#define OHCI_HCD_TD_FLAG_DONE 0x00000008 + +typedef struct _OHCI_TRANSFER *POHCI_TRANSFER; + +typedef union _OHCI_HW_TRANSFER_DESCRIPTOR { + struct { + OHCI_TRANSFER_DESCRIPTOR gTD; // must be aligned to a 16-byte boundary + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + ULONG Padded[2]; + }; + struct { + OHCI_ISO_TRANSFER_DESCRIPTOR iTD; // must be aligned to a 32-byte boundary + }; +} OHCI_HW_TRANSFER_DESCRIPTOR, *POHCI_HW_TRANSFER_DESCRIPTOR; + +C_ASSERT(sizeof(OHCI_HW_TRANSFER_DESCRIPTOR) == 32); + +typedef struct _OHCI_HCD_TD { + // Hardware part + OHCI_HW_TRANSFER_DESCRIPTOR HwTD; // must be aligned to a 32-byte boundary + // Software part + ULONG_PTR PhysicalAddress; + ULONG Flags; + POHCI_TRANSFER OhciTransfer; + struct _OHCI_HCD_TD * NextHcdTD; + ULONG TransferLen; + LIST_ENTRY DoneLink; + ULONG Pad[1]; +} OHCI_HCD_TD, *POHCI_HCD_TD; + +C_ASSERT(sizeof(OHCI_HCD_TD) == 0x40); + +typedef struct _OHCI_HCD_ED { + // Hardware part + OHCI_ENDPOINT_DESCRIPTOR HwED; // must be aligned to a 16-byte boundary + // Software part + ULONG_PTR PhysicalAddress; + ULONG Flags; + LIST_ENTRY HcdEDLink; + ULONG Pad[8]; +} OHCI_HCD_ED, *POHCI_HCD_ED; + +C_ASSERT(sizeof(OHCI_HCD_ED) == 0x40); + +typedef struct _OHCI_STATIC_ED { + // Software only part + POHCI_ENDPOINT_DESCRIPTOR HwED; + ULONG_PTR PhysicalAddress; + UCHAR HeadIndex; + UCHAR Reserved[3]; + LIST_ENTRY Link; + ULONG Type; + PULONG pNextED; + ULONG HccaIndex; +} OHCI_STATIC_ED, *POHCI_STATIC_ED; + +typedef struct _OHCI_HC_RESOURCES { + OHCI_HCCA HcHCCA; // +0x000 (256 byte align) + OHCI_ENDPOINT_DESCRIPTOR InterrruptHeadED[63]; // +0x100 (16 byte align) + OHCI_ENDPOINT_DESCRIPTOR ControlHeadED; // +0x4F0 (16 byte align) + OHCI_ENDPOINT_DESCRIPTOR BulkHeadED; // +0x500 (16 byte align) +} OHCI_HC_RESOURCES, *POHCI_HC_RESOURCES; + +typedef struct _OHCI_ENDPOINT { + ULONG Reserved; + USBPORT_ENDPOINT_PROPERTIES EndpointProperties; + POHCI_STATIC_ED HeadED; + POHCI_HCD_TD FirstTD; + POHCI_HCD_ED HcdED; + ULONG MaxTransferDescriptors; // TdCount + POHCI_HCD_TD HcdHeadP; + POHCI_HCD_TD HcdTailP; + LIST_ENTRY TDList; +} OHCI_ENDPOINT, *POHCI_ENDPOINT; + +typedef struct _OHCI_TRANSFER { + ULONG Reserved; + ULONG TransferLen; + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + ULONG PendingTDs; + ULONG Flags; + USBD_STATUS USBDStatus; + POHCI_ENDPOINT OhciEndpoint; + POHCI_HCD_TD NextTD; +} OHCI_TRANSFER, *POHCI_TRANSFER; + +typedef struct _OHCI_EXTENSION { + ULONG Reserved; + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + OHCI_REG_FRAME_INTERVAL FrameInterval; + ULONG FrameHighPart; + ULONG HcdFmNumber; + ULONG HcResourcesVA; + ULONG HcResourcesPA; + PVOID ScheduleStartVA; + PVOID ScheduleStartPA; + OHCI_STATIC_ED IntStaticED[63]; + OHCI_STATIC_ED ControlStaticED; // [64-1] ED_CONTROL + OHCI_STATIC_ED BulkStaticED; // [65-1] ED_BULK +} OHCI_EXTENSION, *POHCI_EXTENSION; + +/* roothub.c */ + +VOID +NTAPI +OHCI_RH_GetRootHubData( + IN PVOID ohciExtension, + IN PVOID rootHubData); + +MPSTATUS +NTAPI +OHCI_RH_GetStatus( + IN PVOID ohciExtension, + IN PUSHORT Status); + +MPSTATUS +NTAPI +OHCI_RH_GetPortStatus( + IN PVOID ohciExtension, + IN USHORT Port, + IN PULONG PortStatus); + +MPSTATUS +NTAPI +OHCI_RH_GetHubStatus( + IN PVOID ohciExtension, + IN PULONG HubStatus); + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortReset( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortPower( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortEnable( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_SetFeaturePortSuspend( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortEnable( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortPower( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortSuspend( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortEnableChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortConnectChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortResetChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortSuspendChange( + IN PVOID ohciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +OHCI_RH_ClearFeaturePortOvercurrentChange( + IN PVOID ohciExtension, + IN USHORT Port); + +VOID +NTAPI +OHCI_RH_DisableIrq( + IN PVOID ohciExtension); + +VOID +NTAPI +OHCI_RH_EnableIrq( + IN PVOID ohciExtension); + +/* usbohci.c */ + +NTSTATUS +NTAPI +USBPORT_RegisterUSBPortDriver( + IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PVOID RegistrationPacket); + +#endif /* USBOHCI_H__ */ diff --git a/reactos/drivers/usb/usbohci_new/usbohci.rc b/reactos/drivers/usb/usbohci_new/usbohci.rc new file mode 100644 index 00000000000..41799623bbd --- /dev/null +++ b/reactos/drivers/usb/usbohci_new/usbohci.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB OHCI miniport driver" +#define REACTOS_STR_INTERNAL_NAME "usbohci" +#define REACTOS_STR_ORIGINAL_FILENAME "usbohci.sys" +#include 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..8443325c99b --- /dev/null +++ b/reactos/drivers/usb/usbport/debug.c @@ -0,0 +1,250 @@ +#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, + IN ULONG Arg1, + IN ULONG Arg2, + IN ULONG Arg3, + IN ULONG Arg4, + IN ULONG Arg5, + IN ULONG Arg6) +{ + DPRINT("USBPORT_DbgPrint: UNIMPLEMENTED. FIXME. \n"); + return Level; +} + +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(...); + ASSERT(FALSE); +} + +ULONG +NTAPI +USBPORT_LogEntry(IN PVOID BusContext, + IN PVOID DriverTag, + IN PVOID EnumTag, + IN ULONG P1, + IN ULONG P2, + IN ULONG P3) +{ + DPRINT_MINIPORT("USBPORT_LogEntry: BusContext - %p, EnumTag - %p, P1 - %p, P2 - %p, P3 - %p\n", + BusContext, + EnumTag, + P1, + P2, + P3); + + return (ULONG)BusContext; +} + +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) + { + 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) + { + 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); + + if (!Descriptor) + { + return; + } + + for (ix = 0; ix < iDescriptor->bNumEndpoints; ix++) + { + 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); +} \ No newline at end of file diff --git a/reactos/drivers/usb/usbport/device.c b/reactos/drivers/usb/usbport/device.c new file mode 100644 index 00000000000..b79c48f8be6 --- /dev/null +++ b/reactos/drivers/usb/usbport/device.c @@ -0,0 +1,1873 @@ +#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 = (PURB)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 = (PVOID)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._BM.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); + ExFreePool(Urb); + } + 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 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) + { + ix = iDescriptor->bNumEndpoints; + + do + { + 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); + --ix; + } + while (ix); + } + + 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 pAlternate) +{ + PUSB_CONFIGURATION_DESCRIPTOR TmpDescriptor; + PUSB_INTERFACE_DESCRIPTOR iDescriptor; + PUSB_INTERFACE_DESCRIPTOR OutDescriptor = NULL; + ULONG_PTR Descriptor = (ULONG_PTR)ConfigDescriptor; + ULONG EndDescriptors; + ULONG ix; + + DPRINT("USBPORT_ParseConfigurationDescriptor ... \n"); + + if (pAlternate) + *pAlternate = 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; + + if (Descriptor < EndDescriptors) + { + do + { + if (iDescriptor->bInterfaceNumber != InterfaceNumber) + break; + + if (iDescriptor->bAlternateSetting == Alternate) + OutDescriptor = iDescriptor; + + Descriptor = (ULONG_PTR)iDescriptor + + USBPORT_GetInterfaceLength(iDescriptor, EndDescriptors); + + iDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Descriptor; + + ++ix; + } + while (Descriptor < EndDescriptors); + + if ((ix > 1) && pAlternate) + *pAlternate = 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 = (PUSBPORT_INTERFACE_HANDLE)ExAllocatePoolWithTag(NonPagedPool, + HandleLength, + USB_PORT_TAG); + + if (!InterfaceHandle) + { + USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES; + goto Exit; + } + + RtlZeroMemory(InterfaceHandle, HandleLength); + + ix = NumInterfaces; + + if (NumInterfaces > 0) + { + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + do + { + PipeHandle->Flags = PIPE_HANDLE_FLAG_CLOSED; + PipeHandle->Endpoint = NULL; + + PipeHandle += 1; + --ix; + } + while (ix); + } + + 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); + + ix = 0; + + if (NumInterfaces) + { + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + do + { + if (Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE) + { + do + { + if (Descriptor->bLength == 0) + break; + else + Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + + Descriptor->bLength); + } + while (Descriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE); + } + + 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; + + MaxPacketSize = (wMaxPacketSize & 0x7FF) * (((wMaxPacketSize >> 11) & 3) + 1); + + InterfaceInfo->Pipes[ix].EndpointAddress = Descriptor->bEndpointAddress; + InterfaceInfo->Pipes[ix].PipeType = Descriptor->bmAttributes & 3; + InterfaceInfo->Pipes[ix].MaximumPacketSize = MaxPacketSize; + InterfaceInfo->Pipes[ix].PipeHandle = (USBD_PIPE_HANDLE)-1; + InterfaceInfo->Pipes[ix].Interval = Descriptor->bInterval; + + ++ix; + + Descriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)Descriptor + + Descriptor->bLength); + + PipeHandle += 1; + } + while (ix < NumInterfaces); + } + + if (USBD_SUCCESS(USBDStatus)) + { + ix = 0; + + if (InterfaceDescriptor->bNumEndpoints) + { + PipeInfo = &InterfaceInfo->Pipes[ix]; + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + while (TRUE) + { + Status = USBPORT_OpenPipe(FdoDevice, + DeviceHandle, + PipeHandle, + &USBDStatus); + + if (!NT_SUCCESS(Status)) + break; + + PipeInfo->PipeHandle = (USBD_PIPE_HANDLE)PipeHandle; + + PipeHandle += 1; + PipeInfo += 1; + + ++ix; + + if (ix >= InterfaceDescriptor->bNumEndpoints) + goto Exit; + } + + USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); + } + } + +Exit: + + if (USBD_SUCCESS(USBDStatus)) + { + InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)InterfaceHandle; + *iHandle = InterfaceHandle; + InterfaceInfo->Length = Length; + } + else + { + if (InterfaceHandle) + { + if (NumInterfaces) + { + DPRINT1("USBPORT_OpenInterface: USBDStatus - %p\n", USBDStatus); + } + + if (IsAllocated) + ExFreePool(InterfaceHandle); + } + } + + 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; + + if (NumEndpoints > 0) + { + PipeHandle = &iHandle->PipeHandle[0]; + + do + { + USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle); + PipeHandle += 1; + --NumEndpoints; + } + while (NumEndpoints > 0); + } + + ExFreePool(iHandle); + } + + ExFreePool(ConfigHandle); + 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; + + if (NumberOfPipes > 0) + { + Pipe = InterfaceInfo->Pipes; + + do + { + 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; + } + while (NumberOfPipes > 0); + } + } + 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: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + DeviceHandle = (PUSBPORT_DEVICE_HANDLE)Urb->UrbHeader.UsbdDeviceHandle; + ConfigDescriptor = Urb->UrbSelectConfiguration.ConfigurationDescriptor; + + DPRINT("USBPORT_SelectConfiguration: ConfigDescriptor %x\n", + ConfigDescriptor); + + if (!ConfigDescriptor) + { + DPRINT1("USBPORT_SelectConfiguration: ConfigDescriptor == NULL!\n"); + 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)) + { + ConfigHandle = (PUSBPORT_CONFIGURATION_HANDLE) + ExAllocatePoolWithTag(NonPagedPool, + ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE), + USB_PORT_TAG); + + if (ConfigHandle) + { + RtlZeroMemory(ConfigHandle, + ConfigDescriptor->wTotalLength + sizeof(USBPORT_CONFIGURATION_HANDLE)); + + InitializeListHead(&ConfigHandle->InterfaceHandleList); + + ConfigHandle->ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)ConfigHandle + + sizeof(USBPORT_CONFIGURATION_HANDLE)); + + 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_SUCCESS(USBDStatus)) + { + if (iNumber <= 0) + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_SUCCESS); + + goto Exit; + } + + InterfaceInfo = &Urb->UrbSelectConfiguration.Interface; + + ix = 0; + + while (TRUE) + { + USBDStatus = USBPORT_InitInterfaceInfo(InterfaceInfo, + ConfigHandle); + + InterfaceHandle = 0; + + 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; + + ++ix; + + if (ix >= iNumber) + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_SUCCESS); + goto Exit; + } + + InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInfo + + InterfaceInfo->Length); + } + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_SET_CONFIG_FAILED); + } + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, + USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR); + } + +Exit: + + if (NT_SUCCESS(Status)) + { + Urb->UrbSelectConfiguration.ConfigurationHandle = ConfigHandle; + DeviceHandle->ConfigHandle = ConfigHandle; + } + else + { + DPRINT1("USBPORT_SelectConfiguration: 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 = (PUSBPORT_DEVICE_EXTENSION)(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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->DeviceHandleSpinLock, &OldIrql); + if (DeviceHandle) + { + HandleList = &FdoExtension->DeviceHandleList; + + if (!IsListEmpty(HandleList)) + { + HandleList = HandleList->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; + + if (!IsListEmpty(&DeviceHandle->PipeHandleList)) + { + PipeHandleList = 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; + + if (!IsListEmpty(HandleList)) + { + HandleList = HandleList->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; + BOOLEAN IsOpenedPipe; + PVOID DeviceDescriptor; + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + SIZE_T TransferedLen; + UCHAR MaxPacketSize; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + NTSTATUS Status; + + DPRINT("USBPORT_CreateDevice: PortStatus - %p, Port - %x\n", + PortStatus, + Port); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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); + + if (NT_SUCCESS(Status)) + { + IsOpenedPipe = TRUE; + } + + if (NT_ERROR(Status)) + { + DPRINT1("USBPORT_CreateDevice: USBPORT_OpenPipe return - %p\n", Status); + + KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + ExFreePool(DeviceHandle); + + 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._BM.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)); + + ExFreePool(DeviceDescriptor); + + if ((TransferedLen == 8) && !NT_SUCCESS(Status)) + { + Status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(Status) && (TransferedLen >= 8)) + { + 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 = (PUSB_DEVICE_HANDLE)DeviceHandle; + + KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + return Status; + } + } + } + + DPRINT1("USBPORT_CreateDevice: ERROR!!! TransferedLen - %x, Status - %p\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); + + ExFreePool(DeviceHandle); + + return Status; +} + +ULONG +NTAPI +USBPORT_AllocateUsbAddress(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + ULONG BitMap; + ULONG Bit; + ULONG ix = 0; + + DPRINT("USBPORT_AllocateUsbAddress \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + while (TRUE) + { + BitMap = 1; + Bit = 0; + + do + { + if (!(FdoExtension->UsbAddressBitMap[ix] & BitMap)) + { + FdoExtension->UsbAddressBitMap[ix] |= BitMap; + return 32 * ix + Bit; + } + + BitMap *= 2; + ++Bit; + } + while (Bit < 32); + + ++ix; + + if (ix < 4) + continue; + + break; + } + + return 0; +} + +VOID +NTAPI +USBPORT_FreeUsbAddress(IN PDEVICE_OBJECT FdoDevice, + IN USHORT DeviceAddress) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + ULONG ix = 0; + ULONG BitMap; + ULONG Bit; + USHORT CurrentAddress; + + DPRINT("USBPORT_FreeUsbAddress: DeviceAddress - %x\n", DeviceAddress); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + while (TRUE) + { + BitMap = 1; + Bit = 0; + CurrentAddress = 32 * ix; + + do + { + if (CurrentAddress == DeviceAddress) + { + BitMap = ~BitMap; + FdoExtension->UsbAddressBitMap[ix] &= BitMap; + return; + } + + BitMap *= 2; + + ++Bit; + ++CurrentAddress; + } + while (Bit < 32); + + ++ix; + + if (ix < 4) + continue; + + break; + } +} + +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 = (PUSBPORT_DEVICE_EXTENSION)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 == 1); + + 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.B = 0x80; + 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); + + if (!IsListEmpty(&ConfigurationHandle->InterfaceHandleList)) + { + 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; + ULONG NumInterfaces; + USHORT Length; + ULONG ix; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_HandleSelectInterface: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + ConfigurationHandle = (PUSBPORT_CONFIGURATION_HANDLE)Urb->UrbSelectInterface.ConfigurationHandle; + + Interface = (PUSBD_INTERFACE_INFORMATION)&Urb->UrbSelectInterface.Interface; + + Length = Interface->Length + sizeof(USBD_PIPE_INFORMATION); + + if (Length != Urb->UrbHeader.Length) + Urb->UrbHeader.Length = Length; + + USBDStatus = USBPORT_InitInterfaceInfo(Interface, ConfigurationHandle); + + if (USBDStatus) + { + Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1; + return USBPORT_USBDStatusToNtStatus(Urb, USBDStatus); + } + + DeviceHandle = (PUSBPORT_DEVICE_HANDLE)Urb->UrbHeader.UsbdDeviceHandle; + + InterfaceHandle = USBPORT_GetInterfaceHandle(ConfigurationHandle, + Interface->InterfaceNumber); + + if (InterfaceHandle) + { + RemoveEntryList(&InterfaceHandle->InterfaceLink); + + + if (InterfaceHandle->InterfaceDescriptor.bNumEndpoints) + { + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + ix = 0; + + do + { + USBPORT_ClosePipe(DeviceHandle, FdoDevice, PipeHandle); + NumInterfaces = InterfaceHandle->InterfaceDescriptor.bNumEndpoints; + ++ix; + PipeHandle += 1; + } + while (ix < NumInterfaces); + } + } + + iHandle = 0; + + USBDStatus = USBPORT_OpenInterface(Urb, + DeviceHandle, + FdoDevice, + ConfigurationHandle, + Interface, + &iHandle, + 1); + + if (USBDStatus) + { + Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)-1; + } + else + { + if (InterfaceHandle) + ExFreePool(InterfaceHandle); + + Interface->InterfaceHandle = (USBD_INTERFACE_HANDLE)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 = (PUSBPORT_DEVICE_EXTENSION)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)) + { + ExFreePool(DeviceHandle); + } + + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeWaitForSingleObject(&FdoExtension->DeviceSemaphore, + Executive, + KernelMode, + FALSE, + NULL); + + if (!USBPORT_ValidateDeviceHandle(FdoDevice, OldDeviceHandle)) + { + KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + + ASSERT(FALSE); + return STATUS_DEVICE_NOT_CONNECTED; + } + + if (!USBPORT_ValidateDeviceHandle(FdoDevice, NewDeviceHandle)) + { + KeReleaseSemaphore(&FdoExtension->DeviceSemaphore, + LOW_REALTIME_PRIORITY, + 1, + FALSE); + ASSERT(FALSE); + return STATUS_DEVICE_NOT_CONNECTED; + } + + USBPORT_RemoveDeviceHandle(FdoDevice, OldDeviceHandle); + USBPORT_AbortTransfers(FdoDevice, OldDeviceHandle); + + //DPRINT1("USBPORT_RestoreDevice: DeviceHandleLock - %x\n", OldDeviceHandle->DeviceHandleLock); + while (InterlockedDecrement(&OldDeviceHandle->DeviceHandleLock) >= 0) + { + InterlockedIncrement(&OldDeviceHandle->DeviceHandleLock); + USBPORT_Wait(FdoDevice, 100); + } + //DPRINT1("USBPORT_RestoreDevice: DeviceHandleLock ok\n"); + + 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.B = 0; + 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; + + if (!IsListEmpty(&NewDeviceHandle->ConfigHandle->InterfaceHandleList)) + { + 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._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket.bmRequestType._BM.Type = BMREQUEST_STANDARD; + SetupPacket.bmRequestType._BM.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, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT))); + + Packet->SetEndpointDataToggle(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 0); + + Packet->SetEndpointStatus(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 0); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + else + { + MiniportCloseEndpoint(FdoDevice, Endpoint); + + RtlZeroMemory((PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + Packet->MiniPortEndpointSize); + + RtlZeroMemory((PVOID)Endpoint->EndpointProperties.BufferVA, + Endpoint->EndpointProperties.BufferLength); + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt, + &Endpoint->EndpointProperties, + (PULONG)&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) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->SetEndpointState(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + USBPORT_ENDPOINT_ACTIVE); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + } + } + } + } + + USBPORT_AddPipeHandle(OldDeviceHandle, &OldDeviceHandle->PipeHandle); + } + else + { + ASSERT(FALSE); + 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); + + ExFreePool(OldDeviceHandle); + + 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; + } + + ix = 0; + + if (TtCount) + { + do + { + Status = USBPORT_InitializeTT(FdoDevice, HubDeviceHandle, ix + 1); + + if (!NT_SUCCESS(Status)) + break; + + ++ix; + } + while (ix < TtCount); + } + + 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..3a8478de747 --- /dev/null +++ b/reactos/drivers/usb/usbport/endpoint.c @@ -0,0 +1,1581 @@ +#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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + EndpointList = FdoExtension->EndpointList.Flink; + + if (!IsListEmpty(&FdoExtension->EndpointList)) + { + 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"); + + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, &Endpoint->EndpointStateOldIrql); + + if (Endpoint->StateLast != Endpoint->StateNext) + { + State = USBPORT_ENDPOINT_UNKNOWN; + } + else + { + State = Endpoint->StateLast; + } + + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, Endpoint->EndpointStateOldIrql); + + 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 = (PUSBPORT_DEVICE_EXTENSION)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, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 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_CLOSED) + { + 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; + BOOLEAN Result; + PUSBPORT_PIPE_HANDLE CurrentHandle; + + //DPRINT("USBPORT_ValidatePipeHandle: DeviceHandle - %p, PipeHandle - %p\n", + // DeviceHandle, + // PipeHandle); + + HandleList = &DeviceHandle->PipeHandleList; + + Result = FALSE; + + if (!IsListEmpty(HandleList)) + HandleList = HandleList->Flink; + + if (HandleList != &DeviceHandle->PipeHandleList) + { + while (TRUE) + { + CurrentHandle = CONTAINING_RECORD(HandleList, + USBPORT_PIPE_HANDLE, + PipeLink); + + HandleList = HandleList->Flink; + + if (CurrentHandle == PipeHandle) + break; + + if (HandleList == &DeviceHandle->PipeHandleList) + return Result; + } + + Result = TRUE; + } + + return Result; +} + +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 = (PUSBPORT_DEVICE_EXTENSION)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); + } + + ExFreePool(Endpoint); + + 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 = (PUSBPORT_DEVICE_EXTENSION)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, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_RHDEVICE_EXTENSION)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; + + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, &Endpoint->EndpointStateOldIrql); + if (Endpoint->StateLast != Endpoint->StateNext) + IsReady = FALSE; + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, Endpoint->EndpointStateOldIrql); + + 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_CLOSED); + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Endpoint->Flags &= ~ENDPOINT_FLAG_CLOSED; + + MpStatus = Packet->OpenEndpoint(FdoExtension->MiniPortExt, + &Endpoint->EndpointProperties, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT))); + + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_HANDLE)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; // HighSpeedInterval + 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: // 0x00 + 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: // 0x01 + 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: // 0x02 + EndpointProperties->TransferType = USBPORT_TRANSFER_TYPE_BULK; + EndpointProperties->MaxTransferSize = 0x10000; + break; + + case USB_ENDPOINT_TYPE_INTERRUPT: // 0x03 + 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; + } + + //EndpointProperties->Direction = ~EndpointDescriptor->bEndpointAddress >> 7; + Direction = ~EndpointDescriptor->bEndpointAddress; + Direction >>= 7; + 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 = (PUSBPORT_RHDEVICE_EXTENSION)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, + (PULONG)&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 = 2; + 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); + } + } + + ExFreePool(Endpoint); + } + + DPRINT1("USBPORT_OpenPipe: Status - %p\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; + KIRQL OldIrql; + NTSTATUS Status; + + DPRINT("USBPORT_ReopenPipe ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + while (TRUE) + { + if (!InterlockedIncrement(&Endpoint->LockCounter)) + break; + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql); + + Packet->SetEndpointState(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + USBPORT_ENDPOINT_CLOSED); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql); + + USBPORT_Wait(FdoDevice, 2); + + MiniportCloseEndpoint(FdoDevice, Endpoint); + + RtlZeroMemory((PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + Packet->MiniPortEndpointSize); + + if (Endpoint->HeaderBuffer) + { + USBPORT_FreeCommonBuffer(FdoDevice, Endpoint->HeaderBuffer); + Endpoint->HeaderBuffer = 0; + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql); + + Packet->QueryEndpointRequirements(FdoExtension->MiniPortExt, + &Endpoint->EndpointProperties, + (PULONG)&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); + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, &OldIrql); + + if (Endpoint->StateLast == USBPORT_ENDPOINT_ACTIVE) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &MiniportOldIrql); + + Packet->SetEndpointState(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + USBPORT_ENDPOINT_ACTIVE); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, MiniportOldIrql); + } + + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, OldIrql); + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->EndpointClosedSpinLock, &OldIrql); + ClosedList = &FdoExtension->EndpointClosedList; + + while (TRUE) + { + if (IsListEmpty(ClosedList)) + break; + + 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 = (PUSBPORT_DEVICE_EXTENSION)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_NOT_HANDLED) + { + 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; + + if (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_NOT_HANDLED) + { + 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 = (PUSBPORT_DEVICE_EXTENSION)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, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 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 = {{0, 0}}; + UCHAR CF; + MPSTATUS MpStatus; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_DmaEndpointActive \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + Entry = Endpoint->TransferList.Flink; + + if (Entry != &Endpoint->TransferList) + { + while (Entry && Entry != &Endpoint->TransferList) + { + Transfer = CONTAINING_RECORD(Entry, + USBPORT_TRANSFER, + TransferLink); + + if (Transfer->Flags & 0x800) + { + USBPORT_QueueDoneTransfer(Transfer, USBD_STATUS_SUCCESS); + return USBPORT_ENDPOINT_ACTIVE; + } + + 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, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + &Transfer->TransferParameters, + Transfer->MiniportTransfer, + NULL);//&Transfer->IsoTransferParameters); + } + else + { + MpStatus = Packet->SubmitTransfer(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + &Transfer->TransferParameters, + Transfer->MiniportTransfer, + &Transfer->SgList); + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (MpStatus) + { + if ((MpStatus != 1) && 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); + + CF = 0; + TimeOut.QuadPart = 10000 * Transfer->TimeOut; + + if (TimeOut.LowPart > (0xFFFFFFFF - Transfer->Time.LowPart)) + { + CF = 1; + } + + Transfer->Time.LowPart += TimeOut.LowPart; + Transfer->Time.HighPart += (TimeOut.HighPart + CF); + } + + 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 PipeState; + ULONG EndpointState; + BOOLEAN IsPaused = FALSE; + + DPRINT_CORE("USBPORT_DmaEndpointWorker ... \n"); + + FdoDevice = Endpoint->FdoDevice; + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + PipeState = USBPORT_GetEndpointState(Endpoint); + + if (PipeState == USBPORT_ENDPOINT_PAUSED) + { + EndpointState = USBPORT_DmaEndpointPaused(FdoDevice, Endpoint); + } + else if (PipeState == USBPORT_ENDPOINT_ACTIVE) + { + EndpointState = USBPORT_DmaEndpointActive(FdoDevice, Endpoint); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + USBPORT_FlushCancelList(Endpoint); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (EndpointState == PipeState) + { + 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 Flag) +{ + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + KIRQL OldIrql; + ULONG EndpointState; + + DPRINT_CORE("USBPORT_EndpointWorker: Endpoint - %p, Flag - %x\n", + Endpoint, + Flag); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (Flag == FALSE) + { + if (InterlockedIncrement(&Endpoint->LockCounter)) + { + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: LockCounter > 0\n"); + return TRUE; + } + } + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (USBPORT_GetEndpointState(Endpoint) == USBPORT_ENDPOINT_NOT_HANDLED) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_NOT_HANDLED. return FALSE\n"); + return FALSE; + } + + if ((Endpoint->Flags & (ENDPOINT_FLAG_ROOTHUB_EP0 | ENDPOINT_FLAG_NUKE)) == 0) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->PollEndpoint(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT))); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + + EndpointState = USBPORT_GetEndpointState(Endpoint); + + if (EndpointState == USBPORT_ENDPOINT_CLOSED) + { + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, &Endpoint->EndpointStateOldIrql); + Endpoint->StateLast = USBPORT_ENDPOINT_NOT_HANDLED; + Endpoint->StateNext = USBPORT_ENDPOINT_NOT_HANDLED; + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, Endpoint->EndpointStateOldIrql); + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + + ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList, + &Endpoint->CloseLink, + &FdoExtension->EndpointClosedSpinLock); + + KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); + + InterlockedDecrement(&Endpoint->LockCounter); + DPRINT_CORE("USBPORT_EndpointWorker: State == USBPORT_ENDPOINT_CLOSED. return FALSE\n"); + return FALSE; + } + + if (!IsListEmpty(&Endpoint->PendingTransferList) || + !IsListEmpty(&Endpoint->TransferList) || + !IsListEmpty(&Endpoint->CancelList)) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + EndpointState = USBPORT_GetEndpointState(Endpoint); + + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, &Endpoint->EndpointStateOldIrql); + if (EndpointState == Endpoint->StateNext) + { + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, Endpoint->EndpointStateOldIrql); + + 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; + } + + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, Endpoint->EndpointStateOldIrql); + InterlockedDecrement(&Endpoint->LockCounter); + + DPRINT_CORE("USBPORT_EndpointWorker: return TRUE\n"); + return TRUE; + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + 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..da8a2ffd69c --- /dev/null +++ b/reactos/drivers/usb/usbport/iface.c @@ -0,0 +1,916 @@ +#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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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; + NTSTATUS Status; + + DPRINT("USBHI_GetUsbDescriptors ...\n"); + + PdoDevice = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + + if (DeviceDescBuffer && *DeviceDescBufferLen) + { + if (*DeviceDescBufferLen > sizeof(USB_DEVICE_DESCRIPTOR)) + *DeviceDescBufferLen = sizeof(USB_DEVICE_DESCRIPTOR); + + RtlCopyMemory(DeviceDescBuffer, + &(((PUSBPORT_DEVICE_HANDLE)UsbdDeviceHandle)->DeviceDescriptor), + *DeviceDescBufferLen); + } + + Status = USBPORT_GetUsbDescriptor((PUSBPORT_DEVICE_HANDLE)UsbdDeviceHandle, + 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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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; + ULONG jx; + + DPRINT("USBHI_QueryDeviceInformation: ... \n"); + + *LenDataReturned = 0; + + if (DeviceInfoBufferLen < (2 * sizeof(ULONG))) + { + return STATUS_BUFFER_TOO_SMALL; + } + + DeviceInfo = (PUSB_DEVICE_INFORMATION_0)DeviceInfoBuffer; + + if (DeviceInfo->InformationLevel > 0) + { + return STATUS_NOT_SUPPORTED; + } + + DeviceHandle = (PUSBPORT_DEVICE_HANDLE)UsbdDeviceHandle; + ConfigHandle = DeviceHandle->ConfigHandle; + + if (ConfigHandle) + { + InterfaceEntry = ConfigHandle->InterfaceHandleList.Flink; + + if (!IsListEmpty(&ConfigHandle->InterfaceHandleList)) + { + while (InterfaceEntry) + { + if (InterfaceEntry == &ConfigHandle->InterfaceHandleList) + break; + + 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 = 2 * sizeof(ULONG); + + 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 >= 0) + { + 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 = NULL; + + if (!IsListEmpty(&ConfigHandle->InterfaceHandleList)) + { + InterfaceEntry = ConfigHandle->InterfaceHandleList.Flink; + } + + jx = 0; + + while (InterfaceEntry && InterfaceEntry != &ConfigHandle->InterfaceHandleList) + { + ix = 0; + + InterfaceHandle = CONTAINING_RECORD(InterfaceEntry, + USBPORT_INTERFACE_HANDLE, + InterfaceLink); + + if (InterfaceHandle->InterfaceDescriptor.bNumEndpoints > 0) + { + PipeInfo = &DeviceInfo->PipeList[0]; + PipeHandle = &InterfaceHandle->PipeHandle[0]; + + do + { + 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)); + + ++ix; + ++jx; + + PipeInfo += 1; + PipeHandle += 1; + } + while (ix < InterfaceHandle->InterfaceDescriptor.bNumEndpoints); + } + + 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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + InfoBuffer = (PUSB_CONTROLLER_INFORMATION_0)ControllerInfoBuffer; + + *LenDataReturned = 0; + + if (ControllerInfoBufferLen < (2 * sizeof(ULONG))) + { + Status = STATUS_BUFFER_TOO_SMALL; + return Status; + } + + *LenDataReturned = 8; + + 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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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, + (HANDLE)1, + 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; + ULONG PortStatus = 0; + ULONG PortAttrX; + + DPRINT("USBHI_GetExtendedHubInformation: ... \n"); + + PdoDevice = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + HubInfoBuffer = (PUSB_EXTHUB_INFORMATION_0)HubInformationBuffer; + + 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 = 1; ix <= HubInfoBuffer->NumberOfPorts; ++ix) + { + HubInfoBuffer->Port[ix].PhysicalPortNumber = ix; + 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 & 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 = 1; ix <= HubInfoBuffer->NumberOfPorts; ++ix) + { + PortAttrX = 0; + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + 0, + L"PortAttrX", + 128, + &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 = (PDEVICE_OBJECT)BusContext; + + Status = USBPORT_GetSymbolicName(PdoDevice, &HubName); + + if (HubInfoBufferLen < HubName.Length) + { + InfoBuffer = (PUNICODE_STRING)HubInfoBuffer; + InfoBuffer->Length = 0; + } + else + { + RtlCopyMemory(HubInfoBuffer, HubName.Buffer, HubName.Length); + } + + *HubNameActualLen = HubName.Length; + + 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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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_0 Buffer0; + 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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSB_BUS_INFORMATION_LEVEL_0)BusInfoBuffer; + DPRINT1("USBDI_QueryBusInformation: 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 = (PUSB_BUS_INFORMATION_LEVEL_1)BusInfoBuffer; + DPRINT1("USBDI_QueryBusInformation: 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 = (PDEVICE_OBJECT)BusContext; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + return Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2; +} + +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((REFGUID)(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 = (PVOID)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 = (PVOID)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..b60e2afec83 --- /dev/null +++ b/reactos/drivers/usb/usbport/ioctl.c @@ -0,0 +1,369 @@ +#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 = (PUSBPORT_DEVICE_EXTENSION)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; + PUSHORT Buffer; + SIZE_T LengthName; + SIZE_T Length; + PWSTR SourceString; + USHORT Symbol; + + DPRINT("USBPORT_GetSymbolicName: ... \n"); + + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 == 0x005C) // '\' + { + Buffer += 1; + + if (*Buffer == 0x005C) + { + Buffer += 1; + goto Exit; + } + + Symbol = *Buffer; + + do + { + if (Symbol == 0) + { + break; + } + + Buffer += 1; + Symbol = *Buffer; + } + while (*Buffer != 0x005C); + + if (*Buffer == 0x005C) + { + Buffer += 1; + } + +Exit: + Length = (ULONG)Buffer - (ULONG)RootHubName->Buffer; + } + else + { + Length = 0; + } + + RtlCopyMemory(SourceString, + (PVOID)((ULONG)RootHubName->Buffer + Length), + RootHubName->Length - Length); + + RtlInitUnicodeString(DestinationString, (PCWSTR)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; + NTSTATUS Status; + + DPRINT("USBPORT_UserGetRootHubName: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSB_HCD_DRIVERKEY_NAME)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; + + ExFreePool(ControllerName); + } + + 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; + } + + ExFreePool(ControllerName); + + 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_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 Information = 0; + + DPRINT("USBPORT_FdoDeviceControl: Irp - %p\n", Irp); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + ControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode; + + switch (ControlCode) + { + case IOCTL_USB_DIAGNOSTIC_MODE_ON: // 220400 + DPRINT("USBPORT_FdoDeviceControl: IOCTL_USB_DIAGNOSTIC_MODE_ON\n"); + FdoExtension->Flags |= USBPORT_FLAG_DIAGNOSTIC_MODE; + break; + + case IOCTL_USB_DIAGNOSTIC_MODE_OFF: // 0x220404 + DPRINT("USBPORT_FdoDeviceControl: IOCTL_USB_DIAGNOSTIC_MODE_OFF\n"); + FdoExtension->Flags &= ~USBPORT_FLAG_DIAGNOSTIC_MODE; + break; + + case IOCTL_USB_GET_NODE_INFORMATION: // 0x220408 + DPRINT1("USBPORT_FdoDeviceControl: IOCTL_USB_GET_NODE_INFORMATION\n"); + Status = USBPORT_GetUnicodeName(FdoDevice, Irp, &Information); + break; + + case IOCTL_GET_HCD_DRIVERKEY_NAME: // 0x220424 + DPRINT1("USBPORT_FdoDeviceControl: IOCTL_GET_HCD_DRIVERKEY_NAME\n"); + Status = USBPORT_GetUnicodeName(FdoDevice, Irp, &Information); + break; + + case IOCTL_USB_USER_REQUEST: // 0x220438 + 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_FdoScsi(IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp) +{ + DPRINT1("USBPORT_FdoScsi: 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..384f0ac5cd7 --- /dev/null +++ b/reactos/drivers/usb/usbport/pnp.c @@ -0,0 +1,1724 @@ +#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 = (PUSBPORT_RHDEVICE_EXTENSION)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, + (HANDLE)0, + 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 if (DeviceExtension->CommonExtension.IsInterfaceEnabled) + { + // 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 IsEnabled = 0; + + DPRINT("USBPORT_IsSelectiveSuspendEnabled: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + 1, + L"HcDisableSelectiveSuspend", + 52, //FIXME: Length "HcDisableSelectiveSuspend" + 0 + &IsEnabled, + sizeof(IsEnabled)); + + return (IsEnabled == 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_BINARY) + { + *(PUCHAR)EntryContext = *(PUCHAR)ValueData; + } + else 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, 7 * sizeof(RTL_QUERY_REGISTRY_TABLE)); + + *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, + 0, + 0, + 0, + &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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES)); + + Capabilities->Size = 64; + Capabilities->Version = 1; + Capabilities->Address = -1; + Capabilities->UINumber = -1; + + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + swprintf(CharName, L"\\Device\\USBFDO-%d", FdoExtension->FdoNameNumber); + RtlInitUnicodeString(&DeviceName, CharName); + + swprintf(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; + //KIRQL OldIrql; + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + Status = USBPORT_QueryPciBusInterface(FdoDevice); + + 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 |= 4; + + if (MiniportFlags & USB_MINIPORT_FLAGS_WAKE_SUPPORT) + FdoExtension->Flags |= 0x00200000; + + if (MiniportFlags & 0x20) + FdoExtension->Flags = (FdoExtension->Flags & ~USBPORT_FLAG_SELECTIVE_SUSPEND) | + USBPORT_FLAG_BIOS_DISABLE_SS; + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + (PVOID)1, + REG_DWORD, + L"EnIdleEndpointSupport", + &IdleEpSupport, + sizeof(IdleEpSupport)); + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + (PVOID)1, + REG_DWORD, + L"EnIdleEndpointSupportEx", + &IdleEpSupportEx, + sizeof(IdleEpSupportEx)); + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + (PVOID)1, + REG_DWORD, + L"EnSoftRetry", + &SoftRetry, + sizeof(SoftRetry)); + + USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, + FdoExtension->CommonExtension.LowerPdoDevice, + 1, + L"CommonBuffer2GBLimit", + 42, + &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, + 1, + L"TotalBusBandwidth", + 36, + &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; + } + + //KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + MiniPortStatus = Packet->StartController(FdoExtension->MiniPortExt, + UsbPortResources); + //KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (UsbPortResources->LegacySupport) + { + FdoExtension->Flags |= USBPORT_FLAG_LEGACY_SUPPORT; + LegacyBIOS = 1; + } + else + { + LegacyBIOS = 0; + } + + USBPORT_SetRegistryKeyValue(FdoExtension->CommonExtension.LowerPdoDevice, + (HANDLE)0, + 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 + { + USBPORT_MiniportInterrupts(FdoDevice, TRUE); + FdoExtension->MiniPortFlags |= USBPORT_MPFLAG_INTERRUPTS_ENABLED; + } + + FdoExtension->TimerValue = 500; + USBPORT_StartTimer((PVOID)FdoDevice, 500); + + Status = USBPORT_RegisterDeviceInterface(FdoExtension->CommonExtension.LowerPdoDevice, + FdoDevice, + (CONST GUID *)&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 - %p\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 = 0; + 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; + + if (ResourceList->Count > 0) + { + PartialDescriptor = &ResourceList->PartialDescriptors[0]; + + do + { + if (PartialDescriptor->Type == CmResourceTypePort) // 1 + { + if (!PortDescriptor) + PortDescriptor = PartialDescriptor; + } + else if (PartialDescriptor->Type == CmResourceTypeInterrupt) // 2 + { + if (!InterruptDescriptor) + InterruptDescriptor = PartialDescriptor; + } + else if (PartialDescriptor->Type == CmResourceTypeMemory) // 3 + { + if (!MemoryDescriptor) + MemoryDescriptor = PartialDescriptor; + } + ++ix; + PartialDescriptor += 1; + } + while (ix < ResourceList->Count); + } + + 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->TypesResources |= 1; // FIXME const + } + 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->TypesResources |= 4;// FIXME const + } + else + { + Status = STATUS_NONE_MAPPED; + } + } + + if (InterruptDescriptor && NT_SUCCESS(Status)) + { + UsbPortResources->TypesResources |= 2; // FIXME const + + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + do + { + swprintf(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 = (PUSBPORT_RHDEVICE_EXTENSION)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_REGISTRATION_PACKET Packet; + PUSBPORT_RESOURCES UsbPortResources; + PIO_STACK_LOCATION IoStack; + UCHAR Minor; + KEVENT Event; + NTSTATUS Status; + DEVICE_RELATION_TYPE RelationType; + PDEVICE_RELATIONS DeviceRelations; + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + UsbPortResources = (PUSBPORT_RESOURCES)&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: // 0 + DPRINT("IRP_MN_START_DEVICE\n"); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBPORT_FdoStartCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + Status = IoCallDriver(FdoExtension->CommonExtension.LowerDevice, + Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Suspended, + KernelMode, + FALSE, + NULL); + + Status = Irp->IoStatus.Status; + } + + if (NT_SUCCESS(Status)) + { + Status = USBPORT_ParseResources(FdoDevice, + Irp, + UsbPortResources); + + if (NT_SUCCESS(Status)) + { + Status = USBPORT_StartDevice(FdoDevice, UsbPortResources); + + if (NT_SUCCESS(Status)) + { + FdoExtension->CommonExtension.PnpStateFlags = (FdoExtension->CommonExtension.PnpStateFlags & ~1) | 2; + FdoExtension->CommonExtension.DevicePowerState = PowerDeviceD0; + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + USBPORT_AddUSB2Fdo(FdoDevice); + } + else + { + USBPORT_AddUSB1Fdo(FdoDevice); + } + } + else + { + FdoExtension->CommonExtension.PnpStateFlags |= 8; + } + } + else + { + FdoExtension->CommonExtension.PnpStateFlags |= 8; + } + } + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + + case IRP_MN_QUERY_REMOVE_DEVICE: // 1 + //DPRINT("IRP_MN_QUERY_REMOVE_DEVICE\n"); + DPRINT1("USBPORT_FdoPnP: IRP_MN_QUERY_REMOVE_DEVICE UNIMPLEMENTED. FIXME. \n"); + break; + + case IRP_MN_REMOVE_DEVICE: // 2 + //DPRINT("IRP_MN_REMOVE_DEVICE\n"); + DPRINT1("USBPORT_FdoPnP: IRP_MN_REMOVE_DEVICE UNIMPLEMENTED. FIXME. \n"); + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: // 3 + DPRINT("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_STOP_DEVICE: // 4 + //DPRINT("IRP_MN_STOP_DEVICE\n"); + DPRINT1("USBPORT_FdoPnP: IRP_MN_STOP_DEVICE UNIMPLEMENTED. FIXME. \n"); + break; + + case IRP_MN_QUERY_STOP_DEVICE: // 5 + DPRINT("IRP_MN_QUERY_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_CANCEL_STOP_DEVICE: // 6 + DPRINT("IRP_MN_CANCEL_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + goto ForwardIrp; + + case IRP_MN_QUERY_DEVICE_RELATIONS: // 7 + 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.Information = 0; + 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)) + { + ExFreePool(DeviceRelations); + 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: // 8 + DPRINT("IRP_MN_QUERY_INTERFACE\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_CAPABILITIES: // 9 + DPRINT("IRP_MN_QUERY_CAPABILITIES\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_RESOURCES: // 10 + DPRINT("IRP_MN_QUERY_RESOURCES\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 11 + DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_DEVICE_TEXT: // 12 + DPRINT("IRP_MN_QUERY_DEVICE_TEXT\n"); + goto ForwardIrp; + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 13 + DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + goto ForwardIrp; + + case IRP_MN_READ_CONFIG: // 15 + DPRINT("IRP_MN_READ_CONFIG\n"); + goto ForwardIrp; + + case IRP_MN_WRITE_CONFIG: // 16 + DPRINT("IRP_MN_WRITE_CONFIG\n"); + goto ForwardIrp; + + case IRP_MN_EJECT: // 17 + DPRINT("IRP_MN_EJECT\n"); + goto ForwardIrp; + + case IRP_MN_SET_LOCK: // 18 + DPRINT("IRP_MN_SET_LOCK\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_ID: // 19 + DPRINT("IRP_MN_QUERY_ID\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_PNP_DEVICE_STATE: // 20 + DPRINT("IRP_MN_QUERY_PNP_DEVICE_STATE\n"); + goto ForwardIrp; + + case IRP_MN_QUERY_BUS_INFORMATION: // 21 + DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n"); + goto ForwardIrp; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: // 22 + DPRINT("IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); + goto ForwardIrp; + + case IRP_MN_SURPRISE_REMOVAL: // 23 + //DPRINT("IRP_MN_SURPRISE_REMOVAL\n"); + DPRINT1("USBPORT_FdoPnP: IRP_MN_SURPRISE_REMOVAL UNIMPLEMENTED. FIXME. \n"); + goto ForwardIrp; + + default: + DPRINT("unknown IRP_MN_???\n"); +ForwardIrp: + // forward irp to next device object + IoSkipCurrentIrpStackLocation(Irp); + break; + } + + return IoCallDriver(FdoExtension->CommonExtension.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 Index = 0; + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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) + { + /* USB 2.0 hub */ + Index += swprintf(&Buffer[Index], + L"USB\\ROOT_HUB20&VID%04x&PID%04x&REV%04x", + VendorID, + DeviceID, + RevisionID) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\ROOT_HUB20&VID%04x&PID%04x", + VendorID, + DeviceID) + 1; + + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB20") + 1; + } + else + { + /* USB 1.1 */ + Index += swprintf(&Buffer[Index], + L"USB\\ROOT_HUB&VID%04x&PID%04x&REV%04x", + VendorID, + DeviceID, + RevisionID) + 1; + + Index += swprintf(&Buffer[Index], + L"USB\\ROOT_HUB&VID%04x&PID%04x", + VendorID, + DeviceID) + 1; + + Index += swprintf(&Buffer[Index], L"USB\\ROOT_HUB") + 1; + } + + Buffer[Index] = UNICODE_NULL; + Index++; + + if (FALSE) // for debug only + { + PWSTR Ptr; + ULONG Length; + ULONG TotalLength = 0; + + Ptr = (PWSTR)Buffer; + DPRINT("Hardware IDs:\n"); + + while (*Ptr) + { + DPRINT(" %S\n", Ptr); + Length = (ULONG)wcslen(Ptr) + 1; + + Ptr += Length; + TotalLength += Length; + } + + DPRINT("TotalLength: %hu\n", TotalLength); + DPRINT("\n"); + } + + Id = ExAllocatePoolWithTag(PagedPool, + Index * sizeof(WCHAR), + USB_PORT_TAG); + + if (!Id) + return 0; + + RtlZeroMemory(Id, Index * sizeof(WCHAR)); + RtlMoveMemory(Id, Buffer, Index * sizeof(WCHAR)); // copy device name + + return Id; +} + +NTSTATUS +NTAPI +USBPORT_PdoPnP(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PDEVICE_OBJECT FdoDevice; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PIO_STACK_LOCATION IoStack; + UCHAR Minor; + NTSTATUS Status; + PPNP_BUS_INFORMATION BusInformation; + PDEVICE_CAPABILITIES DeviceCapabilities; + + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Minor = IoStack->MinorFunction; + + DPRINT("USBPORT_PdoPnP: PdoDevice - %p, Minor - %x\n", PdoDevice, Minor); + + switch (Minor) + { + case IRP_MN_START_DEVICE: // 0 + DPRINT("IRP_MN_START_DEVICE\n"); + + Status = USBPORT_RootHubCreateDevice(FdoDevice, PdoDevice); + if (NT_SUCCESS(Status)) + { + Status = USBPORT_RegisterDeviceInterface(PdoDevice, + PdoDevice, + (CONST GUID *)&GUID_DEVINTERFACE_USB_HUB, + TRUE); + + if (NT_SUCCESS(Status)) + { + PdoExtension->CommonExtension.DevicePowerState = PowerDeviceD0; + PdoExtension->CommonExtension.PnpStateFlags = 2; + } + } + + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: // 1 + //DPRINT("IRP_MN_QUERY_REMOVE_DEVICE\n"); + DPRINT1("USBPORT_PdoPnP: IRP_MN_QUERY_REMOVE_DEVICE UNIMPLEMENTED. FIXME. \n"); + break; + + case IRP_MN_REMOVE_DEVICE: // 2 + //DPRINT("IRP_MN_REMOVE_DEVICE\n"); + DPRINT1("USBPORT_PdoPnP: IRP_MN_REMOVE_DEVICE UNIMPLEMENTED. FIXME. \n"); + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: // 3 + DPRINT("IRP_MN_CANCEL_REMOVE_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_STOP_DEVICE: // 4 + //DPRINT("IRP_MN_STOP_DEVICE\n"); + DPRINT1("USBPORT_PdoPnP: IRP_MN_STOP_DEVICE UNIMPLEMENTED. FIXME. \n"); + break; + + case IRP_MN_QUERY_STOP_DEVICE: // 5 + DPRINT("IRP_MN_QUERY_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_CANCEL_STOP_DEVICE: // 6 + DPRINT("IRP_MN_CANCEL_STOP_DEVICE\n"); + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: // 7 + { + PDEVICE_RELATIONS DeviceRelations; + + DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n"); + if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) + { + Status = Irp->IoStatus.Status; + break; + } + + DeviceRelations = (PDEVICE_RELATIONS)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: // 8 + DPRINT("IRP_MN_QUERY_INTERFACE\n"); + Status = USBPORT_PdoQueryInterface(FdoDevice, PdoDevice, Irp); + break; + + case IRP_MN_QUERY_CAPABILITIES: // 9 + DPRINT("IRP_MN_QUERY_CAPABILITIES\n"); + + DeviceCapabilities = (PDEVICE_CAPABILITIES) + IoStack->Parameters.DeviceCapabilities.Capabilities; + + RtlCopyMemory(DeviceCapabilities, + &PdoExtension->Capabilities, + sizeof(DEVICE_CAPABILITIES)); + + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_RESOURCES: // 10 + //DPRINT("IRP_MN_QUERY_RESOURCES\n"); + DPRINT("USBPORT_PdoPnP: IRP_MN_QUERY_RESOURCES\n"); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: // 11 + DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); + //ASSERT(FALSE); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_QUERY_DEVICE_TEXT: // 12 + DPRINT("IRP_MN_QUERY_DEVICE_TEXT\n"); + //ASSERT(FALSE); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: // 13 + DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); + //ASSERT(FALSE); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_READ_CONFIG: // 15 + DPRINT("IRP_MN_READ_CONFIG\n"); + ASSERT(FALSE); + break; + + case IRP_MN_WRITE_CONFIG: // 16 + DPRINT("IRP_MN_WRITE_CONFIG\n"); + ASSERT(FALSE); + break; + + case IRP_MN_EJECT: // 17 + DPRINT("IRP_MN_EJECT\n"); + ASSERT(FALSE); + break; + + case IRP_MN_SET_LOCK: // 18 + DPRINT("IRP_MN_SET_LOCK\n"); + ASSERT(FALSE); + break; + + case IRP_MN_QUERY_ID: // 19 + { + 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) // 0 + { + PUSBPORT_REGISTRATION_PACKET Packet; + Packet = &FdoExtension->MiniPortInterface->Packet; + + if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2) + { + swprintf(Buffer, L"USB\\ROOT_HUB20"); + } + else + { + swprintf(Buffer, L"USB\\ROOT_HUB"); + } + + Length = (wcslen(Buffer) + 1); + + Id = ExAllocatePoolWithTag(PagedPool, + Length * sizeof(WCHAR), + USB_PORT_TAG); + + if (!Id) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + RtlZeroMemory(Id, Length * sizeof(WCHAR)); + + wcscpy(Id, Buffer); + DPRINT("BusQueryDeviceID - %S, TotalLength - %hu\n", Id, Length); + + Irp->IoStatus.Information = (ULONG_PTR)Id; + break; + } + + if (IdType == BusQueryHardwareIDs) // 1 + { + Id = USBPORT_GetDeviceHwIds(FdoDevice, + FdoExtension->VendorID, + FdoExtension->DeviceID, + FdoExtension->RevisionID); + + Irp->IoStatus.Information = (ULONG_PTR)Id; + break; + } + + if (IdType == BusQueryCompatibleIDs || + IdType == BusQueryInstanceID) + { + Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + break; + } + + Status = Irp->IoStatus.Status; + break; + } + + case IRP_MN_QUERY_PNP_DEVICE_STATE: // 20 + DPRINT("IRP_MN_QUERY_PNP_DEVICE_STATE\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_BUS_INFORMATION: // 21 + DPRINT("IRP_MN_QUERY_BUS_INFORMATION\n"); + + // Allocate buffer for bus information + BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, + sizeof(PNP_BUS_INFORMATION)); + + RtlZeroMemory(BusInformation, sizeof(PNP_BUS_INFORMATION)); + + if (BusInformation) + { + // 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; + } + else + { + // No memory + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: // 22 + DPRINT("IRP_MN_DEVICE_USAGE_NOTIFICATION\n"); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_SURPRISE_REMOVAL: // 23 + //DPRINT("IRP_MN_SURPRISE_REMOVAL\n"); + DPRINT1("USBPORT_PdoPnP: IRP_MN_SURPRISE_REMOVAL UNIMPLEMENTED. FIXME. \n"); + Status = Irp->IoStatus.Status; + break; + + default: + DPRINT("unknown IRP_MN_???\n"); + Status = Irp->IoStatus.Status; + break; + } + + //Irp->IoStatus.Information = Information; + 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..189efc97663 --- /dev/null +++ b/reactos/drivers/usb/usbport/power.c @@ -0,0 +1,695 @@ +#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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + PdoDevice = FdoExtension->RootHubPdo; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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) +{ + KIRQL OldIrql; + + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT("USBPORT_DoSetPowerD0: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->SetPowerD0SpinLock, &OldIrql); + + if (!(FdoExtension->Flags & 0x00000020)) + { + KeReleaseSpinLock(&FdoExtension->SetPowerD0SpinLock, OldIrql); + return; + } + + DPRINT1("USBPORT_DoSetPowerD0: FIXME!\n"); + DbgBreakPoint(); + //ASSERT(FALSE); +} + +VOID +NTAPI +USBPORT_SuspendController(IN PDEVICE_OBJECT FdoDevice) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PUSBPORT_REGISTRATION_PACKET Packet; + KIRQL OldIrql; + + DPRINT1("USBPORT_SuspendController \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + FdoExtension->TimerFlags |= USBPORT_TMFLAG_RH_SUSPENDED; + + USBPORT_FlushController(FdoDevice); + + if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) + { + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql); + FdoExtension->TimerFlags |= USBPORT_TMFLAG_HC_SUSPENDED; + KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, OldIrql); + + if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) + { + FdoExtension->MiniPortFlags |= USBPORT_MPFLAG_SUSPENDED; + + USBPORT_Wait(FdoDevice, 10); + Packet->SuspendController(FdoExtension->MiniPortExt); + } + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + FdoExtension->Flags |= USBPORT_FLAG_HC_SUSPEND; + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } +} + +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 = (PUSBPORT_DEVICE_EXTENSION)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 | 0x00000004); + 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.Reserved1 = 1; + + MpStatus = Packet->StartController(FdoExtension->MiniPortExt, + &FdoExtension->UsbPortResources); + + FdoExtension->UsbPortResources.Reserved1 = 0; + + if (!MpStatus) + { + USBPORT_MiniportInterrupts(FdoDevice, TRUE); + } + + KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &OldIrql); + + FdoExtension->TimerFlags &= ~(USBPORT_TMFLAG_HC_SUSPENDED | + 0x00000004 | + 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 = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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) + { + while ((FdoExtension->Flags & 0x00000020) || + 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 - %p\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_RHDEVICE_EXTENSION PdoExtension; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + KIRQL OldIrql; + + DPRINT("USBPORT_CancelPendingWakeIrp: ... \n"); + + IoReleaseCancelSpinLock(Irp->CancelIrql); + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)PdoExtension->FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql); + 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; + PDRIVER_CANCEL OldCancelRoutine; + NTSTATUS Status; + KIRQL OldIrql; + + DPRINT("USBPORT_PdoPower: Irp - %p\n", Irp); + + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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)) + { + Status = STATUS_NOT_SUPPORTED; + break; + } + + KeAcquireSpinLock(&FdoExtension->PowerWakeSpinLock, &OldIrql); + + OldCancelRoutine = IoSetCancelRoutine(Irp, USBPORT_CancelPendingWakeIrp); + + if (Irp->Cancel && InterlockedExchange((PLONG)OldCancelRoutine, 0)) + { + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - STATUS_CANCELLED\n"); + Status = STATUS_CANCELLED; + break; + } + + if (!PdoExtension->WakeIrp) + { + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - No WakeIrp\n"); + + IoMarkIrpPending(Irp); + PdoExtension->WakeIrp = Irp; + + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + return STATUS_PENDING; + } + + if (InterlockedExchange((PLONG)OldCancelRoutine, 0)) + { + DPRINT("USBPORT_PdoPower: IRP_MN_WAIT_WAKE - STATUS_DEVICE_BUSY\n"); + + KeReleaseSpinLock(&FdoExtension->PowerWakeSpinLock, OldIrql); + PoStartNextPowerIrp(Irp); + Status = STATUS_DEVICE_BUSY; + break; + } + + 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); + } + else + { + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PTIMER_WORK_QUEUE_ITEM)Context; + + FdoDevice = IdleQueueItem->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + PdoDevice = FdoExtension->RootHubPdo; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PUSB_IDLE_CALLBACK_INFO)IoStack->Parameters.DeviceIoControl.Type3InputBuffer; + + if (IdleCallbackInfo && IdleCallbackInfo->IdleCallback) + { + //DbgBreakPoint(); + 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); + + ExFreePool(IdleQueueItem); +} + +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 = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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..8d648ba98bf --- /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); + +Start: + + 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(0xFE, 1, 0, 0, 0); + } + + IrpTable->LinkNextTable = ExAllocatePoolWithTag(NonPagedPool, + sizeof(USBPORT_IRP_TABLE), + USB_PORT_TAG); + + if (IrpTable->LinkNextTable == NULL) + { + KeBugCheckEx(0xFE, 1, 0, 0, 0); + } + + RtlZeroMemory(IrpTable->LinkNextTable, sizeof(USBPORT_IRP_TABLE)); + + IrpTable = IrpTable->LinkNextTable; + + goto Start; +} + +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) + { + ix = 0; + + 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 == 0) + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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(0xFE, 4, (ULONG_PTR)irp, (ULONG_PTR)urbIn, 0); + } + + KeBugCheckEx(0xFE, 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_TRANSFER)Urb->UrbControlTransfer.hca.Reserved8[0]; + Endpoint = Transfer->Endpoint; + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + KeAcquireSpinLock(&FdoExtension->FlushPendingTransferSpinLock, &OldIrql); + + irp = USBPORT_RemovePendingTransferIrp(FdoDevice, Irp); + + if (!irp) + { + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, OldIrql); + return; + } + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + RemoveEntryList(&Transfer->TransferLink); + + Transfer->TransferLink.Flink = NULL; + Transfer->TransferLink.Blink = NULL; + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + 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 = (PUSBPORT_RHDEVICE_EXTENSION)DeviceObject->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + + irp = USBPORT_FindActiveTransferIrp(FdoDevice, Irp); + + if (irp) + { + Urb = URB_FROM_IRP(irp); + Transfer = (PUSBPORT_TRANSFER)Urb->UrbControlTransfer.hca.Reserved8[0]; + Endpoint = Transfer->Endpoint; + + DPRINT_CORE("USBPORT_CancelTransferIrp: irp - %p, Urb - %p, Transfer - %p\n", + irp, + Urb, + Transfer); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + Transfer->Flags |= TRANSFER_FLAG_CANCELED; + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + 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; + } + + if (!IsListEmpty(&Endpoint->PendingTransferList)) + { + 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; + } + } + + if (!IsListEmpty(&Endpoint->TransferList)) + { + 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 = (PUSBPORT_DEVICE_HANDLE)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_TRANSFER Transfer; + PIRP Irp; + KIRQL OldIrql; + PUSBPORT_DEVICE_EXTENSION FdoExtension; + + DPRINT_CORE("USBPORT_FlushCancelList: ... \n"); + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + 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(&OldIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(OldIrql); + + USBPORT_RemoveActiveTransferIrp(FdoDevice, Irp); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + 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); + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + if (InterlockedCompareExchange(&Endpoint->FlushPendingLock, 1, 0)) + { + DPRINT_CORE("USBPORT_FlushPendingTransfers: Endpoint Locked \n"); + return; + } + + while (TRUE) + { + IsMapTransfer = 0; + + KeAcquireSpinLock(&FdoExtension->FlushPendingTransferSpinLock, &OldIrql); + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + if (FdoExtension->Flags & 0x300) + { + IsEnd = TRUE; + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + 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)) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + KeReleaseSpinLock(&FdoExtension->FlushPendingTransferSpinLock, OldIrql); + + IsEnd = TRUE; + goto Worker; + } + + List = Transfer->TransferLink.Flink; + } + } + } + + List = Endpoint->PendingTransferList.Flink; + + if (IsListEmpty(&Endpoint->PendingTransferList) || List == NULL) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + 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) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + 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); + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + 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 = (PUSBPORT_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 = (PUSBPORT_TRANSFER)Urb->UrbControlTransfer.hca.Reserved8[0]; + FdoDevice = Endpoint->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_HANDLE)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 = (PUSBPORT_TRANSFER)Urb->UrbControlTransfer.hca.Reserved8[0]; + Endpoint = Transfer->Endpoint; + + FdoDevice = Endpoint->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_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 = (PUSBPORT_DEVICE_HANDLE)Urb->UrbHeader.UsbdDeviceHandle; + InterlockedDecrement(&DeviceHandle->DeviceHandleLock); + + USBPORT_FlushPendingTransfers(Endpoint); + + DPRINT_URB("... URB TransferBufferLength - %x\n", + Urb->UrbControlTransfer.TransferBufferLength); + + if (Urb->UrbControlTransfer.TransferBufferLength) + { + ULONG Buffer; + ULONG BufferLength; + ULONG BufferEnd; + ULONG ix; + + Buffer = (ULONG)Urb->UrbControlTransfer.TransferBuffer; + BufferLength = Urb->UrbControlTransfer.TransferBufferLength; + BufferEnd = Buffer + BufferLength; + + DPRINT_URB("URB TransferBuffer - %p\n", Buffer); + + for (ix = 0; (Buffer + ix * 4) <= BufferEnd; ix++) + { + DPRINT_URB("Buffer[%02X] - %p\n", ix, *(PULONG)(Buffer + ix * 4)); + } + } +} + +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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&FdoExtension->EndpointListSpinLock, &OldIrql); + + InitializeListHead(&List); + + if (!IsListEmpty(&FdoExtension->EndpointList) && + FdoExtension->EndpointList.Flink) + { + Entry = FdoExtension->EndpointList.Flink; + + while (Entry != &FdoExtension->EndpointList) + { + Endpoint = CONTAINING_RECORD(Entry, + USBPORT_ENDPOINT, + EndpointLink); + + if (USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_NOT_HANDLED) + { + InsertTailList(&List, &Endpoint->FlushLink); + } + + Entry = Endpoint->EndpointLink.Flink; + + if (!Entry) + break; + } + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + while (TRUE) + { + if (IsListEmpty(&List)) + break; + + 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; + + if (!IsListEmpty(&Endpoint->TransferList)) + { + 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 = (PUSBPORT_DEVICE_EXTENSION)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_CLOSED && + Endpoint->StateLast != USBPORT_ENDPOINT_NOT_HANDLED) + { + InterlockedIncrement(&Endpoint->LockCounter); + InsertTailList(&FlushList, &Endpoint->FlushControllerLink); + } + + Entry = Endpoint->EndpointLink.Flink; + } + } + + KeReleaseSpinLock(&FdoExtension->EndpointListSpinLock, OldIrql); + + if (IsListEmpty(&FlushList)) + break; + + do + { + Endpoint = CONTAINING_RECORD(FlushList.Flink, + USBPORT_ENDPOINT, + FlushControllerLink); + + RemoveHeadList(&FlushList); + + KilledTransfers += USBPORT_KillEndpointActiveTransfers(FdoDevice, + Endpoint); + + InterlockedDecrement(&Endpoint->LockCounter); + } + while (!IsListEmpty(&FlushList)); + + 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 = (PUSBPORT_DEVICE_EXTENSION)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; + + if (PendingList != &Endpoint->PendingTransferList) + { + 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; + + if (ActiveList != &Endpoint->TransferList) + { + 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..1997c0d9a92 --- /dev/null +++ b/reactos/drivers/usb/usbport/roothub.c @@ -0,0 +1,1083 @@ +#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 != 1); + ++RHStatus; + } + + return RHStatus; +} + +ULONG +NTAPI +USBPORT_SetBit(ULONG_PTR Address, + UCHAR Index) +{ + ULONG_PTR AddressBitMap; + + DPRINT("USBPORT_SetBit: Address - %p, Index - %p\n", Address, Index); + + AddressBitMap = Address + 4 * (Index >> 5); + *(ULONG_PTR *)AddressBitMap |= 1 << (Index & 0x1F); + + return AddressBitMap; +} + +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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice, + FALSE, + TRUE); + + if (!CompanionControllersList) + { + Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port); + return 0; + } + + Entry = &CompanionControllersList->Objects[0]; + + while (NumController < CompanionControllersList->Count) + { + CompanionFdoDevice = *Entry; + + CompanionFdoExtension = (PUSBPORT_DEVICE_EXTENSION)CompanionFdoDevice->DeviceExtension; + CompanionPacket = &CompanionFdoExtension->MiniPortInterface->Packet; + + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)CompanionFdoExtension->RootHubPdo->DeviceExtension; + + for (ix = 0; + (PdoExtension->CommonExtension.PnpStateFlags & 2) && + ix < PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts; + ++ix) + { + CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt, + ix + 1); + } + + ++NumController; + ++Entry; + } + + Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port); + + if (CompanionControllersList) + { + ExFreePool(CompanionControllersList); + } + + return 0; +} + +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 = 2; + KIRQL OldIrql; + + DPRINT("USBPORT_RootHubClassCommand: USB command - %x, *BufferLength - %x\n", + SetupPacket->bRequest, + *BufferLength); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)FdoExtension->RootHubPdo->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + Port = SetupPacket->wIndex.W; + + switch (SetupPacket->bRequest) + { + case USB_REQUEST_GET_STATUS: // 0x00 + { + if (!Buffer) + { + return RHStatus; + } + + *(PULONG)Buffer = 0; + + if (SetupPacket->bmRequestType._BM.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: // 0x01 + Feature = SetupPacket->wValue.W; + + if ((SetupPacket->bmRequestType._BM.Recipient) != USBPORT_RECIPIENT_ROOT_PORT) + { + if (Feature == FEATURE_C_HUB_LOCAL_POWER) //0 + { + RHStatus = RH_STATUS_SUCCESS; + return RHStatus; + } + + if (Feature == FEATURE_C_HUB_OVER_CURRENT) //1 + { + MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt, + 0); + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + return RHStatus; + } + + DbgBreakPoint(); + return RHStatus; + } + + switch (Feature) + { + case FEATURE_PORT_ENABLE: // 1 + MPStatus = Packet->RH_ClearFeaturePortEnable(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_SUSPEND: // 2 + MPStatus = Packet->RH_ClearFeaturePortSuspend(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_POWER: // 8 + MPStatus = Packet->RH_ClearFeaturePortPower(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_CONNECTION: // 16 + MPStatus = Packet->RH_ClearFeaturePortConnectChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_ENABLE: // 17 + MPStatus = Packet->RH_ClearFeaturePortEnableChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_SUSPEND: // 18 + MPStatus = Packet->RH_ClearFeaturePortSuspendChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_OVER_CURRENT: // 19 + MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_C_PORT_RESET: // 20 + 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: // 0x03 + if (SetupPacket->bmRequestType._BM.Recipient != USBPORT_RECIPIENT_ROOT_PORT) + { + return RHStatus; + } + + Feature = SetupPacket->wValue.W; + + switch (Feature) + { + case FEATURE_PORT_ENABLE: // 1 + MPStatus = Packet->RH_SetFeaturePortEnable(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_SUSPEND: // 2 + MPStatus = Packet->RH_SetFeaturePortSuspend(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_RESET: // 4 + MPStatus = Packet->RH_SetFeaturePortReset(FdoExtension->MiniPortExt, + Port); + break; + + case FEATURE_PORT_POWER: // 8 + 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: // 0x06 + if (Buffer && + SetupPacket->wValue.W == 0 && + SetupPacket->bmRequestType._BM.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 = 2; + KIRQL OldIrql; + + DPRINT("USBPORT_RootHubStandardCommand: USB command - %x, TransferLength - %p\n", + SetupPacket->bRequest, + TransferLength); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)FdoExtension->RootHubPdo->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + switch (SetupPacket->bRequest) + { + case USB_REQUEST_GET_DESCRIPTOR: //0x06 + if (SetupPacket->wValue.LowByte || + !(SetupPacket->bmRequestType._BM.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: //0x00 + if (!SetupPacket->wValue.W && + SetupPacket->wLength == 2 && + !SetupPacket->wIndex.W && + SetupPacket->bmRequestType._BM.Dir) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + MPStatus = Packet->RH_GetStatus(FdoExtension->MiniPortExt, + Buffer); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + *TransferLength = 2; + RHStatus = USBPORT_MPStatusToRHStatus(MPStatus); + } + + break; + + case USB_REQUEST_GET_CONFIGURATION: //0x08 + if (SetupPacket->wValue.W || + SetupPacket->wIndex.W || + SetupPacket->wLength != 1 || + !(SetupPacket->bmRequestType._BM.Dir)) + { + 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: //0x09 + if (!SetupPacket->wIndex.W && + !SetupPacket->wLength && + !(SetupPacket->bmRequestType._BM.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: //0x05 + if (!SetupPacket->wIndex.W && + !SetupPacket->wLength && + !(SetupPacket->bmRequestType._BM.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._BM.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 2; + } + + 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; + ULONG HubStatus = 0; + PVOID Buffer; + PURB Urb; + RHSTATUS RHStatus = 1; + PUSB_HUB_DESCRIPTOR HubDescriptor; + UCHAR NumberOfPorts; + UCHAR ix; + + DPRINT("USBPORT_RootHubSCE: Transfer - %p\n", Transfer); + + Endpoint = Transfer->Endpoint; + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)Endpoint->FdoDevice->DeviceExtension; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)FdoExtension->RootHubPdo->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + HubDescriptor = (PUSB_HUB_DESCRIPTOR)&PdoExtension->RootHubDescriptors->Descriptor; + NumberOfPorts = HubDescriptor->bNumberOfPorts; + + PortStatus.AsULONG = 0; + + if (FdoExtension->Flags & 0x20000) + { + return 1; + } + + 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 2; + } + + if ((TransferLength < (NumberOfPorts / 8 + 1))) + { + /* Not valid parameters */ + DPRINT1("USBPORT_RootHubSCE: Error! TransferLength - %x, NumberOfPorts - %x\n", + TransferLength, + NumberOfPorts); + + return 2; + } + + RtlZeroMemory(Buffer, TransferLength); + + /* Scan all the ports for changes */ + if (NumberOfPorts) + { + ix = 0; + + while (ix < 256) + { + DPRINT_CORE("USBPORT_RootHubSCE: ix - %p\n", ix); + + /* Request the port status from miniport */ + if (Packet->RH_GetPortStatus(FdoExtension->MiniPortExt, + ix + 1, + &PortStatus.AsULONG)) + { + /* Miniport returned an error */ + DPRINT1("USBPORT_RootHubSCE: RH_GetPortStatus failed\n"); + return 2; + } + + if (PortStatus.UsbPortStatusChange.ConnectStatusChange || + PortStatus.UsbPortStatusChange.EnableStatusChange || + PortStatus.UsbPortStatusChange.SuspendStatusChange || + PortStatus.UsbPortStatusChange.OverCurrentChange || + PortStatus.UsbPortStatusChange.ResetStatusChange) + { + /* At the hub port status there is a change */ + USBPORT_SetBit((ULONG_PTR)Buffer, ix + 1); + RHStatus = RH_STATUS_SUCCESS; + } + + ++ix; + + if (ix >= NumberOfPorts) + { + break; + } + } + } + + /* Request the hub status from miniport */ + if (!Packet->RH_GetHubStatus(FdoExtension->MiniPortExt, &HubStatus)) + { + if (HubStatus & (HUB_STATUS_CHANGE_LOCAL_POWER | + HUB_STATUS_CHANGE_OVERCURRENT)) //0x00030000 + { + /* At the hub status there is a change */ + USBPORT_SetBit((ULONG_PTR)Buffer, 0); + RHStatus = RH_STATUS_SUCCESS; + } + + if (RHStatus == RH_STATUS_SUCCESS) + { + /* Done */ + Urb->UrbControlTransfer.TransferBufferLength = TransferLength; + return RH_STATUS_SUCCESS; + } + + if (RHStatus == 1) + { + /* 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 2; +} + +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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + if (!(FdoExtension->Flags & 0x20300)) + { + 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_CLOSED) + { + 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 != 1) + { + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + DeviceHandle = &PdoExtension->DeviceHandle; + USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle); + + InitializeListHead(&DeviceHandle->PipeHandleList); + + DeviceHandle->IsRootHub = 1; + DeviceHandle->DeviceSpeed = UsbFullSpeed; + DeviceHandle->Flags = DEVICE_HANDLE_FLAG_ROOTHUB; + + RtlZeroMemory(&RootHubData, sizeof(RootHubData)); + + Packet->RH_GetRootHubData(FdoExtension->MiniPortExt, &RootHubData); + + ASSERT(RootHubData.NumberOfPorts > 1); + NumMaskByte = ((RootHubData.NumberOfPorts - 1) >> 3) + 1; + + DescriptorsLength = sizeof(USB_DEVICE_DESCRIPTOR) + + sizeof(USB_CONFIGURATION_DESCRIPTOR) + + sizeof(USB_INTERFACE_DESCRIPTOR) + + sizeof(USB_ENDPOINT_DESCRIPTOR) + + (7 + 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 = 0x40; + 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 = 7 + 2 * NumMaskByte; + RH_HubDescriptor->bDescriptorType = 0x29; + RH_HubDescriptor->bNumberOfPorts = RootHubData.NumberOfPorts; + RH_HubDescriptor->wHubCharacteristics = RootHubData.HubCharacteristics; + RH_HubDescriptor->bPowerOnToPowerGood = RootHubData.PowerOnToPowerGood; + RH_HubDescriptor->bHubControlCurrent = RootHubData.HubControlCurrent; + + if (NumMaskByte) + { + ix = 0; + do + { + RH_HubDescriptor->bRemoveAndPowerMask[ix] = 0; + RH_HubDescriptor->bRemoveAndPowerMask[ix + 1] = -1; + ix += 2; + } + while (ix < NumMaskByte); + } + + EndpointDescriptor = &DeviceHandle->PipeHandle.EndpointDescriptor; + + EndpointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR); + EndpointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE; + EndpointDescriptor->bEndpointAddress = 0x00; + EndpointDescriptor->bmAttributes = 0x00; + 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 & 0x00200000 && + 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 = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + Packet = &FdoExtension->MiniPortInterface->Packet; + + RtlZeroMemory(&RootHubData, sizeof(RootHubData)); + + Packet->RH_GetRootHubData(FdoExtension->MiniPortExt, + &RootHubData); + + NumPorts = RootHubData.NumberOfPorts; + + if (NumPorts) + { + Port = 1; + + do + { + Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, + Port); + ++Port; + } + while (Port < NumPorts); + } + + USBPORT_Wait(FdoDevice, 10); + + CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice, + FALSE, + TRUE); + + if (CompanionControllersList) + { + NumController = 0; + + if (CompanionControllersList->Count) + { + Entry = &CompanionControllersList->Objects[0]; + + do + { + CompanionPacket = &FdoExtension->MiniPortInterface->Packet; + + CompanionFdoExtension = (PUSBPORT_DEVICE_EXTENSION)(*Entry)->DeviceExtension; + + CompanionPacket->RH_GetRootHubData(CompanionFdoExtension->MiniPortExt, + &RootHubData); + + CompanionPorts = RootHubData.NumberOfPorts; + + if (RootHubData.NumberOfPorts) + { + Port = 1; + + do + { + CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt, + Port); + ++Port; + } + while (Port < CompanionPorts); + } + + ++NumController; + ++Entry; + } + while (NumController < CompanionControllersList->Count); + } + + ExFreePool(CompanionControllersList); + } + + USBPORT_Wait(FdoDevice, 100); + + if (NumPorts == 0) + { + return; + } + + Port = 1; + + do + { + if (FdoExtension->MiniPortInterface->Version < 200) + { + break; + } + + InterlockedIncrement((PLONG)&FdoExtension->ChirpRootPortLock); + Packet->RH_ChirpRootPort(FdoExtension->MiniPortExt, Port); + InterlockedDecrement((PLONG)&FdoExtension->ChirpRootPortLock); + + ++Port; + } + while (Port < NumPorts); +} diff --git a/reactos/drivers/usb/usbport/urb.c b/reactos/drivers/usb/usbport/urb.c new file mode 100644 index 00000000000..b27fe22cc28 --- /dev/null +++ b/reactos/drivers/usb/usbport/urb.c @@ -0,0 +1,1027 @@ +#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._BM.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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_PIPE_HANDLE)Urb->UrbPipeRequest.PipeHandle; + DeviceHandle = (PUSBPORT_DEVICE_HANDLE)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; + KIRQL OldIrql; + NTSTATUS Status; + + DPRINT_URB("USBPORT_ResetPipe: ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + PipeHandle = (PUSBPORT_PIPE_HANDLE)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) + { + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->SetEndpointDataToggle(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 0); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + } + + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_SUCCESS); + } + else + { + Status = USBPORT_USBDStatusToNtStatus(Urb, USBD_STATUS_ERROR_BUSY); + } + + Endpoint->Flags |= ENDPOINT_FLAG_QUEUENE_EMPTY; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + Packet->SetEndpointStatus(FdoExtension->MiniPortExt, + (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)), + 0); + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + 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 = (PUSBPORT_PIPE_HANDLE)Urb->UrbPipeRequest.PipeHandle; + DeviceHandle = (PUSBPORT_DEVICE_HANDLE)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._BM.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 = (PUSBPORT_DEVICE_HANDLE)Urb->UrbHeader.UsbdDeviceHandle; + PipeHandle = (PUSBPORT_PIPE_HANDLE)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._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: // 0x0D + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: // 0x0E + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: // 0x0F + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: // 0x10 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: // 0x11 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: // 0x12 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: // 0x22 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_CLEAR_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_OTHER; + break; + + case URB_FUNCTION_SET_FEATURE_TO_OTHER: // 0x23 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_FEATURE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_OTHER; + break; + } + + Urb->UrbControlFeatureRequest.Reserved2 &= ~USBD_TRANSFER_DIRECTION_IN; // ~1; + Urb->UrbControlFeatureRequest.Reserved2 |= USBD_SHORT_TRANSFER_OK; // 2 + + 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; // ~1 + else + Urb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; // 1 + } + + USBPORT_QueueTransferUrb(Urb); + + return STATUS_PENDING; +} + +NTSTATUS +NTAPI +USBPORT_HandleGetStatus(IN PIRP Irp, + IN PURB Urb) +{ + PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET)&Urb->UrbControlDescriptorRequest.Reserved1; + NTSTATUS Status; + + SetupPacket->bmRequestType.B = 0; + SetupPacket->bmRequestType._BM.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: // 0x13 + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_DEVICE\n"); + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: // 0x14 + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_INTERFACE\n"); + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: // 0x15 + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_ENDPOINT\n"); + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_GET_STATUS_FROM_OTHER: // 0x21 + DPRINT_URB("USBPORT_HandleGetStatus: URB_FUNCTION_GET_STATUS_FROM_OTHER\n"); + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_OTHER; + break; + } + + if (SetupPacket->wLength == 2) + { + Urb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; // 2 + + if (SetupPacket->bmRequestType._BM.Dir) + Urb->UrbControlTransfer.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; // 1; + else + Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN; // ~1; + + //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._BM.Dir = Urb->UrbControlTransfer.TransferFlags & 1; + SetupPacket->wLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; + + Urb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; // 2 + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_VENDOR_DEVICE: // 0x17 + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_DEVICE\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_VENDOR_INTERFACE: // 0x18 + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_INTERFACE\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_VENDOR_ENDPOINT: // 0x19 + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_ENDPOINT\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLASS_DEVICE: // 0x1A + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_DEVICE\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_CLASS_INTERFACE: // 0x1B + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_INTERFACE\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_CLASS_ENDPOINT: // 0x1C + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_ENDPOINT\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_CLASS_OTHER: // 0x1F + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_CLASS_OTHER\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_CLASS; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_OTHER; + break; + + case URB_FUNCTION_VENDOR_OTHER: // 0x20 + DPRINT_URB("USBPORT_HandleVendorOrClass: URB_FUNCTION_VENDOR_OTHER\n"); + SetupPacket->bmRequestType._BM.Type = BMREQUEST_VENDOR; + SetupPacket->bmRequestType._BM.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._BM.Type = BMREQUEST_STANDARD; + + switch (Urb->UrbHeader.Function) + { + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: // 0x0B + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR; + SetupPacket->bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: // 0x0C + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_DESCRIPTOR; + SetupPacket->bmRequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE; + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: // 0x24 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR; + SetupPacket->bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: // 0x25 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT\n"); + SetupPacket->bRequest = USB_REQUEST_SET_DESCRIPTOR; + SetupPacket->bmRequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_ENDPOINT; + break; + + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: // 0x28 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_GET_DESCRIPTOR; + SetupPacket->bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: // 0x29 + DPRINT_URB("USBPORT_HandleGetSetDescriptor: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE\n"); + SetupPacket->bRequest = USB_REQUEST_SET_DESCRIPTOR; + SetupPacket->bmRequestType._BM.Dir = BMREQUEST_HOST_TO_DEVICE; + SetupPacket->bmRequestType._BM.Recipient = BMREQUEST_TO_INTERFACE; + break; + } + + Urb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; // 2 + + if (SetupPacket->bmRequestType._BM.Dir) + Urb->UrbControlTransfer.TransferFlags |= USBD_TRANSFER_DIRECTION_IN; // 1; + else + Urb->UrbControlTransfer.TransferFlags &= ~USBD_TRANSFER_DIRECTION_IN; // ~1; + + 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 = (PUSBPORT_DEVICE_HANDLE)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 = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + FdoDevice = PdoExtension->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_HANDLE)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: // 0x10 + DPRINT1("USBPORT_HandleSubmitURB: URB_FUNCTION_ISOCH_TRANSFER UNIMPLEMENTED. FIXME. \n"); + break; + + case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: // 0x09 + case URB_FUNCTION_CONTROL_TRANSFER: // 0x08 + 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: // 0x17 + case URB_FUNCTION_VENDOR_INTERFACE: // 0x18 + case URB_FUNCTION_VENDOR_ENDPOINT: // 0x19 + case URB_FUNCTION_CLASS_DEVICE: // 0x1A + case URB_FUNCTION_CLASS_INTERFACE: // 0x1B + case URB_FUNCTION_CLASS_ENDPOINT: // 0x1C + case URB_FUNCTION_CLASS_OTHER: // 0x1F + case URB_FUNCTION_VENDOR_OTHER: // 0x20 + 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: // 0x0B + case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: // 0x0C + case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: // 0x24 + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: // 0x25 + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: // 0x28 + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: // 0x29 + 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: // 0x2A + 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: // 0x13 + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: // 0x14 + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: // 0x15 + case URB_FUNCTION_GET_STATUS_FROM_OTHER: // 0x21 + 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: // 0x00 + Status = USBPORT_HandleSelectConfiguration(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SELECT_INTERFACE: // 0x01 + Status = USBPORT_HandleSelectInterface(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_GET_CONFIGURATION: // 0x26 + 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: // 0x27 + 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: // 0x1E + Status = USBPORT_SyncResetPipeAndClearStall(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SYNC_RESET_PIPE: // 0x30 + Status = USBPORT_ResetPipe(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SYNC_CLEAR_STALL: // 0x31 + Status = USBPORT_ClearStall(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_ABORT_PIPE: // 0x02 + Status = USBPORT_AbortPipe(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: // 0x0D + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: // 0x0E + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: // 0x0F + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: // 0x11 + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: // 0x12 + case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: // 0x22 + case URB_FUNCTION_SET_FEATURE_TO_OTHER: // 0x23 + 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: // 0x07 + Status = USBPORT_HandleGetCurrentFrame(PdoExtension->FdoDevice, + Irp, + Urb); + break; + + case URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL: // 0x03 + 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: // 0x04 + 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: // 0x05 + 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: // 0x06 + 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); + //0x16 22 URB_FUNCTION_RESERVED_0X0016 + //0x1D 29 URB_FUNCTION_RESERVE_0X001D + //0x2B 43 URB_FUNCTION_RESERVE_0X002B + //0x2C 44 URB_FUNCTION_RESERVE_0X002C + //0x2D 45 URB_FUNCTION_RESERVE_0X002D + //0x2E 46 URB_FUNCTION_RESERVE_0X002E + //0x2F 47 URB_FUNCTION_RESERVE_0X002F + break; + } + + if (Status == STATUS_PENDING) + { + return Status; + } + + if (Urb->UrbHeader.UsbdFlags & USBD_FLAG_ALLOCATED_TRANSFER) + { + PUSBPORT_TRANSFER Transfer; + + Transfer = (PUSBPORT_TRANSFER)Urb->UrbControlTransfer.hca.Reserved8[0]; + Urb->UrbControlTransfer.hca.Reserved8[0] = NULL; + Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_TRANSFER; + ExFreePool(Transfer); + } + + 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..0832a617710 --- /dev/null +++ b/reactos/drivers/usb/usbport/usbport.c @@ -0,0 +1,2890 @@ +#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 = 0; +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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); + + USB2FdoEntry = USBPORT_USB2FdoList.Flink; + + if (!IsListEmpty(&USBPORT_USB2FdoList)) + { + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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; + + if (!IsListEmpty(&USBPORT_USB1FdoList) && USBPORT_USB1FdoList.Flink) + { + do + { + if (USB1FdoList == &USBPORT_USB1FdoList) + { + break; + } + + USB1FdoExtension = CONTAINING_RECORD(USB1FdoList, + USBPORT_DEVICE_EXTENSION, + ControllerLink); + + if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC && + USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension)) + { + ++NumControllers; + } + + USB1FdoList = USB1FdoExtension->ControllerLink.Flink; + } + while (USB1FdoList); + } + + 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; + + if (IsListEmpty(&USBPORT_USB1FdoList)) + { + goto Exit; + } + + USB1FdoList = USBPORT_USB1FdoList.Flink; + + if (USBPORT_USB1FdoList.Flink == NULL) + { + goto Exit; + } + + Entry = &ControllersList->Objects[0]; + + do + { + if (USB1FdoList == &USBPORT_USB1FdoList) + { + break; + } + + 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; + } + while (USB1FdoList); + +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 0; + } + else + { + return 8; + } +} + +NTSTATUS +NTAPI +USBPORT_SetRegistryKeyValue(IN PDEVICE_OBJECT DeviceObject, + IN HANDLE KeyHandle, + IN ULONG Type, + IN PCWSTR ValueNameString, + IN PVOID Data, + IN ULONG DataSize) +{ + UNICODE_STRING ValueName; + NTSTATUS Status; + + DPRINT("USBPORT_SetRegistryKeyValue: ValueNameString - %S \n", + ValueNameString); + + if (KeyHandle) + { + 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 ULONG Type, + IN PCWSTR SourceString, + IN ULONG LengthStr, + IN PVOID Buffer, + IN ULONG NumberOfBytes) +{ + NTSTATUS Status; + PKEY_VALUE_FULL_INFORMATION KeyValue; + UNICODE_STRING ValueName; + HANDLE KeyHandle; + ULONG LengthKey; + + DPRINT("USBPORT_GetRegistryKeyValue: Type - %x, SourceString - %S, LengthStr - %x, Buffer - %p, NumberOfBytes - %x\n", + Type, + SourceString, + LengthStr, + Buffer, + NumberOfBytes); + + if (Type) + { + 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 + NumberOfBytes; + + KeyValue = (PKEY_VALUE_FULL_INFORMATION)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, + NumberOfBytes); + } + + ExFreePool(KeyValue); + } + + ZwClose(KeyHandle); + } + + return Status; +} + +MPSTATUS +NTAPI +USBPORT_GetMiniportRegistryKeyValue(IN PVOID Context, + IN ULONG Type, + IN PCWSTR SourceString, + IN SIZE_T LengthStr, + IN PVOID Buffer, + IN SIZE_T NumberOfBytes) +{ + PUSBPORT_DEVICE_EXTENSION FdoExtension; + PDEVICE_OBJECT FdoDevice; + NTSTATUS Status; + + DPRINT("USBPORT_GetMiniportRegistryKeyValue: Context - %p, Type - %x, SourceString - %S, LengthStr - %x, Buffer - %p, NumberOfBytes - %x\n", + Context, + Type, + SourceString, + LengthStr, + Buffer, + NumberOfBytes); + + //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, + Type, + SourceString, + LengthStr, + Buffer, + NumberOfBytes); + + 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_ReadWriteConfigSpace ... \n"); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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; + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + IsLock = ~(UCHAR)(Packet->MiniPortFlags >> 6) & 1; + + 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 = (PDEVICE_OBJECT)DeferredContext; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PDEVICE_OBJECT)DeferredContext; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PDEVICE_OBJECT)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + InitializeListHead(&List); + + KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); + Entry = FdoExtension->EndpointList.Flink; + + if (!IsListEmpty(&FdoExtension->EndpointList)) + { + 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; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_IsrDpcHandler: IsDpcHandler - %x\n", IsDpcHandler); + + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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); + + KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (FrameNumber <= Endpoint->FrameNumber && !(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) + { + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + ExInterlockedInsertHeadList(&FdoExtension->EpStateChangeList, + &Endpoint->StateChangeLink, + &FdoExtension->EpStateChangeSpinLock); + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + Packet->InterruptNextSOF(FdoExtension->MiniPortExt); + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + break; + } + + KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); + + KeAcquireSpinLock(&Endpoint->StateChangeSpinLock, &Endpoint->EndpointStateOldIrql); + Endpoint->StateLast = Endpoint->StateNext; + KeReleaseSpinLock(&Endpoint->StateChangeSpinLock, Endpoint->EndpointStateOldIrql); + + 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 = (PDEVICE_OBJECT)DeferredContext; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = 0; + + FdoDevice = (PDEVICE_OBJECT)ServiceContext; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + DPRINT_INT("USBPORT_InterruptService: FdoExtension->Flags - %p\n", + FdoExtension->Flags); + + if (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED) + { + if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) + { + Result = Packet->InterruptService(FdoExtension->MiniPortExt); + + if (Result) + { + KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL); + } + } + } + else + { + Result = 0; + } + + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + Packet = &FdoExtension->MiniPortInterface->Packet; + + KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); + + if (!(FdoExtension->Flags & 0x20300)) + { + 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 (TRUE) + { + if (IsListEmpty(&list)) + break; + + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + DPRINT("USBPORT_DoRootHubCallback: FdoDevice - %p\n", FdoDevice); + + PdoDevice = FdoExtension->RootHubPdo; + + if (PdoDevice) + { + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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); + + ix = 0; + + if (CompanionControllersList) + { + Entry = &CompanionControllersList->Objects[0]; + + while (ix < CompanionControllersList->Count) + { + CompanionFdoExtension = (PUSBPORT_DEVICE_EXTENSION)((*Entry)->DeviceExtension); + + InterlockedCompareExchange(&CompanionFdoExtension->RHInitCallBackLock, + 0, + 1); + + ++Entry; + ++ix; + } + + ExFreePool(CompanionControllersList); + } + + USBPORT_DoRootHubCallback(FdoDevice); + + FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; + InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1); + } + else + { + Usb2FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 = {{0, 0}}; + LARGE_INTEGER NewTime = {{0, 0}}; + KIRQL OldIrql; + + DPRINT_CORE("USBPORT_WorkerThread ... \n"); + + FdoDevice = (PDEVICE_OBJECT)StartContext; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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); + } + + if (FdoExtension->Flags & 0x00100000) + { + DPRINT("USBPORT_WorkerThread: EndTransmitTriggerPacket UNIMPLEMENTED.\n"); + DbgBreakPoint(); + } + } + else if (!(FdoExtension->Flags & 0x00020000)) + { + DPRINT1("USBPORT_WorkerThread: !0x00020000 \n"); + DbgBreakPoint(); + continue; + } + + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + PdoDevice = FdoExtension->RootHubPdo; + + if (!PdoDevice) + { + return; + } + + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)USB2FdoDevice->DeviceExtension; + + if (USB2FdoExtension->CommonExtension.PnpStateFlags & 2) + { + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PDEVICE_OBJECT)DeferredContext; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)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 & 0x00200000 && + !(TimerFlags & 0x00000004)) + { + 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 & (0x00020000 | + 0x00000200 | + USBPORT_FLAG_HC_SUSPEND))) + { + Packet->CheckController(FdoExtension->MiniPortExt); + } + + KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); + + if (FdoExtension->Flags & 0x00000004) + { + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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 & 0xFFFFF000; + StartBufferPA = LogicalAddress.LowPart & 0xFFFFF000; + + HeaderBuffer = (PUSBPORT_COMMON_BUFFER_HEADER)(StartBufferVA + + BufferLength + + LengthPadded); + + HeaderBuffer->Length = Length; + HeaderBuffer->BaseVA = BaseVA; + HeaderBuffer->LogicalAddress = LogicalAddress; // PHYSICAL_ADDRESS + + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = NULL; + + 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); + break; + } + } + + KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); + + return MiniPortInterface; +} + +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; + 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 + swprintf(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 = (PUSBPORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + + RtlZeroMemory(FdoExtension, sizeof(USBPORT_DEVICE_EXTENSION)); + + FdoExtension->CommonExtension.SelfDevice = DeviceObject; + FdoExtension->CommonExtension.LowerPdoDevice = PhysicalDeviceObject; + FdoExtension->CommonExtension.IsPDO = FALSE; + FdoExtension->CommonExtension.LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, + PhysicalDeviceObject); + + FdoExtension->CommonExtension.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"); + ASSERT(FALSE); + } + + 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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_ASYNC_CALLBACK_DATA)DeferredContext; + FdoDevice = AsyncCallbackData->FdoDevice; + FdoExtension = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + (*(ASYNC_TIMER_CALLBACK *)AsyncCallbackData->CallbackFunction)(FdoExtension->MiniPortExt, + &AsyncCallbackData->CallbackContext); + + ExFreePool(AsyncCallbackData); +} + +ULONG +NTAPI +USBPORT_RequestAsyncCallback(IN PVOID Context, + IN ULONG TimerValue, + IN PVOID Buffer, + IN SIZE_T Length, + IN ULONG 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 = (PUSBPORT_ASYNC_CALLBACK_DATA) + 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 = (ASYNC_TIMER_CALLBACK *)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 - %p\n", + Urb, + TransferStatus); + + UrbTransfer = &Urb->UrbControlTransfer; + Transfer = (PUSBPORT_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 = (PUSBPORT_DEVICE_EXTENSION)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 - %p\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); + } + + ExFreePool(Transfer); + + 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; + PVOID MappedSystemVa; + 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 = (PUSBPORT_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + DmaAdapter = FdoExtension->DmaAdapter; + DmaOperations = DmaAdapter->DmaOperations; + + Transfer = (PUSBPORT_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; + + Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL; + + if (Mdl->MdlFlags & (MDL_SOURCE_IS_NONPAGED_POOL | MDL_MAPPED_TO_SYSTEM_VA)) + MappedSystemVa = Mdl->MappedSystemVa; + else + MappedSystemVa = MmMapLockedPages(Mdl, KernelMode); + + Transfer->SgList.MappedSystemVa = MappedSystemVa; + + Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL; + + 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 = (PUSBPORT_DEVICE_HANDLE)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 = (PUSBPORT_DEVICE_EXTENSION)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 = (PUSBPORT_DEVICE_EXTENSION)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_PdoScsi(IN PDEVICE_OBJECT PdoDevice, + IN PIRP Irp) +{ + PUSBPORT_RHDEVICE_EXTENSION PdoExtension; + PIO_STACK_LOCATION IoStack; + ULONG IoCtl; + NTSTATUS Status; + + PdoExtension = (PUSBPORT_RHDEVICE_EXTENSION)PdoDevice->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + IoCtl = IoStack->Parameters.DeviceIoControl.IoControlCode; + + DPRINT("USBPORT_PdoScsi: 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_PdoScsi: 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_PdoScsi: IOCTL_INTERNAL_USB_GET_HUB_COUNT\n"); + + if (IoStack->Parameters.Others.Argument1) + { + *(PULONG)IoStack->Parameters.Others.Argument1 = + *(PULONG)IoStack->Parameters.Others.Argument1 + 1; + } + + Status = STATUS_SUCCESS; + goto Exit; + } + + if (IoCtl == IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE) + { + DPRINT("USBPORT_PdoScsi: 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_PdoScsi: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION\n"); + return USBPORT_IdleNotification(PdoDevice, Irp); + } + + DPRINT("USBPORT_PdoScsi: 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_Dispatch(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PUSBPORT_COMMON_DEVICE_EXTENSION DeviceExtension; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status = STATUS_SUCCESS; + + DeviceExtension = (PUSBPORT_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + + if (DeviceExtension->PnpStateFlags & 0x00000004) + { + DPRINT1("USBPORT_Dispatch: DeviceExtension->PnpStateFlags & 0x00000004\n"); + DbgBreakPoint(); + } + + switch (IoStack->MajorFunction) + { + case IRP_MJ_DEVICE_CONTROL: // 14 + 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_SCSI: // 15 IRP_MJ_NTERNAL_DEVICE_CONTROL: + if (DeviceExtension->IsPDO) + { + DPRINT("USBPORT_Dispatch: PDO IRP_MJ_SCSI. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_PdoScsi(DeviceObject, Irp); + } + else + { + DPRINT("USBPORT_Dispatch: FDO IRP_MJ_SCSI. Major - %d, Minor - %d\n", + IoStack->MajorFunction, + IoStack->MinorFunction); + + Status = USBPORT_FdoScsi(DeviceObject, Irp); + } + + break; + + case IRP_MJ_POWER: // 22 + 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: // 23 + 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: // 27 + 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: // 0 + case IRP_MJ_CLOSE: // 2 + 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 0x10000001; +} + +NTSTATUS +NTAPI +USBPORT_RegisterUSBPortDriver(IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PUSBPORT_REGISTRATION_PACKET RegPacket) +{ + NTSTATUS Status; + 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 = (PUSBPORT_MINIPORT_INTERFACE) + 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 = (PDRIVER_ADD_DEVICE)USBPORT_AddDevice; + DriverObject->DriverUnload = (PDRIVER_UNLOAD)USBPORT_Unload; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)USBPORT_Dispatch; // [== IRP_MJ_SCSI] + DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH)USBPORT_Dispatch; + DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)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)); + + Status = STATUS_SUCCESS; + return Status; +} + +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..f2a2957634c --- /dev/null +++ b/reactos/drivers/usb/usbport/usbport.h @@ -0,0 +1,1137 @@ +#ifndef USBPORT_H__ +#define USBPORT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "..\usbmport.h" + +#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 +#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_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_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 + +/* Timer Flags */ + +#define USBPORT_TMFLAG_TIMER_QUEUED 0x00000001 +#define USBPORT_TMFLAG_HC_SUSPENDED 0x00000002 +#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; // 00 + LIST_ENTRY InterfaceHandleList; // 04 + //USB_CONFIGURATION_DESCRIPTOR CfgDescriptor; // 12 Body +} USBPORT_CONFIGURATION_HANDLE, *PUSBPORT_CONFIGURATION_HANDLE; + +typedef struct _USBPORT_INTERFACE_HANDLE { + LIST_ENTRY InterfaceLink; // 00 + UCHAR AlternateSetting; // 08 + UCHAR Pad1[3]; // 09 + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; // 12 + UCHAR Pad2[3]; // 21 + USBPORT_PIPE_HANDLE PipeHandle[1]; // 24 +} 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; // 0x12 + 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; // 18 + USB_CONFIGURATION_DESCRIPTOR ConfigDescriptor; // 9 + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; // 9 + USB_ENDPOINT_DESCRIPTOR EndPointDescriptor; // 7 + USB_HUB_DESCRIPTOR Descriptor; // 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 VOID +(NTAPI ASYNC_TIMER_CALLBACK)( + IN PVOID MiniportExtension, + IN PVOID CallBackContext); + +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_RegisterUSBPortDriver( + IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PUSBPORT_REGISTRATION_PACKET RegistrationPacket); + +ULONG +NTAPI +USBPORT_GetHciMn(VOID); + +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 HANDLE KeyHandle, + 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 ULONG Type, + 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); + +/* debug.c */ + +ULONG +NTAPI +USBPORT_DbgPrint( + IN PVOID Context, + IN ULONG Level, + IN PCH Format, + IN ULONG Arg1, + IN ULONG Arg2, + IN ULONG Arg3, + IN ULONG Arg4, + IN ULONG Arg5, + IN ULONG Arg6); + +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 PVOID DriverTag, + IN PVOID 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); + +/* 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_FdoScsi( + 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/drivers/usb/usbuhci_new/CMakeLists.txt b/reactos/drivers/usb/usbuhci_new/CMakeLists.txt new file mode 100644 index 00000000000..8d1d0e61af4 --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/CMakeLists.txt @@ -0,0 +1,15 @@ + +list(APPEND SOURCE + roothub.c + usbuhci.c + usbuhci.h) + +add_library(usbuhci SHARED + ${SOURCE} + guid.c + usbuhci.rc) + +set_module_type(usbuhci kernelmodedriver) +add_importlibs(usbuhci usbport ntoskrnl hal usbd) +add_pch(usbuhci usbuhci.h SOURCE) +add_cd_file(TARGET usbuhci DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/reactos/drivers/usb/usbuhci_new/guid.c b/reactos/drivers/usb/usbuhci_new/guid.c new file mode 100644 index 00000000000..50a60369ff3 --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/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/usbuhci_new/hardware.h b/reactos/drivers/usb/usbuhci_new/hardware.h new file mode 100644 index 00000000000..b7b94aca9f4 --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/hardware.h @@ -0,0 +1,131 @@ +/* UHCI hardware registers */ + +#define UHCI_USBCMD 0x00 // USB Command +#define UHCI_USBSTS 0x02 // USB Status +#define UHCI_USBINTR 0x04 // USB Interrupt Enable +#define UHCI_FRNUM 0x06 // Frame Number +#define UHCI_FRBASEADD 0x08 // Frame List Base Address +#define UHCI_SOFMOD 0x0C // Start Of Frame Modify +#define UHCI_PORTSC1 0x10 // Port 1 Status/Control +#define UHCI_PORTSC2 0x12 // Port 2 Status/Control + +/* Command register */ + +typedef union _UHCI_USB_COMMAND { + struct { + USHORT Run : 1; + USHORT HcReset : 1; + USHORT GlobalReset : 1; + USHORT GlobalSuspend : 1; + USHORT GlobalResume : 1; // Force Global Resume + USHORT SoftwareDebug : 1; // 0 - Normal Mode, 1 - Debug mode + USHORT ConfigureFlag : 1; // no effect on the hardware + USHORT MaxPacket : 1; // 0 = 32, 1 = 64 + USHORT Reserved : 8; + }; + USHORT AsUSHORT; +} UHCI_USB_COMMAND; + +/* Status register */ + +typedef union _UHCI_USB_STATUS { + struct { + USHORT Interrupt : 1; // due to IOC (Interrupt On Complete) + USHORT ErrorInterrupt : 1; // due to error + USHORT ResumeDetect : 1; + USHORT HostSystemError : 1; // PCI problems + USHORT HcProcessError : 1; // Schedule is buggy + USHORT HcHalted : 1; + USHORT Reserved : 10; + }; + USHORT AsUSHORT; +} UHCI_USB_STATUS; + +/* Interrupt enable register */ + +typedef union _UHCI_INTERRUPT_ENABLE { + struct { + USHORT TimeoutCRC : 1; // Timeout/CRC error enable + USHORT ResumeInterrupt : 1; + USHORT InterruptOnComplete : 1; + USHORT ShortPacket : 1; + USHORT Reserved : 12; + }; + USHORT AsUSHORT; +} UHCI_INTERRUPT_ENABLE; + +/* USB port status and control registers */ + +typedef union _UHCI_PORT_STATUS_CONTROL { + struct { + USHORT CurrentConnectStatus : 1; + USHORT ConnectStatusChange : 1; + USHORT PortEnabledDisabled : 1; + USHORT PortEnableDisableChange : 1; + USHORT LineStatus : 2; // D+ and D- + USHORT ResumeDetect : 1; + USHORT Reserved1 : 1; // always 1 + USHORT LowSpeedDevice : 1; // LS device Attached + USHORT PortReset : 1; + USHORT Reserved2 : 2; // Intel use it (not UHCI 1.1d spec) + USHORT Suspend : 1; + USHORT Reserved3 : 3; // write zeroes + }; + USHORT AsUSHORT; +} UHCI_PORT_STATUS_CONTROL; + +/* Transfer Descriptor (TD) */ + +#define UHCI_TD_STS_ACTIVE (1 << 7) // 0x80 +#define UHCI_TD_STS_STALLED (1 << 6) // 0x40 +#define UHCI_TD_STS_DATA_BUFFER_ERROR (1 << 5) // 0x20 +#define UHCI_TD_STS_BABBLE_DETECTED (1 << 4) // 0x10 +#define UHCI_TD_STS_NAK_RECEIVED (1 << 3) // 0x08 +#define UHCI_TD_STS_TIMEOUT_CRC_ERROR (1 << 2) // 0x04 +#define UHCI_TD_STS_BITSTUFF_ERROR (1 << 1) // 0x02 +//#define UHCI_TD_STS_Reserved (1 << 0) // 0x01 + +typedef union _UHCI_CONTROL_STATUS { + struct { + ULONG ActualLength : 11; // encoded as n - 1 + ULONG Reserved1 : 5; + ULONG Status : 8; // UHCI_TD_STS_ xxx + ULONG InterruptOnComplete : 1; + ULONG IsochronousType : 1; + ULONG LowSpeedDevice : 1; + ULONG ErrorCounter : 2; + ULONG ShortPacketDetect : 1; + ULONG Reserved2 : 2; + }; + ULONG AsULONG; +} UHCI_CONTROL_STATUS; + +typedef union _UHCI_TD_TOKEN { + struct { + ULONG PIDCode : 8; + ULONG DeviceAddress : 7; + ULONG Endpoint : 4; + ULONG DataToggle : 1; + ULONG Reserved : 1; + ULONG MaximumLength : 11; + }; + ULONG AsULONG; +} UHCI_TD_TOKEN; + +typedef struct _UHCI_TD { // always aligned on 16-byte boundaries + ULONG_PTR NextElement; // another TD, or a QH, or nothing + UHCI_CONTROL_STATUS ControlStatus; + UHCI_TD_TOKEN Token; + ULONG_PTR Buffer; +} UHCI_TD, *PUHCI_TD; + +C_ASSERT(sizeof(UHCI_TD) == 16); + +/* Queue Header (QH) */ + +typedef struct _UHCI_QH { // must be aligned on a 16-byte boundary + ULONG_PTR NextQH; + ULONG_PTR FirstElement; +} UHCI_QH, *PUHCI_QH; + +C_ASSERT(sizeof(UHCI_QH) == 8); diff --git a/reactos/drivers/usb/usbuhci_new/roothub.c b/reactos/drivers/usb/usbuhci_new/roothub.c new file mode 100644 index 00000000000..f590394198c --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/roothub.c @@ -0,0 +1,163 @@ +#include "usbuhci.h" + +//#define NDEBUG +#include + +VOID +NTAPI +UhciRHGetRootHubData(IN PVOID uhciExtension, + IN PVOID rootHubData) +{ + DPRINT("UhciRHGetRootHubData: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciRHGetStatus(IN PVOID uhciExtension, + IN PUSHORT Status) +{ + DPRINT("UhciRHGetStatus: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHGetPortStatus(IN PVOID uhciExtension, + IN USHORT Port, + IN PULONG PortStatus) +{ + DPRINT("UhciRHGetPortStatus: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHGetHubStatus(IN PVOID uhciExtension, + IN PULONG HubStatus) +{ + DPRINT("UhciRHGetHubStatus: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortReset(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHSetFeaturePortReset: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortPower(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHSetFeaturePortPower: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortEnable(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHSetFeaturePortEnable: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortSuspend(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHSetFeaturePortSuspend: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortEnable(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortEnable: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortPower(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortPower: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortSuspend(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortSuspend: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortEnableChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortEnableChange: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortConnectChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortConnectChange: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortResetChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortResetChange: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortSuspendChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortSuspendChange: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortOvercurrentChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortOvercurrentChange: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciRHDisableIrq(IN PVOID uhciExtension) +{ + DPRINT("UhciRHDisableIrq: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciRHEnableIrq(IN PVOID uhciExtension) +{ + DPRINT("UhciRHEnableIrq: UNIMPLEMENTED. FIXME\n"); +} + diff --git a/reactos/drivers/usb/usbuhci_new/usbuhci.c b/reactos/drivers/usb/usbuhci_new/usbuhci.c new file mode 100644 index 00000000000..3d998bc4637 --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/usbuhci.c @@ -0,0 +1,364 @@ +#include "usbuhci.h" + +//#define NDEBUG +#include + + +USBPORT_REGISTRATION_PACKET RegPacket; + + +MPSTATUS +NTAPI +UhciOpenEndpoint(IN PVOID uhciExtension, + IN PVOID endpointParameters, + IN PVOID uhciEndpoint) +{ + DPRINT("UhciOpenEndpoint: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciReopenEndpoint(IN PVOID uhciExtension, + IN PVOID endpointParameters, + IN PVOID uhciEndpoint) +{ + DPRINT("Uhci: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciQueryEndpointRequirements(IN PVOID uhciExtension, + IN PVOID endpointParameters, + IN PULONG EndpointRequirements) +{ + DPRINT("UhciQueryEndpointRequirements: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciCloseEndpoint(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN BOOLEAN IsDoDisablePeriodic) +{ + DPRINT("UhciCloseEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciStartController(IN PVOID uhciExtension, + IN PUSBPORT_RESOURCES Resources) +{ + DPRINT("UhciStartController: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciStopController(IN PVOID uhciExtension, + IN BOOLEAN IsDoDisableInterrupts) +{ + DPRINT("UhciStopController: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciSuspendController(IN PVOID uhciExtension) +{ + DPRINT("UhciSuspendController: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciResumeController(IN PVOID uhciExtension) +{ + DPRINT("UhciResumeController: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +BOOLEAN +NTAPI +UhciInterruptService(IN PVOID uhciExtension) +{ + DPRINT("UhciInterruptService: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciInterruptDpc(IN PVOID uhciExtension, + IN BOOLEAN IsDoEnableInterrupts) +{ + DPRINT("UhciInterruptDpc: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciSubmitTransfer(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN PVOID transferParameters, + IN PVOID uhciTransfer, + IN PVOID sgList) +{ + DPRINT("UhciSubmitTransfer: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciIsochTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PVOID transferParameters, + IN PVOID ehciTransfer, + IN PVOID isoParameters) +{ + DPRINT("UhciIsochTransfer: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciAbortTransfer(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN PVOID uhciTransfer, + IN PULONG CompletedLength) +{ + DPRINT("UhciAbortTransfer: UNIMPLEMENTED. FIXME\n"); +} + +ULONG +NTAPI +UhciGetEndpointState(IN PVOID uhciExtension, + IN PVOID uhciEndpoint) +{ + DPRINT("UhciGetEndpointState: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciSetEndpointState(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN ULONG EndpointState) +{ + DPRINT("UhciSetEndpointState: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciPollEndpoint(IN PVOID uhciExtension, + IN PVOID ohciEndpoint) +{ + DPRINT("UhciPollEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciCheckController(IN PVOID uhciExtension) +{ + DPRINT("UhciCheckController: UNIMPLEMENTED. FIXME\n"); +} + +ULONG +NTAPI +UhciGet32BitFrameNumber(IN PVOID uhciExtension) +{ + DPRINT("UhciGet32BitFrameNumber: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciInterruptNextSOF(IN PVOID uhciExtension) +{ + DPRINT("UhciInterruptNextSOF: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciEnableInterrupts(IN PVOID uhciExtension) +{ + DPRINT("UhciEnableInterrupts: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciDisableInterrupts(IN PVOID uhciExtension) +{ + DPRINT("UhciDisableInterrupts: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciPollController(IN PVOID uhciExtension) +{ + DPRINT("UhciPollController: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciSetEndpointDataToggle(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN ULONG DataToggle) +{ + DPRINT("UhciSetEndpointDataToggle: UNIMPLEMENTED. FIXME\n"); +} + +ULONG +NTAPI +UhciGetEndpointStatus(IN PVOID uhciExtension, + IN PVOID uhciEndpoint) +{ + DPRINT("UhciGetEndpointStatus: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciSetEndpointStatus(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN ULONG EndpointStatus) +{ + DPRINT("UhciSetEndpointStatus: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciResetController(IN PVOID uhciExtension) +{ + DPRINT("UhciResetController: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciStartSendOnePacket(IN PVOID uhciExtension, + IN PVOID PacketParameters, + IN PVOID Data, + IN PULONG pDataLength, + IN PVOID BufferVA, + IN PVOID BufferPA, + IN ULONG BufferLength, + IN USBD_STATUS * pUSBDStatus) +{ + DPRINT("UhciStartSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciEndSendOnePacket(IN PVOID uhciExtension, + IN PVOID PacketParameters, + IN PVOID Data, + IN PULONG pDataLength, + IN PVOID BufferVA, + IN PVOID BufferPA, + IN ULONG BufferLength, + IN USBD_STATUS * pUSBDStatus) +{ + DPRINT("UhciEndSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +MPSTATUS +NTAPI +UhciPassThru(IN PVOID uhciExtension, + IN PVOID passThruParameters, + IN ULONG ParameterLength, + IN PVOID pParameters) +{ + DPRINT("UhciPassThru: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciFlushInterrupts(IN PVOID uhciExtension) +{ + DPRINT("UhciFlushInterrupts: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciUnload(IN PVOID uhciExtension) +{ + DPRINT("UhciUnload: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + DPRINT("DriverEntry: DriverObject - %p, RegistryPath - %p\n", DriverObject, RegistryPath); + + RtlZeroMemory(&RegPacket, sizeof(USBPORT_REGISTRATION_PACKET)); + + RegPacket.MiniPortVersion = USB_MINIPORT_VERSION_UHCI; + + RegPacket.MiniPortFlags = USB_MINIPORT_FLAGS_INTERRUPT | + USB_MINIPORT_FLAGS_PORT_IO | + 0x40 | + USB_MINIPORT_FLAGS_POLLING | + USB_MINIPORT_FLAGS_WAKE_SUPPORT; + + RegPacket.MiniPortBusBandwidth = 12000; + + RegPacket.MiniPortExtensionSize = sizeof(UHCI_EXTENSION); + RegPacket.MiniPortEndpointSize = sizeof(UHCI_ENDPOINT); + RegPacket.MiniPortTransferSize = sizeof(UHCI_TRANSFER); + RegPacket.MiniPortResourcesSize = sizeof(UHCI_HC_RESOURCES); + + RegPacket.OpenEndpoint = UhciOpenEndpoint; + RegPacket.ReopenEndpoint = UhciReopenEndpoint; + RegPacket.QueryEndpointRequirements = UhciQueryEndpointRequirements; + RegPacket.CloseEndpoint = UhciCloseEndpoint; + RegPacket.StartController = UhciStartController; + RegPacket.StopController = UhciStopController; + RegPacket.SuspendController = UhciSuspendController; + RegPacket.ResumeController = UhciResumeController; + RegPacket.InterruptService = UhciInterruptService; + RegPacket.InterruptDpc = UhciInterruptDpc; + RegPacket.SubmitTransfer = UhciSubmitTransfer; + RegPacket.SubmitIsoTransfer = UhciIsochTransfer; + RegPacket.AbortTransfer = UhciAbortTransfer; + RegPacket.GetEndpointState = UhciGetEndpointState; + RegPacket.SetEndpointState = UhciSetEndpointState; + RegPacket.PollEndpoint = UhciPollEndpoint; + RegPacket.CheckController = UhciCheckController; + RegPacket.Get32BitFrameNumber = UhciGet32BitFrameNumber; + RegPacket.InterruptNextSOF = UhciInterruptNextSOF; + RegPacket.EnableInterrupts = UhciEnableInterrupts; + RegPacket.DisableInterrupts = UhciDisableInterrupts; + RegPacket.PollController = UhciPollController; + RegPacket.SetEndpointDataToggle = UhciSetEndpointDataToggle; + RegPacket.GetEndpointStatus = UhciGetEndpointStatus; + RegPacket.SetEndpointStatus = UhciSetEndpointStatus; + RegPacket.RH_GetRootHubData = UhciRHGetRootHubData; + RegPacket.RH_GetStatus = UhciRHGetStatus; + RegPacket.RH_GetPortStatus = UhciRHGetPortStatus; + RegPacket.RH_GetHubStatus = UhciRHGetHubStatus; + RegPacket.RH_SetFeaturePortReset = UhciRHSetFeaturePortReset; + RegPacket.RH_SetFeaturePortPower = UhciRHSetFeaturePortPower; + RegPacket.RH_SetFeaturePortEnable = UhciRHSetFeaturePortEnable; + RegPacket.RH_SetFeaturePortSuspend = UhciRHSetFeaturePortSuspend; + RegPacket.RH_ClearFeaturePortEnable = UhciRHClearFeaturePortEnable; + RegPacket.RH_ClearFeaturePortPower = UhciRHClearFeaturePortPower; + RegPacket.RH_ClearFeaturePortSuspend = UhciRHClearFeaturePortSuspend; + RegPacket.RH_ClearFeaturePortEnableChange = UhciRHClearFeaturePortEnableChange; + RegPacket.RH_ClearFeaturePortConnectChange = UhciRHClearFeaturePortConnectChange; + RegPacket.RH_ClearFeaturePortResetChange = UhciRHClearFeaturePortResetChange; + RegPacket.RH_ClearFeaturePortSuspendChange = UhciRHClearFeaturePortSuspendChange; + RegPacket.RH_ClearFeaturePortOvercurrentChange = UhciRHClearFeaturePortOvercurrentChange; + RegPacket.RH_DisableIrq = UhciRHEnableIrq; + RegPacket.RH_EnableIrq = UhciRHEnableIrq; + RegPacket.StartSendOnePacket = UhciStartSendOnePacket; + RegPacket.EndSendOnePacket = UhciEndSendOnePacket; + RegPacket.PassThru = UhciPassThru; + RegPacket.FlushInterrupts = UhciFlushInterrupts; + + DriverObject->DriverUnload = NULL; + + return USBPORT_RegisterUSBPortDriver(DriverObject, 100, &RegPacket); +} diff --git a/reactos/drivers/usb/usbuhci_new/usbuhci.h b/reactos/drivers/usb/usbuhci_new/usbuhci.h new file mode 100644 index 00000000000..2211f5ff755 --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/usbuhci.h @@ -0,0 +1,174 @@ +#ifndef USBUHCI_H__ +#define USBUHCI_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "..\usbmport.h" +#include "hardware.h" + +/* Host Controller Driver Transfer Descriptor (HCD TD) */ + +typedef struct _UHCI_HCD_TD { + /* Hardware */ + UHCI_TD HwTD; + /* Software */ + struct _UHCI_HCD_TD * PhysicalAddress; + ULONG Padded[11]; +} UHCI_HCD_TD, *PUHCI_HCD_TD; + +C_ASSERT(sizeof(UHCI_HCD_TD) == 0x40); + +/* Host Controller Driver Queue Header (HCD QH) */ + +typedef struct _UHCI_HCD_QH { + /* Hardware */ + UHCI_QH HwQH; + /* Software */ + struct _UHCI_HCD_QH * PhysicalAddress; + ULONG Padded[13]; +} UHCI_HCD_QH, *PUHCI_HCD_QH; + +C_ASSERT(sizeof(UHCI_HCD_QH) == 0x40); + +typedef struct _UHCI_ENDPOINT { + ULONG Reserved; +} UHCI_ENDPOINT, *PUHCI_ENDPOINT; + +typedef struct _UHCI_TRANSFER { + ULONG Reserved; +} UHCI_TRANSFER, *PUHCI_TRANSFER; + +typedef struct _UHCI_HC_RESOURCES { + UCHAR Padded[0x2000]; +} UHCI_HC_RESOURCES, *PUHCI_HC_RESOURCES; + +typedef struct _UHCI_EXTENSION { + ULONG Reserved; +} UHCI_EXTENSION, *PUHCI_EXTENSION; + +extern USBPORT_REGISTRATION_PACKET RegPacket; + +/* roothub.c */ + +VOID +NTAPI +UhciRHGetRootHubData( + IN PVOID uhciExtension, + IN PVOID rootHubData); + +MPSTATUS +NTAPI +UhciRHGetStatus( + IN PVOID uhciExtension, + IN PUSHORT Status); + +MPSTATUS +NTAPI +UhciRHGetPortStatus( + IN PVOID uhciExtension, + IN USHORT Port, + IN PULONG PortStatus); + +MPSTATUS +NTAPI +UhciRHGetHubStatus( + IN PVOID uhciExtension, + IN PULONG HubStatus); + +MPSTATUS +NTAPI +UhciRHSetFeaturePortReset( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHSetFeaturePortPower( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHSetFeaturePortEnable( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHSetFeaturePortSuspend( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortEnable( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortPower( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortSuspend( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortEnableChange( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortConnectChange( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortResetChange( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortSuspendChange( + IN PVOID uhciExtension, + IN USHORT Port); + +MPSTATUS +NTAPI +UhciRHClearFeaturePortOvercurrentChange( + IN PVOID uhciExtension, + IN USHORT Port); + +VOID +NTAPI +UhciRHDisableIrq( + IN PVOID uhciExtension); + +VOID +NTAPI +UhciRHEnableIrq( + IN PVOID uhciExtension); + +/* usbuhci.c */ + +NTSTATUS +NTAPI +USBPORT_RegisterUSBPortDriver( + IN PDRIVER_OBJECT DriverObject, + IN ULONG Version, + IN PVOID RegistrationPacket); + +#endif /* USBUHCI_H__ */ diff --git a/reactos/drivers/usb/usbuhci_new/usbuhci.rc b/reactos/drivers/usb/usbuhci_new/usbuhci.rc new file mode 100644 index 00000000000..801d5be7368 --- /dev/null +++ b/reactos/drivers/usb/usbuhci_new/usbuhci.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "USB UHCI miniport driver" +#define REACTOS_STR_INTERNAL_NAME "usbuhci" +#define REACTOS_STR_ORIGINAL_FILENAME "usbuhci.sys" +#include diff --git a/reactos/sdk/lib/drivers/hidparser/api.c b/reactos/sdk/lib/drivers/hidparser/api.c index d4eb327a9a4..2085fe07bc3 100644 --- a/reactos/sdk/lib/drivers/hidparser/api.c +++ b/reactos/sdk/lib/drivers/hidparser/api.c @@ -539,7 +539,7 @@ HidParser_GetUsagesWithReport( return HIDPARSER_STATUS_SUCCESS; } -ULONG +BOOLEAN HidParser_UsesReportId( IN PVOID CollectionContext, IN UCHAR ReportType) @@ -565,6 +565,26 @@ HidParser_UsesReportId( } +UCHAR +HidParser_GetReportId( + IN PVOID CollectionContext, + IN UCHAR ReportType) +{ + PHID_REPORT Report; + + /* get report */ + Report = HidParser_GetReportInCollection(CollectionContext, ReportType); + + if (!Report) + { + /* no such report */ + return 0; + } + + /* returns report id */ + return Report->ReportID; +} + HIDPARSER_STATUS HidParser_GetUsageValueWithReport( IN PHID_PARSER Parser, diff --git a/reactos/sdk/lib/drivers/hidparser/hidparser.c b/reactos/sdk/lib/drivers/hidparser/hidparser.c index 6e9d4ef6fdd..ba1c5a79c8b 100644 --- a/reactos/sdk/lib/drivers/hidparser/hidparser.c +++ b/reactos/sdk/lib/drivers/hidparser/hidparser.c @@ -57,6 +57,7 @@ HidParser_GetCollectionDescription( ULONG CollectionCount; ULONG Index; PVOID ParserContext; + BOOLEAN IsUsesReportId = FALSE; // // first parse the report descriptor @@ -135,12 +136,42 @@ HidParser_GetCollectionDescription( // init report description // DeviceDescription->ReportIDs[Index].CollectionNumber = Index + 1; - DeviceDescription->ReportIDs[Index].ReportID = Index; //FIXME + + if (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT) || + HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT) || + HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE)) + { + IsUsesReportId = TRUE; + } + + if (IsUsesReportId) + { + UCHAR ReportId = 0; + + ReportId = HidParser_GetReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT); + + if (!ReportId) + { + ReportId = HidParser_GetReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT); + + if (!ReportId) + { + ReportId = HidParser_GetReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE); + } + } + + ASSERT(ReportId); + DeviceDescription->ReportIDs[Index].ReportID = ReportId; + } + else + { + DeviceDescription->ReportIDs[Index].ReportID = Index; + } + DeviceDescription->ReportIDs[Index].InputLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT); DeviceDescription->ReportIDs[Index].OutputLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT); DeviceDescription->ReportIDs[Index].FeatureLength = HidParser_GetReportLength((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE); - DeviceDescription->ReportIDs[Index].InputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_INPUT) ? 1 : 0); DeviceDescription->ReportIDs[Index].OutputLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_OUTPUT) ? 1 : 0); DeviceDescription->ReportIDs[Index].FeatureLength += (HidParser_UsesReportId((PVOID)DeviceDescription->CollectionDesc[Index].PreparsedData, HID_REPORT_TYPE_FEATURE) ? 1 : 0); @@ -298,7 +329,7 @@ HidParser_MaxUsageListLength( // // implement me // - UNIMPLEMENTED + UNIMPLEMENTED; // // invalid report @@ -899,7 +930,7 @@ HidParser_GetSpecificButtonCaps( OUT PHIDP_BUTTON_CAPS ButtonCaps, IN OUT PULONG ButtonCapsLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -917,7 +948,7 @@ HidParser_GetData( IN PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -933,7 +964,7 @@ HidParser_GetExtendedAttributes( OUT PHIDP_EXTENDED_ATTRIBUTES Attributes, IN OUT PULONG LengthAttributes) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -947,7 +978,7 @@ HidParser_GetLinkCollectionNodes( OUT PHIDP_LINK_COLLECTION_NODE LinkCollectionNodes, IN OUT PULONG LinkCollectionNodesLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1025,7 +1056,7 @@ HidParser_SysPowerEvent( IN USHORT HidPacketLength, OUT PULONG OutputBuffer) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1037,7 +1068,7 @@ HidParser_SysPowerCaps ( IN PVOID CollectionContext, OUT PULONG OutputBuffer) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1057,7 +1088,7 @@ HidParser_GetUsageValueArray( IN PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1076,7 +1107,7 @@ HidParser_UnsetUsages( IN OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1092,7 +1123,7 @@ HidParser_TranslateUsagesToI8042ScanCodes( IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, IN PVOID InsertCodesContext) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1111,7 +1142,7 @@ HidParser_SetUsages( IN OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1131,7 +1162,7 @@ HidParser_SetUsageValueArray( OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1150,7 +1181,7 @@ HidParser_SetUsageValue( IN OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1169,7 +1200,7 @@ HidParser_SetScaledUsageValue( IN OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1186,7 +1217,7 @@ HidParser_SetData( IN OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1199,7 +1230,7 @@ HidParser_MaxDataListLength( IN PVOID CollectionContext, IN HIDP_REPORT_TYPE ReportType) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return 0; } @@ -1215,7 +1246,7 @@ HidParser_InitializeReportForID( IN OUT PCHAR Report, IN ULONG ReportLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } @@ -1232,7 +1263,7 @@ HidParser_GetValueCaps( PHIDP_VALUE_CAPS ValueCaps, PULONG ValueCapsLength) { - UNIMPLEMENTED + UNIMPLEMENTED; ASSERT(FALSE); return STATUS_NOT_IMPLEMENTED; } diff --git a/reactos/sdk/lib/drivers/hidparser/parser.h b/reactos/sdk/lib/drivers/hidparser/parser.h index 1a8f0ce49f7..5656b39317d 100644 --- a/reactos/sdk/lib/drivers/hidparser/parser.h +++ b/reactos/sdk/lib/drivers/hidparser/parser.h @@ -260,7 +260,12 @@ typedef struct #define HID_REPORT_TYPE_OUTPUT 0x02 #define HID_REPORT_TYPE_FEATURE 0x04 -ULONG +UCHAR +HidParser_GetReportId( + IN PVOID CollectionContext, + IN UCHAR ReportType); + +BOOLEAN HidParser_UsesReportId( IN PVOID CollectionContext, IN UCHAR ReportType); diff --git a/usbhub.sys.zip b/usbhub.sys.zip new file mode 100644 index 0000000000000000000000000000000000000000..4efbfada50e510cf9fa2a77a00016c51a1e3c383 GIT binary patch literal 41507 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