From e7623cbfc6d4cd646ca5bb833975daa7bc072d0c Mon Sep 17 00:00:00 2001 From: Nikita Krapivin Date: Sat, 18 Aug 2018 21:44:39 +0500 Subject: [PATCH] Apply all Vadim Galyant non-merged patches --- base/setup/usetup/usetup.c | 26 + boot/bootdata/hivesys.inf | 4 +- boot/bootdata/txtsetup.sif | 37 +- boot/freeldr/freeldr/ntldr/setupldr.c | 80 + drivers/hid/hidclass/fdo.c | 2670 +++++++++++++++++++---- drivers/hid/hidclass/hidclass.c | 1770 ++++++++++----- drivers/hid/hidclass/pdo.c | 923 ++++++-- drivers/hid/hidclass/precomp.h | 344 ++- drivers/hid/hidusb/hidusb.c | 650 +++--- drivers/hid/hidusb/hidusb.h | 11 + drivers/hid/hidusb/hidusb.rc | 2 +- drivers/hid/kbdhid/kbdhid.c | 3 +- drivers/hid/mouhid/mouhid.c | 13 +- drivers/usb/CMakeLists.txt | 18 +- drivers/usb/usbccgp/pdo.c | 7 + drivers/usb/usbehci_new/CMakeLists.txt | 16 + drivers/usb/usbehci_new/dbg_ehci.h | 44 + drivers/usb/usbehci_new/debug.c | 37 + drivers/usb/usbehci_new/guid.c | 9 + drivers/usb/usbehci_new/hardware.h | 405 ++++ drivers/usb/usbehci_new/roothub.c | 702 ++++++ drivers/usb/usbehci_new/usbehci.c | 3699 ++++++++++++++++++++++++++++++++ drivers/usb/usbehci_new/usbehci.h | 318 +++ drivers/usb/usbehci_new/usbehci.rc | 5 + drivers/usb/usbhub_new/CMakeLists.txt | 1 + drivers/usb/usbhub_new/blacklst.c | 963 +++++++++ drivers/usb/usbhub_new/pnp.c | 56 +- drivers/usb/usbhub_new/usbhub.h | 7 + drivers/usb/usbport/pnp.c | 2 +- drivers/usb/usbstor_new/CMakeLists.txt | 2 +- drivers/usb/usbstor_new/disk.c | 148 +- drivers/usb/usbstor_new/error.c | 425 ++-- drivers/usb/usbstor_new/fdo.c | 227 +- drivers/usb/usbstor_new/misc.c | 8 +- drivers/usb/usbstor_new/pdo.c | 566 ++--- drivers/usb/usbstor_new/queue.c | 54 +- drivers/usb/usbstor_new/scsi.c | 1657 ++++++-------- drivers/usb/usbstor_new/usbstor.c | 61 +- drivers/usb/usbstor_new/usbstor.h | 263 ++- drivers/usb/usbuhci_new/CMakeLists.txt | 15 + drivers/usb/usbuhci_new/dbg_uhci.h | 49 + drivers/usb/usbuhci_new/guid.c | 9 + drivers/usb/usbuhci_new/hardware.h | 218 ++ drivers/usb/usbuhci_new/roothub.c | 472 ++++ drivers/usb/usbuhci_new/usbuhci.c | 2791 ++++++++++++++++++++++++ drivers/usb/usbuhci_new/usbuhci.h | 297 +++ drivers/usb/usbuhci_new/usbuhci.rc | 5 + hal/halx86/acpi/halpnpdd.c | 2 +- hal/halx86/legacy/halpnpdd.c | 2 +- ntoskrnl/include/internal/io.h | 4 +- ntoskrnl/io/iomgr/iomgr.c | 51 +- ntoskrnl/io/pnpmgr/pnpinit.c | 251 ++- ntoskrnl/io/pnpmgr/pnpmgr.c | 751 +++++-- sdk/lib/drivers/hidparser/api.c | 22 +- sdk/lib/drivers/hidparser/hidparser.c | 35 +- sdk/lib/drivers/hidparser/parser.h | 7 +- 56 files changed, 17741 insertions(+), 3473 deletions(-) create mode 100644 drivers/usb/usbehci_new/CMakeLists.txt create mode 100644 drivers/usb/usbehci_new/dbg_ehci.h create mode 100644 drivers/usb/usbehci_new/debug.c create mode 100644 drivers/usb/usbehci_new/guid.c create mode 100644 drivers/usb/usbehci_new/hardware.h create mode 100644 drivers/usb/usbehci_new/roothub.c create mode 100644 drivers/usb/usbehci_new/usbehci.c create mode 100644 drivers/usb/usbehci_new/usbehci.h create mode 100644 drivers/usb/usbehci_new/usbehci.rc create mode 100644 drivers/usb/usbhub_new/blacklst.c create mode 100644 drivers/usb/usbuhci_new/CMakeLists.txt create mode 100644 drivers/usb/usbuhci_new/dbg_uhci.h create mode 100644 drivers/usb/usbuhci_new/guid.c create mode 100644 drivers/usb/usbuhci_new/hardware.h create mode 100644 drivers/usb/usbuhci_new/roothub.c create mode 100644 drivers/usb/usbuhci_new/usbuhci.c create mode 100644 drivers/usb/usbuhci_new/usbuhci.h create mode 100644 drivers/usb/usbuhci_new/usbuhci.rc diff --git a/base/setup/usetup/usetup.c b/base/setup/usetup/usetup.c index 1a7940c..5251ed9 100644 --- a/base/setup/usetup/usetup.c +++ b/base/setup/usetup/usetup.c @@ -4651,6 +4651,7 @@ RunUSetup(VOID) NTSTATUS Status; BOOLEAN Old; + DPRINT("RunUSetup: ... \n"); NtQuerySystemTime(&Time); /* Create the PnP thread in suspended state */ @@ -4704,11 +4705,23 @@ RunUSetup(VOID) { /* Start page */ case START_PAGE: + DPRINT("RunUSetup: START_PAGE\n"); Page = SetupStartPage(&Ir); +#if 1 +{ + LARGE_INTEGER Timeout; + Timeout.QuadPart = 5000LL; // 5 sec + DPRINT("Waiting %lu milliseconds (START_PAGE)\n", Timeout.LowPart); + Timeout.QuadPart *= -10000LL; // convert to 100 ns units (absolute) + NtDelayExecution(FALSE, &Timeout); + DPRINT("End Waiting (START_PAGE)\n"); +} +#endif break; /* Language page */ case LANGUAGE_PAGE: + DPRINT("RunUSetup: LANGUAGE_PAGE\n"); Page = LanguagePage(&Ir); break; @@ -4868,6 +4881,19 @@ RunUSetup(VOID) VOID NTAPI NtProcessStartup(PPEB Peb) { + DPRINT("NtProcessStartup: \n"); + +#if 1 +{ + LARGE_INTEGER Timeout; + Timeout.QuadPart = 5000LL; // 5 sec + DPRINT("Waiting %lu milliseconds (NtProcessStartup)\n", Timeout.LowPart); + Timeout.QuadPart *= -10000LL; // convert to 100 ns units (absolute) + NtDelayExecution(FALSE, &Timeout); + DPRINT("End Waiting (NtProcessStartup)\n"); +} +#endif + RtlNormalizeProcessParams(Peb->ProcessParameters); ProcessHeap = Peb->ProcessHeap; diff --git a/boot/bootdata/hivesys.inf b/boot/bootdata/hivesys.inf index 31f50ed..bacf91b 100644 --- a/boot/bootdata/hivesys.inf +++ b/boot/bootdata/hivesys.inf @@ -38,8 +38,8 @@ HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#Class_08&SubCl HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#COMPOSITE","Service",0x00000000,"usbccgp" HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#COMPOSITE","ClassGUID",0x00000000,"{36FC9E60-C465-11CF-8056-444553540000}" -;HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#CLASS_09","Service",0x00000000,"usbhub" -;HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#CLASS_09","ClassGUID",0x00000000,"{36FC9E60-C465-11CF-8056-444553540000}" +HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#CLASS_09","Service",0x00000000,"usbhub" +HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#CLASS_09","ClassGUID",0x00000000,"{36FC9E60-C465-11CF-8056-444553540000}" HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#ROOT_HUB","Service",0x00000000,"usbhub" HKLM,"SYSTEM\CurrentControlSet\Control\CriticalDeviceDatabase\USB#ROOT_HUB","ClassGUID",0x00000000,"{36FC9E60-C465-11CF-8056-444553540000}" diff --git a/boot/bootdata/txtsetup.sif b/boot/bootdata/txtsetup.sif index fc2aa63..45dcc71 100644 --- a/boot/bootdata/txtsetup.sif +++ b/boot/bootdata/txtsetup.sif @@ -48,11 +48,12 @@ usbhub.sys=,,,,,,x,,,,,,4 usbuhci.sys=,,,,,,x,,,,,,4 usbohci.sys=,,,,,,x,,,,,,4 usbehci.sys=,,,,,,x,,,,,,4 +usbport.sys=,,,,,,,,,,,,4 usbstor.sys=,,,,,,x,,,,,,4 kbdhid.sys=,,,,,,,,,,,,4 kbdclass.sys=,,,,,,x,,,,,,4 l_intl.nls=,,,,,,,,,,,,2 -pci.sys=,,,,,,,,,,,,4 +pci.sys=,,,,,,x,,,,,,4 scsiport.sys=,,,,,,x,,,,,,4 storport.sys=,,,,,,x,,,,,,4 fastfat.sys=,,,,,,x,,,,,,4 @@ -84,7 +85,7 @@ PCI\CC_0105 = uniata PCI\CC_0106 = uniata ;PCI\CC_0106 = storahci *PNP0600 = uniata -;USB\CLASS_09 = usbhub +USB\CLASS_09 = usbhub USB\ROOT_HUB = usbhub USB\ROOT_HUB20 = usbhub PCI\CC_0C0300 = usbuhci @@ -92,11 +93,30 @@ PCI\CC_0C0310 = usbohci PCI\CC_0C0320 = usbehci USB\Class_08&SubClass_06&Prot_50 = usbstor HID_DEVICE_SYSTEM_KEYBOARD = kbdhid,{4D36E96B-E325-11CE-BFC1-08002BE10318} +HID_DEVICE_SYSTEM_MOUSE = mouhid,{4D36E96F-E325-11CE-BFC1-08002BE10318} USB\COMPOSITE = usbccgp GenDisk = disk USB\Class_03 = hidusb GENERIC_HID_DEVICE = hidusb +*PNP0300 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0301 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0302 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} *PNP0303 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0304 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0305 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0306 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0309 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP030a = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP030b = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0320 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*CPQA0D7 = i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +PS2_KEYBOARD= i8042prt,{4D36E96B-E325-11CE-BFC1-08002BE10318} +*PNP0F03 = i8042prt,{4D36E96F-E325-11CE-BFC1-08002BE10318} +*PNP0F0B = i8042prt,{4D36E96F-E325-11CE-BFC1-08002BE10318} +*PNP0F0E = i8042prt,{4D36E96F-E325-11CE-BFC1-08002BE10318} +*PNP0F12 = i8042prt,{4D36E96F-E325-11CE-BFC1-08002BE10318} +*PNP0F13 = i8042prt,{4D36E96F-E325-11CE-BFC1-08002BE10318} +PS2_MOUSE= i8042prt,{4D36E96F-E325-11CE-BFC1-08002BE10318} ROOT\SWENUM = swenum [BootBusExtenders.Load] @@ -105,9 +125,9 @@ pci = pci.sys isapnp = isapnp.sys [InputDevicesSupport.Load] -usbehci = usbehci.sys -usbohci = usbohci.sys -usbuhci = usbuhci.sys +;usbehci = usbehci.sys +;usbohci = usbohci.sys +;usbuhci = usbuhci.sys usbhub = usbhub.sys usbccgp = usbccgp.sys hidusb = hidusb.sys @@ -117,8 +137,15 @@ usbstor = usbstor.sys kbdhid = kbdhid.sys i8042prt = i8042prt.sys +[MouseDrivers.Load] +mouclass = mouclass.sys +mouhid = mouhid.sys + [BusExtenders.Load] pciide = pciide.sys +usbehci = usbehci.sys +usbohci = usbohci.sys +usbuhci = usbuhci.sys [SCSI.Load] uniata = uniata.sys diff --git a/boot/freeldr/freeldr/ntldr/setupldr.c b/boot/freeldr/freeldr/ntldr/setupldr.c index 20fc1b6..f74122c 100644 --- a/boot/freeldr/freeldr/ntldr/setupldr.c +++ b/boot/freeldr/freeldr/ntldr/setupldr.c @@ -27,6 +27,7 @@ DBG_DEFAULT_CHANNEL(WINDOWS); #define TAG_BOOT_OPTIONS 'pOtB' +#define TAG_HARDWARE_ID 'dIwH' void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock); @@ -133,6 +134,82 @@ SetupLdrScanBootDrivers(PLIST_ENTRY BootDriverListHead, HINF InfHandle, LPCSTR S } while (InfFindNextLine(&InfContext, &InfContext)); } +static VOID +SetupLdrLoadHardwareIdsDatabase(PSETUP_LOADER_BLOCK SetupBlock, HINF InfHandle, LPCSTR SearchPath) +{ + INFCONTEXT InfContext; + LPCSTR Id; + LPCSTR DriverName; + SIZE_T Size; + PVOID Temp; + PPNP_HARDWARE_ID HardwareId; + PPNP_HARDWARE_ID HeadHardwareId; + PPNP_HARDWARE_ID LastHardwareId = 0; + + /* + typedef struct _PNP_HARDWARE_ID + { + struct _PNP_HARDWARE_ID *Next; + PCHAR Id; + PCHAR DriverName; + PCHAR ClassGuid; + } PNP_HARDWARE_ID, *PPNP_HARDWARE_ID; + */ + + /* Open inf section */ + if (!InfFindFirstLine(InfHandle, "HardwareIdsDatabase", NULL, &InfContext)) + return; + + /* Load all HardwareIds */ + do + { + if (InfGetDataField(&InfContext, 0, &Id) && + InfGetDataField(&InfContext, 1, &DriverName)) + { + /* Allocate and initialize the new struct _PNP_HARDWARE_ID */ + Size = sizeof(PNP_HARDWARE_ID); + HardwareId = FrLdrHeapAlloc(Size, TAG_HARDWARE_ID); + if (HardwareId == NULL) + return; + + memset(HardwareId, 0, Size); + + /* For link field */ + if(LastHardwareId) + LastHardwareId->Next = (PPNP_HARDWARE_ID)((ULONG)HardwareId | 0x80000000); + else + HeadHardwareId = (PPNP_HARDWARE_ID)((ULONG)HardwareId | 0x80000000); //first record + + /* DPRINT */ + //ERR("SetupLdrLoadHardwareIdsDatabase: HardwareId - %p\n", HardwareId); + + LastHardwareId = HardwareId; + + /* Allocate and copy name Id */ + Size = strlen(Id) + 1; + Temp = FrLdrHeapAlloc(Size, TAG_HARDWARE_ID); + if (Temp == NULL) + return; + + memmove(Temp, Id, Size); + + HardwareId->Id = (PCHAR)((ULONG)Temp | 0x80000000); + + /* Allocate and copy driver name */ + Size = strlen(DriverName) + 1; + Temp = FrLdrHeapAlloc(Size, TAG_HARDWARE_ID); + if (Temp == NULL) + return; + + memmove(Temp, DriverName, Size); + + HardwareId->DriverName = (PCHAR)((ULONG)Temp | 0x80000000); + } + } while (InfFindNextLine(&InfContext, &InfContext)); + + SetupBlock->HardwareIdDatabase = (PPNP_HARDWARE_ID)((ULONG)HeadHardwareId | 0x80000000); +} + VOID LoadReactOSSetup(IN OperatingSystemItem* OperatingSystem, IN USHORT OperatingSystemVersion) @@ -328,6 +405,9 @@ LoadReactOSSetup(IN OperatingSystemItem* OperatingSystem, /* Get a list of boot drivers */ SetupLdrScanBootDrivers(&LoaderBlock->BootDriverListHead, InfHandle, BootPath); + /* Load HardwareIds Database */ + SetupLdrLoadHardwareIdsDatabase(SetupBlock, InfHandle, BootPath); + /* Close the inf file */ InfCloseFile(InfHandle); diff --git a/drivers/hid/hidclass/fdo.c b/drivers/hid/hidclass/fdo.c index 8ea6590..0dc80cc 100644 --- a/drivers/hid/hidclass/fdo.c +++ b/drivers/hid/hidclass/fdo.c @@ -13,48 +13,1523 @@ #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) + { + for (Idx = 0; Idx < DeviceDescription->CollectionDescLength; ++Idx) + { + 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"); + } + } + + if (DeviceDescription->ReportIDsLength) + { + for (Idx = 0; Idx < DeviceDescription->ReportIDsLength; ++Idx) + { + 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"); + } + } +} + +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); + + if (Entry) + { + ExFreePoolWithTag(Entry, HIDCLASS_TAG); + } + + FileContext->PendingReports--; + } + + InsertTailList(&FileContext->ReportList, &Header->ReportLink); + + FileContext->PendingReports++; +} + +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; + + while (!IsListEmpty(ReadIrpList)) + { + // + // dequeue and get the IRP + // + Entry = RemoveHeadList(ReadIrpList); + Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); + + if (IoSetCancelRoutine(Irp, NULL)) + { + HidCollection->NumPendingReads--; + } + else + { + InitializeListHead(Entry); + break; + } + } + + 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) + { + for (Idx = 0; Idx < NumCollections; ++Idx) + { + if (CollectionDescArray[Idx].CollectionNumber == CollectionNumber) + { + HidCollectionDesc = &CollectionDescArray[Idx]; + break; + } + } + } + } + + 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) + { + NumCollections = FDODeviceExtension->Common.DeviceDescription.CollectionDescLength; + + if (NumCollections) + { + for (Idx = 0; Idx < NumCollections; ++Idx) + { + if (HidCollections[Idx].CollectionNumber == CollectionNumber) + { + HidCollection = &HidCollections[Idx]; + break; + } + } + } + } + + 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; + + if (NumCollections) + { + for (Idx = 0; Idx < NumCollections; ++Idx) + { + if (ReportIDs[Idx].ReportID == Id) + { + Result = &ReportIDs[Idx]; + break; + } + } + } + } + + return Result; +} + +PHIDCLASS_SHUTTLE +NTAPI +GetShuttleFromIrp( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN PIRP Irp) +{ + ULONG ShuttleCount; + ULONG Idx; + PHIDCLASS_SHUTTLE Shuttle; + PHIDCLASS_SHUTTLE Result = NULL; + + ShuttleCount = FDODeviceExtension->ShuttleCount; + + if (ShuttleCount) + { + Shuttle = &FDODeviceExtension->Shuttles[0]; + + for (Idx = 0; Idx < ShuttleCount; ++Idx) + { + if (Shuttle[Idx].ShuttleIrp == Irp) + { + Result = &Shuttle[Idx]; + break; + } + } + } + + 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; + PHIDCLASS_COLLECTION HidCollection; + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; + FDODeviceExtension->MaxReportSize = 0; + + if (DeviceDescription->ReportIDsLength) + { + for (Idx = 0; Idx < DeviceDescription->ReportIDsLength; ++Idx) + { + ReportId = &DeviceDescription->ReportIDs[Idx]; + + HidCollection = GetHidclassCollection(FDODeviceExtension, + ReportId->CollectionNumber); + + if (HidCollection) + { + FDODeviceExtension->MaxReportSize = max(FDODeviceExtension->MaxReportSize, + ReportId->InputLength); + } + } + } + + DPRINT("HidClassSetMaxReportSize: ReportIDsLength - %x, MaxReportSize - %x\n", + DeviceDescription->ReportIDsLength, + 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] Collection descriptor not found\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 = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, + NormalPagePriority); + + 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 (!IsListEmpty(&IrpList)) + { + Entry = 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; + + InterlockedDecrement(&FDODeviceExtension->OutstandingRequests); + + 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], Report[1], Report[2], Report[3], Report[4], Report[5], Report[6], Report[7]); + + 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) + { + goto NextData; + } + + PDODeviceExtension = ClientPdoExtensions[HidCollection->CollectionIdx]; + + if (!PDODeviceExtension) + { + goto NextData; + } + + if (PDODeviceExtension == NULL || + 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.QuadPart = (LONGLONG)-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 the 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 (NT_SUCCESS(Status)); + + // + // 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; + BOOLEAN IsSending; + + DPRINT("HidClassAllShuttlesStart: ShuttleCount - %x\n", + FDODeviceExtension->ShuttleCount); + + if (!(FDODeviceExtension->ShuttleCount)) + { + DPRINT1("ShuttleCount is 0\n"); + return Status; + } + + for (ix = 0; ix < FDODeviceExtension->ShuttleCount; ++ix) + { + // + // 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; + } + } + } + + 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; + } +} + + for (ix = 0; ix < FDODeviceExtension->ShuttleCount; ++ix) + { + Shuttle = &FDODeviceExtension->Shuttles[ix]; + + InterlockedIncrement(&Shuttle->CancellingShuttle); + + KeWaitForSingleObject(&Shuttle->ShuttleEvent, + Executive, + KernelMode, + FALSE, + NULL); + + IoCancelIrp(Shuttle->ShuttleIrp); + + KeWaitForSingleObject(&Shuttle->ShuttleDoneEvent, + Executive, + KernelMode, + FALSE, + NULL); + + InterlockedDecrement(&Shuttle->CancellingShuttle); + } + } + + 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) + { + HidClassCancelAllShuttleIrps(FDODeviceExtension); + + if (FDODeviceExtension->ShuttleCount) + { + for (ix = 0; ix < FDODeviceExtension->ShuttleCount; ++ix) + { + DPRINT("HidClassDestroyShuttles: Free ShuttleIrp - %p\n", + FDODeviceExtension->Shuttles[ix].ShuttleIrp); + + IoFreeIrp(FDODeviceExtension->Shuttles[ix].ShuttleIrp); + ExFreePoolWithTag(FDODeviceExtension->Shuttles[ix].ShuttleBuffer, + HIDCLASS_TAG); + } + } + + ExFreePoolWithTag(FDODeviceExtension->Shuttles, HIDCLASS_TAG); + FDODeviceExtension->Shuttles = NULL; + } +} + +VOID +NTAPI +HidClassShuttleTimerDpc( + IN KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PHIDCLASS_SHUTTLE Shuttle; + LONGLONG TimerValue; + BOOLEAN IsSending; + + Shuttle = (PHIDCLASS_SHUTTLE)DeferredContext; + TimerValue = Shuttle->TimerPeriod.QuadPart; + + if (TimerValue > (LONGLONG)(-5000 * 10000)) + { + Shuttle->TimerPeriod.QuadPart = TimerValue - (LONGLONG)(1000 * 10000); + } + + HidClassSubmitInterruptRead(Shuttle->FDODeviceExtension, + Shuttle, + &IsSending); +} + +NTSTATUS +NTAPI +HidClassInitializeShuttleIrps( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension) +{ + PHIDCLASS_SHUTTLE Shuttles; + PIRP Irp; + SIZE_T NumberOfBytes; + ULONG ix; + + DPRINT("HidClassInitializeShuttleIrps: ... \n"); + + if (!FDODeviceExtension->ShuttleCount) + { + DPRINT("[HIDCLASS] FDODeviceExtension->ShuttleCount - 0\n"); + return STATUS_SUCCESS; + } + + Shuttles = ExAllocatePoolWithTag(NonPagedPool, + FDODeviceExtension->ShuttleCount * sizeof(HIDCLASS_SHUTTLE), + HIDCLASS_TAG); + + FDODeviceExtension->Shuttles = Shuttles; + + if (!Shuttles) + { + DPRINT1("[HIDCLASS] Allocating shuttles failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NumberOfBytes = FDODeviceExtension->MaxReportSize; + + RtlZeroMemory(Shuttles, + FDODeviceExtension->ShuttleCount * sizeof(HIDCLASS_SHUTTLE)); + + for (ix = 0; ix < FDODeviceExtension->ShuttleCount; ++ix) + { + FDODeviceExtension->Shuttles[ix].FDODeviceExtension = FDODeviceExtension; + FDODeviceExtension->Shuttles[ix].CancellingShuttle = 0; + FDODeviceExtension->Shuttles[ix].TimerPeriod.QuadPart = (LONGLONG)(-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] Allocating shuttle buffer failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Irp = IoAllocateIrp(FDODeviceExtension->FDODeviceObject->StackSize - 1, + FALSE); + + if (!Irp) + { + DPRINT1("[HIDCLASS] Allocating shuttle IRP failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + 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); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HidClassFDO_QueryCapabilitiesCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + // + // set event + // + KeSetEvent(Context, 0, FALSE); + + // + // completion is done in the HidClassFDO_QueryCapabilities routine + // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +HidClassFDO_QueryCapabilities( + IN PDEVICE_OBJECT DeviceObject, + IN OUT PDEVICE_CAPABILITIES Capabilities) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + PIO_STACK_LOCATION IoStack; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + + // + // get device extension + // + FDODeviceExtension = DeviceObject->DeviceExtension; + ASSERT(FDODeviceExtension->Common.IsFDO); + + // + // init event + // + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + // + // now allocate the irp + // + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // get next stack location + // + IoStack = IoGetNextIrpStackLocation(Irp); + + // + // init stack location + // + IoStack->MajorFunction = IRP_MJ_PNP; + IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; + IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities; + + // + // set completion routine + // + IoSetCompletionRoutine(Irp, HidClassFDO_QueryCapabilitiesCompletionRoutine, &Event, TRUE, TRUE, TRUE); + + // + // init capabilities + // + RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES)); + Capabilities->Size = sizeof(DEVICE_CAPABILITIES); + Capabilities->Version = 1; // FIXME hardcoded constant + Capabilities->Address = MAXULONG; + Capabilities->UINumber = MAXULONG; + + // + // pnp irps have default completion code + // + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + // + // call lower device + // + Status = IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + // + // wait for completion + // + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + } + + // + // get status + // + Status = Irp->IoStatus.Status; + + // + // complete request + // + IoFreeIrp(Irp); + + // + // done + // + return Status; +} + NTSTATUS NTAPI -HidClassFDO_QueryCapabilitiesCompletionRoutine( +HidClassFDO_DispatchRequestSynchronousCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { // - // set event + // signal event // KeSetEvent(Context, 0, FALSE); // - // completion is done in the HidClassFDO_QueryCapabilities routine + // done // return STATUS_MORE_PROCESSING_REQUIRED; } + NTSTATUS -HidClassFDO_QueryCapabilities( +HidClassFDO_DispatchRequestSynchronous( IN PDEVICE_OBJECT DeviceObject, - IN OUT PDEVICE_CAPABILITIES Capabilities) + IN PIRP Irp) { - PIRP Irp; KEVENT Event; NTSTATUS Status; + LARGE_INTEGER Timeout = {{0, 0}}; + + // + // init event + // + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + // + // set completion routine + // + IoSetCompletionRoutine(Irp, + HidClassFDO_DispatchRequestSynchronousCompletion, + &Event, + TRUE, + TRUE, + TRUE); + + // + // send request + // + Status = HidClassFDO_DispatchRequest(DeviceObject, Irp); + + if (Status != STATUS_PENDING) + { + return Status; + } + + Timeout.QuadPart -= (LONGLONG)(5000 * 10000); // (5 sec.) + + // + // Status == STATUS_PENDING + // + if (KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + &Timeout) != STATUS_TIMEOUT) + { + return Irp->IoStatus.Status; + } + + // + // 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; +} + +NTSTATUS +HidClassFDO_DispatchRequest( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + NTSTATUS Status; PIO_STACK_LOCATION IoStack; - PHIDCLASS_FDO_EXTENSION FDODeviceExtension; // // get device extension // - FDODeviceExtension = DeviceObject->DeviceExtension; - ASSERT(FDODeviceExtension->Common.IsFDO); + CommonDeviceExtension = DeviceObject->DeviceExtension; // - // init event + // create stack location // - KeInitializeEvent(&Event, NotificationEvent, FALSE); + IoSetNextIrpStackLocation(Irp); // - // now allocate the irp + // get next stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + + // + // store device object + // + IoStack->DeviceObject = DeviceObject; + + // + // sanity check + // + ASSERT(CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction] != NULL); + + // + // call driver + // + Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp); + + // + // done + // + return Status; +} + +NTSTATUS +HidClassFDO_GetDescriptors( + IN PDEVICE_OBJECT DeviceObject) +{ + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + 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 // Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (!Irp) @@ -66,407 +1541,705 @@ HidClassFDO_QueryCapabilities( } // - // get next stack location + // get stack location // IoStack = IoGetNextIrpStackLocation(Irp); // // init stack location // - IoStack->MajorFunction = IRP_MJ_PNP; - IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; - IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities; + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_DESCRIPTOR; + IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR); + IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; + IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; + Irp->UserBuffer = HidDescriptor; // - // set completion routine + // send request // - IoSetCompletionRoutine(Irp, HidClassFDO_QueryCapabilitiesCompletionRoutine, &Event, TRUE, TRUE, TRUE); + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + // + // failed to get device descriptor + // + DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status); + IoFreeIrp(Irp); + return Status; + } - // - // init capabilities - // - RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES)); - Capabilities->Size = sizeof(DEVICE_CAPABILITIES); - Capabilities->Version = 1; // FIXME hardcoded constant - Capabilities->Address = MAXULONG; - Capabilities->UINumber = MAXULONG; + if (Irp->IoStatus.Information != sizeof(HID_DESCRIPTOR)) + { + DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR: invalid size - %x\n", + Irp->IoStatus.Information); + + IoFreeIrp(Irp); + return STATUS_DEVICE_DATA_ERROR; + } // - // pnp irps have default completion code + // let's get device attributes // - Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES; + IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES); + Irp->UserBuffer = &FDODeviceExtension->Common.Attributes; // - // call lower device + // send request // - Status = IoCallDriver(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject, Irp); - if (Status == STATUS_PENDING) + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); + if (!NT_SUCCESS(Status)) { // - // wait for completion + // failed to get device descriptor // - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + 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; + } + + for (nx = 0; nx < 3; ++nx) + { + 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)) + { + if (Irp->IoStatus.Information == ReportLength) + { + // + // save the report descriptor in the FDO extension + // + FDODeviceExtension->ReportDescriptor = ReportDesc; + break; + } + + Status = STATUS_DEVICE_DATA_ERROR; + } + } + + // + // deallocate the report descriptor if we failed + // + if (!NT_SUCCESS(Status) && ReportDesc) + { + ExFreePoolWithTag(ReportDesc, HIDCLASS_TAG); + } + + IoFreeIrp(Irp); + return Status; +} + +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 = NULL; + Status = STATUS_INSUFFICIENT_RESOURCES; } - // - // get status - // - Status = Irp->IoStatus.Status; + if (!NT_SUCCESS(Status)) + { + return Status; + } + + CollectionDescArray = DeviceDescription->CollectionDesc; + InputLength = CollectionDescArray[HIDCollection->CollectionIdx].InputLength; + + if (InputLength) + { + if (HIDCollection->HidCollectInfo.Polled) + { + HIDCollection->InputReport = NULL; + } + else + { + InputReport = ExAllocatePoolWithTag(NonPagedPool, + InputLength, + HIDCLASS_TAG); + - // - // complete request - // - IoFreeIrp(Irp); + HIDCollection->InputReport = InputReport; + + if (!InputReport) + { + DPRINT1("[HIDCLASS] Failed to allocate InputReport\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + FDODeviceExtension->NotAllocCollectResources = FALSE; + } + else + { + DPRINT1("[HIDCLASS] InputLength is 0\n"); + HIDCollection->InputReport = NULL; + } - // - // done - // return Status; } NTSTATUS NTAPI -HidClassFDO_DispatchRequestSynchronousCompletion( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Context) +HidClassInitializeCollection( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN ULONG CollectionIdx) { - // - // signal event - // - KeSetEvent(Context, 0, FALSE); + PHIDCLASS_COLLECTION HIDCollection; + PHIDP_COLLECTION_DESC HidCollectionDesc; + HID_COLLECTION_INFORMATION CollectionInfo; + PHIDP_DEVICE_DESC DeviceDescription; + ULONG CollectionNumber; - // - // done - // - return STATUS_MORE_PROCESSING_REQUIRED; -} + 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 -HidClassFDO_DispatchRequestSynchronous( +NTAPI +HidClassFDO_StartDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { - KEVENT Event; - PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; NTSTATUS Status; - PIO_STACK_LOCATION IoStack; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + ULONG OldFdoState; + PHIDCLASS_COLLECTION HidCollections; + PHIDP_DEVICE_DESC DeviceDescription; + ULONG CollectionIdx; + ULONG CollectionNumber; + SIZE_T Length; - // - // init event - // - KeInitializeEvent(&Event, NotificationEvent, FALSE); + DPRINT("[HIDCLASS] HidClassFDO_StartDevice: DeviceObject - %p, Irp - %p\n", DeviceObject, Irp); // // get device extension // - CommonDeviceExtension = DeviceObject->DeviceExtension; - - // - // set completion routine - // - IoSetCompletionRoutine(Irp, HidClassFDO_DispatchRequestSynchronousCompletion, &Event, TRUE, TRUE, TRUE); + FDODeviceExtension = DeviceObject->DeviceExtension; + ASSERT(FDODeviceExtension->Common.IsFDO); - ASSERT(Irp->CurrentLocation > 0); // - // create stack location + // begin FDO start // - IoSetNextIrpStackLocation(Irp); + OldFdoState = FDODeviceExtension->HidFdoState; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_STARTING; // - // get next stack location + // query capabilities // - IoStack = IoGetCurrentIrpStackLocation(Irp); + Status = HidClassFDO_QueryCapabilities(DeviceObject, + &FDODeviceExtension->Capabilities); - // - // store device object - // - IoStack->DeviceObject = DeviceObject; + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to retrieve capabilities %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } // - // sanity check + // let's start the lower device too // - ASSERT(CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction] != NULL); + IoSkipCurrentIrpStackLocation(Irp); + Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - // - // call minidriver (hidusb) - // - Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp); + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to start lower device with %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } // - // wait for the request to finish + // only first time initialize needed // - if (Status == STATUS_PENDING) + if (OldFdoState == HIDCLASS_STATE_NOT_INIT) { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + // + // 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 = NULL; + goto ExitError; + } + + DeviceDescription = &FDODeviceExtension->Common.DeviceDescription; // - // update status + // now get the the collection description // - Status = Irp->IoStatus.Status; - } + Status = HidP_GetCollectionDescription(FDODeviceExtension->ReportDescriptor, + FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, + NonPagedPool, + DeviceDescription); - // - // done - // - return Status; -} + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed to retrieve the collection description %x\n", Status); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + goto ExitError; + } -NTSTATUS -HidClassFDO_DispatchRequest( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp) -{ - PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; - NTSTATUS Status; - PIO_STACK_LOCATION IoStack; +#ifndef NDEBUG + if (DeviceDescription->ReportIDsLength > 1) + HidClassDumpDeviceDesc(DeviceDescription); +#endif - // - // get device extension - // - CommonDeviceExtension = DeviceObject->DeviceExtension; + // + // device resources allocated successful + // + FDODeviceExtension->IsDeviceResourcesAlloceted = TRUE; - ASSERT(Irp->CurrentLocation > 0); + // + // now allocate the array of HIDCLASS_COLLECTIONs + // + Length = DeviceDescription->CollectionDescLength * sizeof(HIDCLASS_COLLECTION); + HidCollections = ExAllocatePoolWithTag(NonPagedPool, Length, HIDCLASS_TAG); + FDODeviceExtension->HidCollections = HidCollections; - // - // create stack location - // - IoSetNextIrpStackLocation(Irp); + if (HidCollections) + { + RtlZeroMemory(HidCollections, Length); + } + else + { + DPRINT1("[HIDCLASS] HidCollections not allocated\n"); + FDODeviceExtension->ReportDescriptor = NULL; + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_FAILED; + Status = STATUS_INSUFFICIENT_RESOURCES; + goto ExitError; + } - // - // get next stack location - // - IoStack = IoGetCurrentIrpStackLocation(Irp); + FDODeviceExtension->NotAllocCollectResources = TRUE; - // - // store device object - // - IoStack->DeviceObject = DeviceObject; + // + // initialize collections array + // + if (DeviceDescription->CollectionDescLength) + { + for (CollectionIdx = 0; + CollectionIdx < DeviceDescription->CollectionDescLength; + CollectionIdx++) + { + Status = HidClassInitializeCollection(FDODeviceExtension, + CollectionIdx); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed initialize Collection (Idx %x)\n", + CollectionIdx); + break; + } + + CollectionNumber = DeviceDescription->CollectionDesc[CollectionIdx].CollectionNumber; + + // + // allocate resources for current collection + // + Status = HidClassAllocCollectionResources(FDODeviceExtension, + CollectionNumber); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("[HIDCLASS] Failed alloc Collection (Idx %x) resources\n", + CollectionIdx); + break; + } + } + } - // - // sanity check - // - ASSERT(CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction] != NULL); + // + // for polled devices shuttles not needed + // + if (FDODeviceExtension->Common.DriverExtension->DevicesArePolled) + { + DPRINT("[HIDCLASS] DevicesArePolled \n"); + FDODeviceExtension->ShuttleCount = 0; + FDODeviceExtension->Shuttles = NULL; + } + + // + // 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; + } // - // call driver + // FDO start successful // - Status = CommonDeviceExtension->DriverExtension->MajorFunction[IoStack->MajorFunction](DeviceObject, Irp); + FDODeviceExtension->HidFdoState = HIDCLASS_STATE_STARTED; // - // done + // complete request // + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } -NTSTATUS -HidClassFDO_GetDescriptors( - IN PDEVICE_OBJECT DeviceObject) +VOID +NTAPI +HidClassFreeCollectionResources( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR CollectionNumber) { - PHIDCLASS_FDO_EXTENSION FDODeviceExtension; - PIRP Irp; - PIO_STACK_LOCATION IoStack; - NTSTATUS Status; + PHIDCLASS_COLLECTION HidCollection; - // - // get device extension - // - FDODeviceExtension = DeviceObject->DeviceExtension; - ASSERT(FDODeviceExtension->Common.IsFDO); + DPRINT("HidClassFreeCollectionResources: ... \n"); - // - // let's allocate irp - // - Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); - if (!Irp) + HidCollection = GetHidclassCollection(FDODeviceExtension, CollectionNumber); + + if (!HidCollection) { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; + return; } - // - // get stack location - // - IoStack = IoGetNextIrpStackLocation(Irp); + if (HidCollection->HidCollectInfo.Polled) + { + if (HidCollection->PollReport) + { + ExFreePoolWithTag(HidCollection->PollReport, HIDCLASS_TAG); + } - // - // init stack location - // - IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_DESCRIPTOR; - IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR); - IoStack->Parameters.DeviceIoControl.InputBufferLength = 0; - IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; - Irp->UserBuffer = &FDODeviceExtension->HidDescriptor; + HidCollection->PollReport = NULL; + } + else + { + if (HidCollection->InputReport) + { + ExFreePoolWithTag(HidCollection->InputReport, HIDCLASS_TAG); + } + } - // - // send request - // - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) + HidCollection->InputReport = NULL; + + if (HidCollection->CollectionData) { - // - // failed to get device descriptor - // - DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_DESCRIPTOR failed with %x\n", Status); - IoFreeIrp(Irp); - return Status; + ExFreePoolWithTag(HidCollection->CollectionData, HIDCLASS_TAG); } - // - // let's get device attributes - // - IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES; - IoStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES); - Irp->UserBuffer = &FDODeviceExtension->Common.Attributes; + HidCollection->CollectionData = NULL; +} - // - // send request - // - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) +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) + { + do + { + HidClassFreeCollectionResources(FDODeviceExtension, + FDODeviceExtension->HidCollections[ix].CollectionNumber); + ++ix; + } + while (ix < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength); + } + + if (FDODeviceExtension->IsDeviceResourcesAlloceted) { - // - // failed to get device descriptor - // - DPRINT1("[HIDCLASS] IOCTL_HID_GET_DEVICE_ATTRIBUTES failed with %x\n", Status); - IoFreeIrp(Irp); - return Status; + HidP_FreeCollectionDescription(&FDODeviceExtension->Common.DeviceDescription); } - // - // 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); + ReportDesc = FDODeviceExtension->ReportDescriptor; + FDODeviceExtension->Common.DeviceDescription.CollectionDescLength = 0; - // - // now allocate space for the report descriptor - // - FDODeviceExtension->ReportDescriptor = ExAllocatePoolWithTag(NonPagedPool, - FDODeviceExtension->HidDescriptor.DescriptorList[0].wReportLength, - HIDCLASS_TAG); - if (!FDODeviceExtension->ReportDescriptor) + if (ReportDesc) { - // - // not enough memory - // - IoFreeIrp(Irp); - return STATUS_INSUFFICIENT_RESOURCES; + ExFreePoolWithTag(ReportDesc, HIDCLASS_TAG); } - // - // 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 = NULL; - // - // send request - // - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) + if (HidCollections) { - // - // failed to get device descriptor - // - DPRINT1("[HIDCLASS] IOCTL_HID_GET_REPORT_DESCRIPTOR failed with %x\n", Status); - IoFreeIrp(Irp); - return Status; + ExFreePoolWithTag(HidCollections, HIDCLASS_TAG); } - // - // completed successfully - // - IoFreeIrp(Irp); - return STATUS_SUCCESS; + FDODeviceExtension->HidCollections = NULL; } - -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 = NULL; + + if (DeviceRelations) { - 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, HIDCLASS_TAG); } - // - // let's start the lower device too - // - IoSkipCurrentIrpStackLocation(Irp); - Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp); - if (!NT_SUCCESS(Status)) + FDODeviceExtension->DeviceRelations = NULL; + + if (FDODeviceExtension->ClientPdoExtensions) { - 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, HIDCLASS_TAG); } - // - // let's get the descriptors - // - Status = HidClassFDO_GetDescriptors(DeviceObject); - if (!NT_SUCCESS(Status)) + FDODeviceExtension->ClientPdoExtensions = NULL; + + 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 @@ -474,103 +2247,55 @@ HidClassFDO_RemoveDevice( 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 = NULL; - // - // 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 +2310,121 @@ 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) + { + Status = STATUS_SUCCESS; + } + else { // - // time to create the pdos + // time to create the PDOs // - Status = HidClassPDO_CreatePDO(DeviceObject, &FDODeviceExtension->DeviceRelations); + 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; } + + ASSERT(FDODeviceExtension->DeviceRelations->Count > 0); + } + + 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); + // - // sanity check + // now copy device relations // - ASSERT(FDODeviceExtension->DeviceRelations->Count > 0); + 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); - // - // now copy device relations - // - Status = HidClassFDO_CopyDeviceRelations(DeviceObject, &DeviceRelations); - // - // store result - // - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + DeviceRelations = ExAllocatePoolWithTag(PagedPool, + sizeof(DEVICE_RELATIONS), + HIDCLASS_TAG); + + Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; + + if (DeviceRelations) + { + if (FDODeviceExtension->DeviceRelations) + { + ExFreePoolWithTag(FDODeviceExtension->DeviceRelations, HIDCLASS_TAG); + } + + FDODeviceExtension->DeviceRelations = NULL; + + 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,7 +2435,8 @@ HidClassFDO_PnP( { PIO_STACK_LOCATION IoStack; PHIDCLASS_FDO_EXTENSION FDODeviceExtension; - NTSTATUS Status; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + BOOLEAN CompleteIrp = FALSE; // // get device extension @@ -642,10 +2444,21 @@ HidClassFDO_PnP( 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 +2471,93 @@ 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; + } + + CompleteIrp = TRUE; + 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); + + CompleteIrp = TRUE; + break; } default: { - // - // dispatch to mini driver - // - IoCopyCurrentIrpStackLocationToNext(Irp); - Status = HidClassFDO_DispatchRequest(DeviceObject, Irp); - return Status; + break; } } + + //IoReleaseRemoveLock(&FDODeviceExtension->HidRemoveLock, 0); + + if (!CompleteIrp) + { + IoCopyCurrentIrpStackLocationToNext(Irp); + Status = HidClassFDO_DispatchRequest(DeviceObject, Irp); + return Status; + } + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; } diff --git a/drivers/hid/hidclass/hidclass.c b/drivers/hid/hidclass/hidclass.c index 6d21f14..03797f6 100644 --- a/drivers/hid/hidclass/hidclass.c +++ b/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,119 @@ NTSTATUS NTAPI DllUnload(VOID) { + DPRINT("DllUnload: ... \n"); return STATUS_SUCCESS; } +PHIDCLASS_DRIVER_EXTENSION +NTAPI +GetDriverExtension( + IN PDRIVER_OBJECT DriverObject, + OUT PLIST_ENTRY * OutEntry) +{ + PHIDCLASS_DRIVER_EXTENSION DriverExtension = NULL; + PHIDCLASS_DRIVER_EXTENSION driverExtension; + PLIST_ENTRY Entry; + + ExAcquireFastMutex(&DriverExtListMutex); + + Entry = DriverExtList.Flink; + + while (Entry != &DriverExtList) + { + driverExtension = CONTAINING_RECORD(Entry, + HIDCLASS_DRIVER_EXTENSION, + DriverExtLink.Flink); + + if (driverExtension->DriverObject == DriverObject) + { + DriverExtension = driverExtension; + break; + } + + Entry = Entry->Flink; + } + + ExReleaseFastMutex(&DriverExtListMutex); + + if (OutEntry) + { + *OutEntry = Entry; + } + + return DriverExtension; +} + +PHIDCLASS_DRIVER_EXTENSION +NTAPI +RefDriverExt( + IN PDRIVER_OBJECT DriverObject) +{ + PHIDCLASS_DRIVER_EXTENSION DriverExtension; + + if (IsListEmpty(&DriverExtList)) + { + DPRINT("RefDriverExt: DriverExtList is empty\n"); + return NULL; + } + + DriverExtension = GetDriverExtension(DriverObject, NULL); + + if (DriverExtension) + { + // + // increments the reference count + // + DriverExtension->RefCount++; + } + + DPRINT("RefDriverExt: DriverObject - %p, DriverExtension - %p\n", + DriverObject, + DriverExtension); + + return DriverExtension; +} + +PHIDCLASS_DRIVER_EXTENSION +NTAPI +DerefDriverExt( + IN PDRIVER_OBJECT DriverObject) +{ + PHIDCLASS_DRIVER_EXTENSION DriverExtension = NULL; + PLIST_ENTRY Entry; + + if (IsListEmpty(&DriverExtList)) + { + DPRINT("DerefDriverExt: DriverExtList is empty\n"); + return NULL; + } + + DriverExtension = GetDriverExtension(DriverObject, &Entry); + + if (DriverExtension) + { + // + // decrements the reference count + // + DriverExtension->RefCount--; + } + + // + // if reference count < 0 + // then remove given driver object extension's link + // + if (DriverExtension->RefCount < 0) + { + RemoveEntryList(Entry); + } + + DPRINT("DerefDriverExt: DriverObject - %p, DriverExtension - %p\n", + DriverObject, + DriverExtension); + + return DriverExtension; +} + NTSTATUS NTAPI HidClassAddDevice( @@ -44,80 +171,177 @@ 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 +350,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 +375,320 @@ 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; + + 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 device extension + // 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 // 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); + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + // - // allocate context + // validate parameters // - Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG); - if (!Context) + 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; + } + + 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; + } + + 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; + } + + if (IoStack->Parameters.Create.Options & 1) // FIXME const. + { + DPRINT1("HidClass_Create: STATUS_NOT_A_DIRECTORY \n"); + Status = STATUS_NOT_A_DIRECTORY; + goto UnlockExit; } // - // init context + // get PnP states // - RtlZeroMemory(Context, sizeof(HIDCLASS_FILEOP_CONTEXT)); - Context->DeviceExtension = PDODeviceExtension; - KeInitializeSpinLock(&Context->Lock); - InitializeListHead(&Context->ReadPendingIrpListHead); - InitializeListHead(&Context->IrpCompletedListHead); - KeInitializeEvent(&Context->IrpReadComplete, NotificationEvent, FALSE); + HidFdoState = FDODeviceExtension->HidFdoState; + HidPdoState = PDODeviceExtension->HidPdoState; + + DPRINT("HidClass_Create: HidFdoState - %p, HidPdoState - %p\n", + HidFdoState, + HidPdoState); // - // store context + // validate PnP states // - ASSERT(IoStack->FileObject); - IoStack->FileObject->FsContext = Context; + 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; + } // - // done + // allocate file context // - Irp->IoStatus.Status = STATUS_SUCCESS; + 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, HIDCLASS_TAG); + } + + 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, HIDCLASS_TAG); } NTSTATUS @@ -217,13 +697,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 +718,20 @@ 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 +747,616 @@ 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); + } - // - // release lock - // - KeReleaseSpinLock(&IrpContext->Lock, OldLevel); + HidClassDestroyFileContext(HidCollection, IrpContext); - // - // remove context - // - IoStack->FileObject->FsContext = NULL; + DPRINT1("HidClass_Close: FIXME RemoveLock support\n"); + ASSERT(FALSE); - // - // free context - // - ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); + if (0)//IoAcquireRemoveLock(&FDODeviceExtension->HidRemoveLock, 0)) + { + HidClassCleanUpFDO(FDODeviceExtension); + } + } + else + { + KeAcquireSpinLock(&HidCollection->CollectSpinLock, &OldIrql); + InterlockedExchangeAdd(&PDODeviceExtension->OpenCount, -1); - // - // complete request - // - Irp->IoStatus.Status = STATUS_SUCCESS; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; -} + if (IrpContext->DesiredAccess & FILE_READ_DATA) + { + PDODeviceExtension->OpensForRead--; + } -NTSTATUS -NTAPI -HidClass_ReadCompleteIrp( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Ctx) -{ - PHIDCLASS_IRP_CONTEXT IrpContext; - KIRQL OldLevel; - PUCHAR Address; - ULONG Offset; - PHIDP_COLLECTION_DESC CollectionDescription; - PHIDP_REPORT_IDS ReportDescription; - BOOLEAN IsEmpty; + if (IrpContext->DesiredAccess & FILE_WRITE_DATA) + { + PDODeviceExtension->OpensForWrite--; + } - // - // get irp context - // - IrpContext = Ctx; + if (!(IrpContext->ShareAccess & FILE_SHARE_READ)) + { + PDODeviceExtension->RestrictionsForRead--; + } - 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); + if (!(IrpContext->ShareAccess & FILE_SHARE_WRITE)) + { + PDODeviceExtension->RestrictionsForWrite--; + } - // - // copy result - // - if (Irp->IoStatus.Information) - { - // - // get address - // - Address = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority); - if (Address) + if (!IrpContext->ShareAccess) { - // - // reports may have a report id prepended - // - Offset = 0; + PDODeviceExtension->RestrictionsForAnyOpen--; + } - // - // get collection description - // - CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, - IrpContext->FileOp->DeviceExtension->CollectionNumber); - ASSERT(CollectionDescription); + RemoveEntryList(&IrpContext->InterruptReportLink); + KeReleaseSpinLock(&HidCollection->CollectSpinLock, OldIrql); - // - // get report description - // - ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, - IrpContext->FileOp->DeviceExtension->CollectionNumber); - ASSERT(ReportDescription); + if (IrpContext->IsMyPrivilegeTrue) + { + KeAcquireSpinLock(&HidCollection->CollectCloseSpinLock, &OldIrql); - if (CollectionDescription && ReportDescription) + while (IrpContext->CloseCounter) { - // - // calculate offset - // - ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength); - Offset = CollectionDescription->InputLength - ReportDescription->InputLength; + IrpContext->CloseCounter--; + HidCollection->CloseFlag--; } - // - // copy result - // - RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength); + IrpContext->CloseCounter--; + + KeReleaseSpinLock(&HidCollection->CollectCloseSpinLock, OldIrql); } + + HidClassDestroyFileContext(HidCollection, IrpContext); } - // - // copy result status - // - IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status; - IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information; + Status = STATUS_SUCCESS; - // - // free input report buffer - // - ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG); +Exit: // - // remove us from pending list + // complete request // - KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel); + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} - // - // remove from pending list - // - RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +VOID +NTAPI +HidClassCompleteIrpAsynchronously( + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context) +{ + PHIDCLASS_COMPLETION_WORKITEM CompletionWorkItem; - // - // is list empty - // - IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead); + DPRINT("HidClassCompleteIrpAsynchronously: ... \n"); - // - // insert into completed list - // - InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry); + CompletionWorkItem = (PHIDCLASS_COMPLETION_WORKITEM)Context; + IoCompleteRequest(CompletionWorkItem->Irp, 0); + IoFreeWorkItem(CompletionWorkItem->CompleteWorkItem); + ExFreePoolWithTag(CompletionWorkItem, HIDCLASS_TAG); +} + +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; + + DPRINT("HidClass_Read: Irp - %p\n", Irp); // - // release lock + // get device extensions // - KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel); + CommonDeviceExtension = DeviceObject->DeviceExtension; + ASSERT(CommonDeviceExtension->IsFDO == FALSE); + PDODeviceExtension = DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->FDODeviceExtension; // - // complete original request + // get current stack location // - IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT); + IoStack = IoGetCurrentIrpStackLocation(Irp); + FileObject = IoStack->FileObject; - DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty); - if (IrpContext->FileOp->StopInProgress && IsEmpty) + if (!FileObject) { - // - // last pending irp - // - DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n"); - KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE); + DPRINT1("HidClass_Read: error ... \n"); + Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_PRIVILEGE_NOT_HELD; } - if (IrpContext->FileOp->StopInProgress && IsEmpty) + FileContext = FileObject->FsContext; + + if (!FileContext) { - // - // last pending irp - // - DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n"); - KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE); + DPRINT1("HidClass_Read: error ... \n"); + Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return STATUS_PRIVILEGE_NOT_HELD; } - // - // free irp context - // - ExFreePoolWithTag(IrpContext, HIDCLASS_TAG); + ASSERT(IoStack->FileObject->Type == IO_TYPE_FILE); - // - // done - // - return STATUS_MORE_PROCESSING_REQUIRED; -} + HidFdoState = FDODeviceExtension->HidFdoState; + HidPdoState = PDODeviceExtension->HidPdoState; -PIRP -HidClass_GetIrp( - IN PHIDCLASS_FILEOP_CONTEXT Context) -{ - KIRQL OldLevel; - PIRP Irp = NULL; - PLIST_ENTRY ListEntry; + 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); - // - // acquire lock - // - KeAcquireSpinLock(&Context->Lock, &OldLevel); + Status = STATUS_DEVICE_NOT_CONNECTED; + goto Exit; + } - // - // is list empty? - // - if (!IsListEmpty(&Context->IrpCompletedListHead)) + if (HidFdoState == HIDCLASS_STATE_DISABLED || + HidFdoState == HIDCLASS_STATE_STOPPING || + HidPdoState == HIDCLASS_STATE_FAILED || + HidPdoState == HIDCLASS_STATE_STOPPING) { - // - // grab first entry - // - ListEntry = RemoveHeadList(&Context->IrpCompletedListHead); + IsNotRunning = TRUE; + } + else + { + IsNotRunning = FALSE; + } - // - // get irp - // - Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry); + Irp->IoStatus.Information = 0; + + HidCollection = GetHidclassCollection(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); + + HidCollectionDesc = GetCollectionDesc(FDODeviceExtension, + PDODeviceExtension->CollectionNumber); + + if (!HidCollection || !HidCollectionDesc) + { + DPRINT1("HidClass_Read: error ... \n"); + Status = STATUS_DEVICE_NOT_CONNECTED; + + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; } - // - // release lock - // - KeReleaseSpinLock(&Context->Lock, OldLevel); + Length = IoStack->Parameters.Read.Length; - // - // done - // - return Irp; -} + if (Length < HidCollectionDesc->InputLength) + { + DPRINT1("HidClass_Read: error ... \n"); + Status = STATUS_INVALID_BUFFER_SIZE; -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; + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } - // - // get an irp from fresh list - // - Irp = HidClass_GetIrp(Context); - if (!Irp) + goto Exit; + } + + DPRINT("HidClass_Read: Polled - %x\n", HidCollection->HidCollectInfo.Polled); + + if (!HidCollection->HidCollectInfo.Polled) { + KeAcquireSpinLock(&FileContext->Lock, &OldIrql); + // - // build new irp + // FIXME: PowerState implement // - Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); - if (!Irp) + if (IsNotRunning /*|| (FDODeviceExtension->DevicePowerState != PowerDeviceD0)*/) + { + Status = HidClassEnqueueInterruptReadIrp(HidCollection, FileContext, Irp); + } + else + { + BufferRemaining = IoStack->Parameters.Read.Length; + + VAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, + NormalPagePriority); + + StartVAddress = VAddress; + + if (!VAddress) + { + DPRINT1("HidClass_Read: Invalid buffer address\n"); + Status = STATUS_INVALID_USER_BUFFER; + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + 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(HIDCLASS_INT_REPORT_HEADER)); + + Status = HidClassCopyInputReportToUser(FileContext, + InputReportBuffer, + &ReportSize, + VAddress); + + ExFreePoolWithTag(Header, HIDCLASS_TAG); + + 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); + + if (Status == STATUS_PENDING) + { + return STATUS_PENDING; + } + + goto Exit; + } + } + + Status = HidClassEnqueueInterruptReadIrp(HidCollection, + FileContext, + Irp); + } + + KeReleaseSpinLock(&FileContext->Lock, OldIrql); + + 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, HIDCLASS_TAG); + + 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 + // get current stack location // - Context = IoStack->FileObject->FsContext; - ASSERT(Context); + 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 + // FIXME CheckIdleState() // - Status = HidClass_BuildIrp(DeviceObject, - Irp, - Context, - IOCTL_HID_READ_REPORT, - IoStack->Parameters.Read.Length, - &NewIrp, - &NewIrpContext); - if (!NT_SUCCESS(Status)) + + Report = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + + 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 + // first byte of the buffer is the report ID for the report // - KeAcquireSpinLock(&Context->Lock, &OldLevel); + 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 = NULL; + +Exit: + + if (Irp) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return Status; } NTSTATUS @@ -934,9 +1485,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; @@ -1014,31 +1574,63 @@ 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( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension; + PHIDCLASS_FDO_EXTENSION FDODeviceExtension; + PHID_DEVICE_EXTENSION HidDeviceExtension; + NTSTATUS Status; + + 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 +1645,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 +1657,77 @@ 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 +1735,94 @@ 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/drivers/hid/hidclass/pdo.c b/drivers/hid/hidclass/pdo.c index 761cb24..29070f1 100644 --- a/drivers/hid/hidclass/pdo.c +++ b/drivers/hid/hidclass/pdo.c @@ -15,6 +15,69 @@ #define NDEBUG #include +NTSTATUS +NTAPI +HidClassSymbolicLinkOnOff( + IN PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension, + IN ULONG CollectionNumber, + IN BOOLEAN Enable, + IN PDEVICE_OBJECT PDODeviceObject) +{ + PHIDCLASS_COLLECTION HidCollection; + NTSTATUS Status; + + DPRINT("HidClassSymbolicLinkOnOff: CollectionNumber - %x, Enable - %x\n", + CollectionNumber, + Enable); + + HidCollection = GetHidclassCollection(PDODeviceExtension->FDODeviceExtension, + CollectionNumber); + + if (!HidCollection) + { + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + if (Enable) + { + 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) + { + DPRINT("HidClassSymbolicLinkOnOff: SymbolicLinkName - %wZ\n", + &HidCollection->SymbolicLinkName); + + Status = IoSetDeviceInterfaceState(&HidCollection->SymbolicLinkName, + FALSE); + + ExFreePoolWithTag(HidCollection->SymbolicLinkName.Buffer, + HIDCLASS_TAG); + + HidCollection->SymbolicLinkName.Buffer = NULL; + } + else + { + Status = STATUS_SUCCESS; + } + } + + return Status; +} + PHIDP_COLLECTION_DESC HidClassPDO_GetCollectionDescription( PHIDP_DEVICE_DESC DeviceDescription, @@ -349,125 +412,478 @@ 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) + { + 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) + { + 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 (!IsListEmpty(&ListHead)) + { + 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) + { + 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; + + 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 + // Copy capabilities from PDO extension // - RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, + 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)); + 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 +899,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 +916,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 +928,172 @@ 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] = NULL; + } - // - // 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,9 +1101,18 @@ 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 @@ -649,49 +1120,120 @@ HidClassPDO_CreatePDO( FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO); + 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 // - Length = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * FDODeviceExtension->Common.DeviceDescription.CollectionDescLength; - DeviceRelations = ExAllocatePoolWithTag(PagedPool, Length, HIDCLASS_TAG); + if (*OutDeviceRelations == NULL) + { + 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 + // allocate ClientPdoExtensions array // - RtlZeroMemory(DeviceRelations, Length); + if (!FDODeviceExtension->ClientPdoExtensions) + { + PVOID clientPdoExtensions; + ULONG Length; + + Length = DescLength * sizeof(PHIDCLASS_PDO_DEVICE_EXTENSION); + + clientPdoExtensions = ExAllocatePoolWithTag(NonPagedPool, + Length, + HIDCLASS_TAG); + + FDODeviceExtension->ClientPdoExtensions = clientPdoExtensions; + } + + if (!FDODeviceExtension->ClientPdoExtensions) + { + DPRINT1("[HIDCLASS]: Allocate DeviceRelations failed\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(DeviceRelations, HIDCLASS_TAG); + FDODeviceExtension->DeviceRelations = NULL; + } + + 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 PDO for top level collection + // let's create a PDOs for top level collections // - Index = 0; - while (Index < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength) + do { + CollectionNumber = DeviceDescription->CollectionDesc[PdoIdx].CollectionNumber; + // // let's create the device object // - Status = IoCreateDevice(FDODeviceExtension->Common.DriverExtension->DriverObject, + 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; } + DPRINT("[HIDCLASS] HidClassCreatePDOs: added PDO IoCreateDevice (%p)\n", + PDODeviceObject); + + CollectionDesc = &DeviceDescription->CollectionDesc[PdoIdx]; + UsagePage = CollectionDesc->UsagePage; + Usage = CollectionDesc->Usage; + + ObReferenceObject(PDODeviceObject); + // // patch stack size // @@ -701,80 +1243,103 @@ HidClassPDO_CreatePDO( // 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)); + + RtlCopyMemory(&PDODeviceExtension->Common.DeviceDescription, + &FDODeviceExtension->Common.DeviceDescription, + sizeof(HIDP_DEVICE_DESC)); + + RtlCopyMemory(&PDODeviceExtension->Capabilities, + &FDODeviceExtension->Capabilities, + sizeof(DEVICE_CAPABILITIES)); // - // set device flags + // store device object in device relations // - PDODeviceObject->Flags |= DO_MAP_IO_BUFFER; + DeviceRelations->Objects[PdoIdx] = PDODeviceObject; + FDODeviceExtension->ClientPdoExtensions[PdoIdx] = PDODeviceExtension; // - // device is initialized + // set device flags // - PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + PDODeviceObject->Flags |= DO_POWER_PAGABLE; // - // store device object in device relations + // device is initialized // - DeviceRelations->Objects[Index] = PDODeviceObject; - DeviceRelations->Count++; + PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; // // move to next // - Index++; + PdoIdx++; } - + while (PdoIdx < DescLength); // - // check if creating succeeded + // store device relations // + *OutDeviceRelations = DeviceRelations; + if (!NT_SUCCESS(Status)) { - // - // failed - // - for (Index = 0; Index < DeviceRelations->Count; Index++) +ErrorExit: + ExFreePoolWithTag(FDODeviceExtension->ClientPdoExtensions, + HIDCLASS_TAG); + + FDODeviceExtension->ClientPdoExtensions = NULL; + + if (!NT_SUCCESS(Status)) { - // - // delete device - // - IoDeleteDevice(DeviceRelations->Objects[Index]); + ExFreePoolWithTag(DeviceRelations, HIDCLASS_TAG); + FDODeviceExtension->DeviceRelations = NULL; } - - // - // 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/drivers/hid/hidclass/precomp.h b/drivers/hid/hidclass/precomp.h index afaa571..0aec55d 100644 --- a/drivers/hid/hidclass/precomp.h +++ b/drivers/hid/hidclass/precomp.h @@ -2,27 +2,102 @@ #define _HIDCLASS_PCH_ #define _HIDPI_NO_FUNCTION_MACROS_ -#include +#include #include #include #include +#include #define HIDCLASS_TAG 'CdiH' -typedef struct -{ +#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 _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 +125,8 @@ typedef struct } HIDCLASS_COMMON_DEVICE_EXTENSION, *PHIDCLASS_COMMON_DEVICE_EXTENSION; -typedef struct -{ +typedef struct _HIDCLASS_FDO_EXTENSION { + // // parts shared by fdo and pdo // @@ -77,16 +152,92 @@ typedef struct // 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 // DEVICE_CAPABILITIES Capabilities; @@ -111,10 +262,38 @@ 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,44 +318,70 @@ typedef struct __HIDCLASS_FILEOP_CONTEXT__ // stop in progress indicator // BOOLEAN StopInProgress; + BOOLEAN IsMyPrivilegeTrue; + UCHAR Reserved1[2]; // // read complete event // KEVENT IrpReadComplete; -} HIDCLASS_FILEOP_CONTEXT, *PHIDCLASS_FILEOP_CONTEXT; - -typedef struct -{ // - // original request + // read IRP pending list // - PIRP OriginalIrp; + LIST_ENTRY InterruptReadIrpList; // - // file op + // report list // - PHIDCLASS_FILEOP_CONTEXT FileOp; + 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; - // - // buffer for reading report - // - PVOID InputReportBuffer; - - // - // buffer length - // - ULONG InputReportBufferLength; +} HIDCLASS_FILEOP_CONTEXT, *PHIDCLASS_FILEOP_CONTEXT; - // - // work item - // - PIO_WORKITEM CompletionWorkItem; +// +// 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 +// +PHIDP_COLLECTION_DESC +NTAPI +GetCollectionDesc( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN UCHAR CollectionNumber); -} HIDCLASS_IRP_CONTEXT, *PHIDCLASS_IRP_CONTEXT; +PHIDCLASS_COLLECTION +NTAPI +GetHidclassCollection( + IN PHIDCLASS_FDO_EXTENSION FDODeviceExtension, + IN ULONG CollectionNumber); -/* fdo.c */ NTSTATUS HidClassFDO_PnP( IN PDEVICE_OBJECT DeviceObject, @@ -192,9 +397,66 @@ HidClassFDO_DispatchRequestSynchronous( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); -/* pdo.c */ NTSTATUS -HidClassPDO_CreatePDO( +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 +HidClassCreatePDOs( IN PDEVICE_OBJECT DeviceObject, OUT PDEVICE_RELATIONS *OutDeviceRelations); @@ -213,4 +475,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/drivers/hid/hidusb/hidusb.c b/drivers/hid/hidusb/hidusb.c index 6cd9301..4395dfb 100644 --- a/drivers/hid/hidusb/hidusb.c +++ b/drivers/hid/hidusb/hidusb.c @@ -185,6 +185,8 @@ HidUsb_AbortPipe( NTSTATUS Status; PUSBD_PIPE_INFORMATION PipeInformation; + DPRINT("HidUsb_AbortPipe: ... \n"); + // // get device extension // @@ -339,6 +341,7 @@ HidUsb_ResetWorkerRoutine( ULONG PortStatus; PHID_USB_RESET_CONTEXT ResetContext; PHID_DEVICE_EXTENSION DeviceExtension; + PHID_USB_DEVICE_EXTENSION HidDeviceExtension; DPRINT("[HIDUSB] ResetWorkerRoutine\n"); @@ -351,59 +354,66 @@ HidUsb_ResetWorkerRoutine( // get device extension // DeviceExtension = ResetContext->DeviceObject->DeviceExtension; + HidDeviceExtension = DeviceExtension->MiniDeviceExtension; + + //FIXME RemoveLock support // // 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)) - { - // - // port is disabled - // - Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status); - } - else + if (!(PortStatus & USBD_PORT_CONNECTED)) { // - // abort pipe + // port is not connected // - Status = HidUsb_AbortPipe(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetWorkerRoutine AbortPipe %x\n", Status); + +ResetPipe: if (NT_SUCCESS(Status)) { // - // reset port + // reset interrupt pipe // - Status = HidUsb_ResetPort(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetPort %x\n", Status); - if (Status == STATUS_DEVICE_DATA_ERROR) - { - // - // invalidate device state - // - IoInvalidateDeviceState(DeviceExtension->PhysicalDeviceObject); - } + 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) + { // - // reset interrupt pipe + // invalidate device state // - if (NT_SUCCESS(Status)) - { - // - // reset pipe - // - Status = HidUsb_ResetInterruptPipe(ResetContext->DeviceObject); - DPRINT1("[HIDUSB] ResetWorkerRoutine ResetPipe %x\n", Status); - } + HidDeviceExtension->HidState = HIDUSB_STATE_FAILED; + IoInvalidateDeviceState(DeviceExtension->PhysicalDeviceObject); } + + goto ResetPipe; } } +Exit: + // // cleanup // @@ -413,7 +423,6 @@ HidUsb_ResetWorkerRoutine( ExFreePoolWithTag(ResetContext, HIDUSB_TAG); } - NTSTATUS NTAPI HidUsb_ReadReportCompletion( @@ -423,6 +432,7 @@ HidUsb_ReadReportCompletion( { PURB Urb; PHID_USB_RESET_CONTEXT ResetContext; + NTSTATUS Status = STATUS_SUCCESS; // // get urb @@ -430,42 +440,55 @@ 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 + // store result length // - IoMarkIrpPending(Irp); + Irp->IoStatus.Information = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; + goto Exit; } // - // did the reading report succeed / cancelled + // did the reading report cancelled // - if (NT_SUCCESS(Irp->IoStatus.Status) || Irp->IoStatus.Status == STATUS_CANCELLED || Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED) + 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 + // FIXME RemoveLock support + // + // // allocate reset context // @@ -489,33 +512,40 @@ 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); } + else + { + DPRINT1("[HIDUSB] HidUsb_ReadReportCompletion: ExAllocatePoolWithTag failed\n"); + } + +Exit: // // free urb // ExFreePoolWithTag(Urb, HIDUSB_URB_TAG); - // - // complete request - // - return STATUS_CONTINUE_COMPLETION; -} + //FIXME RemoveLock support + if (Irp->PendingReturned) + { + // + // mark irp pending + // + IoMarkIrpPending(Irp); + } + + return Status; +} NTSTATUS NTAPI @@ -528,6 +558,7 @@ HidUsb_ReadReport( PIO_STACK_LOCATION IoStack; PURB Urb; PUSBD_PIPE_INFORMATION PipeInformation; + NTSTATUS Status; // // get device extension @@ -609,18 +640,16 @@ 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); -} + //FIXME RemoveLock support + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + return Status; +} NTSTATUS NTAPI @@ -756,6 +785,7 @@ HidInternalDeviceControl( IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_BUFFER_SIZE; } + // // store result // @@ -799,7 +829,9 @@ HidInternalDeviceControl( Irp->IoStatus.Information = HidDeviceExtension->HidDescriptor->bLength; Irp->IoStatus.Status = STATUS_SUCCESS; - /* complete request */ + // + // complete request + // IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } @@ -820,7 +852,6 @@ HidInternalDeviceControl( case IOCTL_HID_WRITE_REPORT: { DPRINT1("[HIDUSB] IOCTL_HID_WRITE_REPORT not implemented \n"); - ASSERT(FALSE); Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; @@ -946,13 +977,23 @@ Hid_PnpCompletion( IN PVOID Context) { // - // signal event + // set event to signaled state // - KeSetEvent(Context, 0, FALSE); + KeSetEvent((PRKEVENT)Context, EVENT_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} +NTSTATUS +NTAPI +HidDispatchUrbComplete( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ // - // done + // set event to signaled state // + KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } @@ -1011,7 +1052,7 @@ Hid_DispatchUrb( // // set completion routine // - IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE); + IoSetCompletionRoutine(Irp, HidDispatchUrbComplete, &Event, TRUE, TRUE, TRUE); // // call driver @@ -1041,7 +1082,6 @@ Hid_DispatchUrb( DPRINT("[HIDUSB] DispatchUrb %x\n", Status); - // // done // @@ -1191,6 +1231,8 @@ Hid_SelectConfiguration( PHID_USB_DEVICE_EXTENSION HidDeviceExtension; PHID_DEVICE_EXTENSION DeviceExtension; + DPRINT("Hid_SelectConfiguration: DeviceObject - %p\n", DeviceObject); + // // get device extension // @@ -1277,7 +1319,7 @@ Hid_SelectConfiguration( } NTSTATUS -Hid_DisableConfiguration( +Hid_CloseConfiguration( IN PDEVICE_OBJECT DeviceObject) { PHID_DEVICE_EXTENSION DeviceExtension; @@ -1297,12 +1339,14 @@ Hid_DisableConfiguration( Urb = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct _URB_SELECT_CONFIGURATION), HIDUSB_URB_TAG); + if (!Urb) { // // no memory // - return STATUS_INSUFFICIENT_RESOURCES; + HidDeviceExtension->HidState = HIDUSB_STATE_STOPPED; + return STATUS_UNSUCCESSFUL; } // @@ -1319,6 +1363,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 +1375,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 +1409,34 @@ Hid_DisableConfiguration( HidDeviceExtension->DeviceDescriptor = NULL; } + 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; + // - // done + // abort pending requests + // + HidUsb_AbortPipe(DeviceObject); + + //FIXME RemoveLock support + // + // select configuration with NULL pointer for ConfigurationDescriptor + // + Status = Hid_CloseConfiguration(DeviceObject); + return Status; } @@ -1503,7 +1583,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; + + if (OldState == HIDUSB_STATE_STOPPING || + OldState == HIDUSB_STATE_STOPPED || + OldState == HIDUSB_STATE_REMOVED) + { + // + // start after stop + // + DPRINT("[HIDUSB] FIXME RemoveLock support\n"); + } + + HidDeviceExtension->InterfaceInfo = NULL; + + return STATUS_SUCCESS; +} + +NTSTATUS +Hid_StartDevice( IN PDEVICE_OBJECT DeviceObject) { PHID_USB_DEVICE_EXTENSION HidDeviceExtension; @@ -1555,9 +1664,9 @@ Hid_PnpStart( if (!NT_SUCCESS(Status)) { // - // failed to obtain device descriptor + // failed to obtain configuration descriptor // - DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status); + DPRINT1("[HIDUSB] failed to get configuration descriptor %x\n", Status); return Status; } @@ -1565,8 +1674,14 @@ Hid_PnpStart( // 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 @@ -1593,12 +1708,25 @@ Hid_PnpStart( if (!NT_SUCCESS(Status)) { // - // failed to obtain device descriptor + // failed to obtain full configuration descriptor // - DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status); + 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 +1746,33 @@ Hid_PnpStart( return STATUS_UNSUCCESSFUL; } + 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->bInterfaceClass == USB_DEVICE_CLASS_HUMAN_INTERFACE); 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 @@ -1679,6 +1822,65 @@ Hid_PnpStart( 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) + { + DPRINT("[HIDUSB] FIXME RemoveLock support\n"); + } + + // + // abort pending requests if state was "running" + // + if (OldDeviceState == HIDUSB_STATE_RUNNING) + { + HidUsb_AbortPipe(DeviceObject); + } + + DPRINT("[HIDUSB] Hid_RemoveDevice: State - %x\n", HidDeviceExtension->HidState); + + // + // 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 +1891,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 @@ -1703,183 +1907,131 @@ HidPnp( 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; - - // - // pass request to next request - // - IoSkipCurrentIrpStackLocation(Irp); - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - - // - // 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_START_DEVICE: + Status = Hid_Init(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); - - // - // prepare irp - // - KeInitializeEvent(&Event, NotificationEvent, FALSE); - IoCopyCurrentIrpStackLocationToNext(Irp); - IoSetCompletionRoutine(Irp, Hid_PnpCompletion, &Event, TRUE, TRUE, TRUE); - - // - // send irp and wait for completion - // - Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); - if (Status == STATUS_PENDING) + if (HidDeviceExtension->HidState == HIDUSB_STATE_STARTING) { - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Irp->IoStatus.Status; + Status = Hid_StopDevice(DeviceObject); + + if (!NT_SUCCESS(Status)) + { + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } } + 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); + case IRP_MN_REMOVE_DEVICE: + return Hid_RemoveDevice(DeviceObject, 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; - } + case IRP_MN_QUERY_PNP_DEVICE_STATE: + DPRINT("[HIDUSB] IRP_MN_QUERY_PNP_DEVICE_STATE. HidState - %x\n", + HidDeviceExtension->HidState); - if (NT_SUCCESS(Status) && IoStack->Parameters.DeviceCapabilities.Capabilities != NULL) + if (HidDeviceExtension->HidState == HIDUSB_STATE_FAILED) { + DPRINT1("[HIDUSB] PNP_DEVICE_FAILED!\n"); + DPRINT1("[FIXME: PnP manager have bag (IoInvalidateDeviceState())!\n"); // - // don't need to safely remove + // HACK: due problem disconnecting from PC USB port CORE-9070). + // W2003 not call this code in it case. // - IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE; + + //Irp->IoStatus.Information |= PNP_DEVICE_FAILED; } + break; - // - // 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); + 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); - // - // 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; - } + IoSetCompletionRoutine(Irp, + Hid_PnpCompletion, + &Event, + TRUE, + TRUE, + TRUE); - // - // start device - // - Status = Hid_PnpStart(DeviceObject); + // + // send request to driver for lower device and wait for completion + // + Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp); + + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + 0, + NULL); + } + + Status = Irp->IoStatus.Status; + + // + // complete handle request + // + if (IoStack->MinorFunction != IRP_MN_START_DEVICE) + { + if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE) + { + HidDeviceExtension->HidState = HIDUSB_STATE_STOPPED; // - // complete request + // free resources // - Irp->IoStatus.Status = Status; - DPRINT("[HIDUSB] IRP_MN_START_DEVICE Status %x\n", Status); - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; + 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( @@ -1901,8 +2053,10 @@ HidAddDevice( KeInitializeEvent(&HidDeviceExtension->Event, NotificationEvent, FALSE); // - // done + // set HidState as not initialized value // + HidDeviceExtension->HidState = 0; + return STATUS_SUCCESS; } diff --git a/drivers/hid/hidusb/hidusb.h b/drivers/hid/hidusb/hidusb.h index 9209362..331ca13 100644 --- a/drivers/hid/hidusb/hidusb.h +++ b/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; } HID_USB_DEVICE_EXTENSION, *PHID_USB_DEVICE_EXTENSION; typedef struct diff --git a/drivers/hid/hidusb/hidusb.rc b/drivers/hid/hidusb/hidusb.rc index bcf0774..c6d53b7 100644 --- a/drivers/hid/hidusb/hidusb.rc +++ b/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/drivers/hid/kbdhid/kbdhid.c b/drivers/hid/kbdhid/kbdhid.c index bacf72a..f74e3cd 100644 --- a/drivers/hid/kbdhid/kbdhid.c +++ b/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); diff --git a/drivers/hid/mouhid/mouhid.c b/drivers/hid/mouhid/mouhid.c index 0450909..e67948e 100644 --- a/drivers/hid/mouhid/mouhid.c +++ b/drivers/hid/mouhid/mouhid.c @@ -535,11 +535,18 @@ MouHid_Close( /* request stopping of the report cycle */ DeviceExtension->StopReadReport = TRUE; - /* wait until the reports have been read */ - KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL); + DPRINT("[MOUHID] MouHid_Close: Disabling Mouse\n"); /* cancel irp */ - IoCancelIrp(DeviceExtension->Irp); + if (IoCancelIrp(DeviceExtension->Irp)) + { + /* wait until the reports have been read */ + KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, + Executive, + KernelMode, + FALSE, + NULL); + } } DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive); diff --git a/drivers/usb/CMakeLists.txt b/drivers/usb/CMakeLists.txt index 51edb17..534e079 100644 --- a/drivers/usb/CMakeLists.txt +++ b/drivers/usb/CMakeLists.txt @@ -1,11 +1,13 @@ add_subdirectory(usbccgp) add_subdirectory(usbd) -add_subdirectory(usbehci) -add_subdirectory(usbhub) -#add_subdirectory(usbhub_new) -add_subdirectory(usbohci) -#add_subdirectory(usbohci_new) +#add_subdirectory(usbehci) +add_subdirectory(usbehci_new) +#add_subdirectory(usbhub) +add_subdirectory(usbhub_new) +#add_subdirectory(usbohci) +add_subdirectory(usbohci_new) add_subdirectory(usbport) -add_subdirectory(usbstor) -#add_subdirectory(usbstor_new) -add_subdirectory(usbuhci) +#add_subdirectory(usbstor) +add_subdirectory(usbstor_new) +#add_subdirectory(usbuhci) +add_subdirectory(usbuhci_new) diff --git a/drivers/usb/usbccgp/pdo.c b/drivers/usb/usbccgp/pdo.c index 06a549f..0c75a29 100644 --- a/drivers/usb/usbccgp/pdo.c +++ b/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/drivers/usb/usbehci_new/CMakeLists.txt b/drivers/usb/usbehci_new/CMakeLists.txt new file mode 100644 index 0000000..f9105af --- /dev/null +++ b/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 usbd hal ntoskrnl) +add_pch(usbehci usbehci.h SOURCE) +add_cd_file(TARGET usbehci DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/usb/usbehci_new/dbg_ehci.h b/drivers/usb/usbehci_new/dbg_ehci.h new file mode 100644 index 0000000..6ebecf2 --- /dev/null +++ b/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/drivers/usb/usbehci_new/debug.c b/drivers/usb/usbehci_new/debug.c new file mode 100644 index 0000000..7cf66f6 --- /dev/null +++ b/drivers/usb/usbehci_new/debug.c @@ -0,0 +1,37 @@ +#include "usbehci.h" + +//#define NDEBUG +#include + +VOID +NTAPI +EHCI_DumpHwTD(IN PEHCI_HCD_TD TD) +{ + if (!TD) + return; + + do + { + 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); + + TD = TD->NextHcdTD; + } + while (TD); +} + +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/drivers/usb/usbehci_new/guid.c b/drivers/usb/usbehci_new/guid.c new file mode 100644 index 0000000..50a6036 --- /dev/null +++ b/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/drivers/usb/usbehci_new/hardware.h b/drivers/usb/usbehci_new/hardware.h new file mode 100644 index 0000000..f0fe13e --- /dev/null +++ b/drivers/usb/usbehci_new/hardware.h @@ -0,0 +1,405 @@ +#define EHCI_FRAME_LIST_MAX_ENTRIES 1024 // Number of frames in Frame List + +/* 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 + +#define EHCI_FLADJ_PCI_CONFIG_OFFSET 0x61 + +typedef union _EHCI_LEGACY_EXTENDED_CAPABILITY { + struct { + ULONG CapabilityID : 8; + ULONG NextCapabilityPointer : 8; + ULONG BiosOwnedSemaphore : 1; + ULONG Reserved1 : 7; + ULONG OsOwnedSemaphore : 1; + ULONG Reserved2 : 7; + }; + ULONG AsULONG; +} EHCI_LEGACY_EXTENDED_CAPABILITY; + +C_ASSERT(sizeof(EHCI_LEGACY_EXTENDED_CAPABILITY) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_HC_STRUCTURAL_PARAMS) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_HC_CAPABILITY_PARAMS) == sizeof(ULONG)); + +typedef struct _EHCI_HC_CAPABILITY_REGISTERS { + UCHAR RegistersLength; // RO + UCHAR Reserved; // RO + USHORT InterfaceVersion; // RO + EHCI_HC_STRUCTURAL_PARAMS StructParameters; // RO + EHCI_HC_CAPABILITY_PARAMS CapParameters; // RO + UCHAR CompanionPortRouteDesc[8]; // RO +} EHCI_HC_CAPABILITY_REGISTERS, *PEHCI_HC_CAPABILITY_REGISTERS; + +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; + +C_ASSERT(sizeof(EHCI_USB_COMMAND) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_USB_STATUS) == sizeof(ULONG)); + +#define EHCI_INTERRUPT_MASK 0x3F + +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; + +C_ASSERT(sizeof(EHCI_INTERRUPT_ENABLE) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_PORT_STATUS_CONTROL) == sizeof(ULONG)); + +/* FRINDEX Frame Index Register */ +#define EHCI_FRINDEX_FRAME_MASK 0x7FF +#define EHCI_FRINDEX_INDEX_MASK 0x3FF + +typedef struct _EHCI_HW_REGISTERS { + EHCI_USB_COMMAND HcCommand; // RO, R/W (field dependent), WO + EHCI_USB_STATUS HcStatus; // RO, R/W, R/WC, (field dependent) + EHCI_INTERRUPT_ENABLE HcInterruptEnable; // R/W + ULONG FrameIndex; // R/W (Writes must be DWord Writes) + ULONG SegmentSelector; // R/W (Writes must be DWord Writes) + ULONG PeriodicListBase; // R/W (Writes must be DWord Writes) + ULONG AsyncListBase; // Read/Write (Writes must be DWord Writes) + ULONG Reserved[9]; + ULONG ConfiFlag; // R/W + EHCI_PORT_STATUS_CONTROL PortControl[15]; // (1-15) RO, R/W, R/WC (field dependent) +} EHCI_HW_REGISTERS, *PEHCI_HW_REGISTERS; + +/* 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 + +/* Used for QHs and qTDs to mark Pointers as the end */ +#define TERMINATE_POINTER 1 + +#define LINK_POINTER_MASK 0xFFFFFFE0 + +typedef union _EHCI_LINK_POINTER { + struct { + ULONG Terminate : 1; + ULONG Type : 2; + ULONG Reserved : 2; + ULONG Adress : 27; + }; + ULONG AsULONG; +} EHCI_LINK_POINTER; + +C_ASSERT(sizeof(EHCI_LINK_POINTER) == sizeof(ULONG)); + +/* 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; + +C_ASSERT(sizeof(EHCI_TRANSACTION_CONTROL) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_TRANSACTION_BUFFER) == sizeof(ULONG)); + +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 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; + +C_ASSERT(sizeof(EHCI_FS_ENDPOINT_PARAMS) == sizeof(ULONG)); + +typedef union _EHCI_MICROFRAME_CONTROL { + struct { + ULONG StartMask : 8; + ULONG CompletionMask : 8; + ULONG Reserved : 16; + }; + ULONG AsULONG; +} EHCI_MICROFRAME_CONTROL; + +C_ASSERT(sizeof(EHCI_MICROFRAME_CONTROL) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_SPLIT_TRANSFER_STATE) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_SPLIT_BUFFER_POINTER) == sizeof(ULONG)); + +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 BackPointer; + ULONG ExtendedBuffer[2]; +} EHCI_SPLIT_ISOCHRONOUS_TD, *PEHCI_SPLIT_ISOCHRONOUS_TD; + +C_ASSERT(sizeof(EHCI_SPLIT_ISOCHRONOUS_TD) == 36); + +/* Queue Element Transfer Descriptor (qTD) */ +#define EHCI_MAX_QTD_BUFFER_PAGES 5 + +#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) + +#define EHCI_TD_TOKEN_PID_OUT 0 +#define EHCI_TD_TOKEN_PID_IN 1 +#define EHCI_TD_TOKEN_PID_SETUP 2 +#define EHCI_TD_TOKEN_PID_RESERVED 3 + +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; + +C_ASSERT(sizeof(EHCI_TD_TOKEN) == sizeof(ULONG)); + +typedef struct _EHCI_QUEUE_TD { // must be aligned on 32-byte boundaries + ULONG NextTD; + ULONG AlternateNextTD; + EHCI_TD_TOKEN Token; + ULONG Buffer[5]; + ULONG ExtendedBuffer[5]; +} EHCI_QUEUE_TD, *PEHCI_QUEUE_TD; + +C_ASSERT(sizeof(EHCI_QUEUE_TD) == 52); + +/* Queue Head */ +#define EHCI_QH_EP_FULL_SPEED 0 +#define EHCI_QH_EP_LOW_SPEED 1 +#define EHCI_QH_EP_HIGH_SPEED 2 + +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; + +C_ASSERT(sizeof(EHCI_QH_EP_PARAMS) == sizeof(ULONG)); + +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; + +C_ASSERT(sizeof(EHCI_QH_EP_CAPS) == sizeof(ULONG)); + +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 CurrentTD; + ULONG NextTD; + ULONG AlternateNextTD; + EHCI_TD_TOKEN Token; + ULONG Buffer[5]; + ULONG ExtendedBuffer[5]; +} EHCI_QUEUE_HEAD, *PEHCI_QUEUE_HEAD; + +C_ASSERT(sizeof(EHCI_QUEUE_HEAD) == 68); diff --git a/drivers/usb/usbehci_new/roothub.c b/drivers/usb/usbehci_new/roothub.c new file mode 100644 index 0000000..816755e --- /dev/null +++ b/drivers/usb/usbehci_new/roothub.c @@ -0,0 +1,702 @@ +#include "usbehci.h" + +//#define NDEBUG +#include + +#define NDEBUG_EHCI_ROOT_HUB +#include "dbg_ehci.h" + +MPSTATUS +NTAPI +EHCI_RH_ChirpRootPort(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + ULONG PortBit; + ULONG ix; + + DPRINT_RH("EHCI_RH_ChirpRootPort: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + DPRINT_RH("EHCI_RH_ChirpRootPort: PortSC - %X\n", PortSC.AsULONG); + + PortBit = 1 << (Port - 1); + + if (PortBit & EhciExtension->ResetPortBits) + { + DPRINT_RH("EHCI_RH_ChirpRootPort: Skip port - %x\n", Port); + return MP_STATUS_SUCCESS; + } + + if (PortSC.PortPower == 0) + { + DPRINT_RH("EHCI_RH_ChirpRootPort: Skip port - %x\n", Port); + return MP_STATUS_SUCCESS; + } + + if (PortSC.CurrentConnectStatus == 0 || + PortSC.PortEnabledDisabled == 1 || + PortSC.PortOwner == 1) + { + DPRINT_RH("EHCI_RH_ChirpRootPort: No port - %x\n", Port); + return MP_STATUS_SUCCESS; + } + + if (PortSC.LineStatus == 1 && + PortSC.Suspend == 0 && + PortSC.CurrentConnectStatus == 1) + { + /* Attached device is not a high-speed device. + Release ownership of the port to a selected HC. + Companion HC owns and controls the port. Section 4.2 */ + PortSC.PortOwner = 1; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + DPRINT_RH("EHCI_RH_ChirpRootPort: Companion HC port - %x\n", Port); + return MP_STATUS_SUCCESS; + } + + DPRINT("EHCI_RH_ChirpRootPort: EhciExtension - %p, Port - %x\n", + EhciExtension, + Port); + + PortSC.PortEnabledDisabled = 0; + PortSC.PortReset = 1; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + RegPacket.UsbPortWait(EhciExtension, 10); + + do + { + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortReset = 0; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + for (ix = 0; ix <= 500; ix += 20) + { + KeStallExecutionProcessor(20); + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + DPRINT_RH("EHCI_RH_ChirpRootPort: Reset port - %x\n", Port); + + if (PortSC.PortReset == 0) + break; + } + } + while (PortSC.PortReset == 1); + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (PortSC.PortEnabledDisabled == 1) + { + PortSC.ConnectStatusChange = 0; + PortSC.PortEnabledDisabled = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + + RegPacket.UsbPortWait(EhciExtension, 10); + + EhciExtension->ResetPortBits |= PortBit; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + DPRINT_RH("EHCI_RH_ChirpRootPort: Disable port - %x\n", Port); + } + else + { + PortSC.PortOwner = 1; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + DPRINT_RH("EHCI_RH_ChirpRootPort: Companion HC port - %x\n", Port); + } + + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +EHCI_RH_GetRootHubData(IN PVOID ehciExtension, + IN PVOID rootHubData) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PUSBPORT_ROOT_HUB_DATA RootHubData; + USBPORT_HUB_20_CHARACTERISTICS HubCharacteristics; + + DPRINT_RH("EHCI_RH_GetRootHubData: EhciExtension - %p, rootHubData - %p\n", + EhciExtension, + rootHubData); + + RootHubData = rootHubData; + + RootHubData->NumberOfPorts = EhciExtension->NumberOfPorts; + + HubCharacteristics.AsUSHORT = 0; + + /* Logical Power Switching Mode */ + if (EhciExtension->PortPowerControl == 1) + { + /* Individual port power switching */ + HubCharacteristics.PowerControlMode = 1; + } + else + { + /* Ganged power switching (all ports’ power at once) */ + HubCharacteristics.PowerControlMode = 0; + } + + HubCharacteristics.NoPowerSwitching = 0; + + /* EHCI RH is not part of a compound device */ + HubCharacteristics.PartOfCompoundDevice = 0; + + /* Global Over-current Protection */ + HubCharacteristics.OverCurrentProtectionMode = 0; + + RootHubData->HubCharacteristics.Usb20HubCharacteristics = HubCharacteristics; + + RootHubData->PowerOnToPowerGood = 2; // Time (in 2 ms intervals) + RootHubData->HubControlCurrent = 0; +} + +MPSTATUS +NTAPI +EHCI_RH_GetStatus(IN PVOID ehciExtension, + IN PUSHORT Status) +{ + DPRINT_RH("EHCI_RH_GetStatus: ... \n"); + *Status = 1; + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_GetPortStatus(IN PVOID ehciExtension, + IN USHORT Port, + IN PUSB_PORT_STATUS_AND_CHANGE PortStatus) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + USB_PORT_STATUS_AND_CHANGE status; + ULONG PortMaskBits; + + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (PortSC.CurrentConnectStatus) + { + DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, PortSC.AsULONG - %X\n", + Port, + PortSC.AsULONG); + } + + PortStatus->AsUlong32 = 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 MP_STATUS_SUCCESS; + } + + status.AsUlong32 = 0; + + status.PortStatus.Usb20PortStatus.CurrentConnectStatus = PortSC.CurrentConnectStatus; + status.PortStatus.Usb20PortStatus.PortEnabledDisabled = PortSC.PortEnabledDisabled; + status.PortStatus.Usb20PortStatus.Suspend = PortSC.Suspend; + status.PortStatus.Usb20PortStatus.OverCurrent = PortSC.OverCurrentActive; + status.PortStatus.Usb20PortStatus.Reset = PortSC.PortReset; + status.PortStatus.Usb20PortStatus.PortPower = PortSC.PortPower; + status.PortStatus.Usb20PortStatus.Reserved1 = (PortSC.PortOwner == 1) ? 4 : 0; + + status.PortChange.Usb20PortChange.PortEnableDisableChange = PortSC.PortEnableDisableChange; + status.PortChange.Usb20PortChange.OverCurrentIndicatorChange = PortSC.OverCurrentChange; + + PortMaskBits = 1 << (Port - 1); + + if (status.PortStatus.Usb20PortStatus.CurrentConnectStatus) + status.PortStatus.Usb20PortStatus.LowSpeedDeviceAttached = 0; + + status.PortStatus.Usb20PortStatus.HighSpeedDeviceAttached = 1; + + if (PortSC.ConnectStatusChange) + EhciExtension->ConnectPortBits |= PortMaskBits; + + if (EhciExtension->FinishResetPortBits & PortMaskBits) + status.PortChange.Usb20PortChange.ResetChange = 1; + + if (EhciExtension->ConnectPortBits & PortMaskBits) + status.PortChange.Usb20PortChange.ConnectStatusChange = 1; + + if (EhciExtension->SuspendPortBits & PortMaskBits) + status.PortChange.Usb20PortChange.SuspendChange = 1; + + *PortStatus = status; + + if (status.PortStatus.Usb20PortStatus.CurrentConnectStatus) + { + DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, status.AsULONG - %X\n", + Port, + status.AsUlong32); + } + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_GetHubStatus(IN PVOID ehciExtension, + IN PUSB_HUB_STATUS_AND_CHANGE HubStatus) +{ + DPRINT_RH("EHCI_RH_GetHubStatus: ... \n"); + HubStatus->AsUlong32 = 0; + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +EHCI_RH_FinishReset(IN PVOID ehciExtension, + IN PVOID Context) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + PUSHORT Port = Context; + + DPRINT("EHCI_RH_FinishReset: *Port - %x\n", *Port); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG; + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + if (PortSC.AsULONG != -1) + { + if (!PortSC.CurrentConnectStatus) + DPRINT("EHCI_RH_FinishReset: PortSC.AsULONG - %X\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)); + } +} + +VOID +NTAPI +EHCI_RH_PortResetComplete(IN PVOID ehciExtension, + IN PVOID Context) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + ULONG ix; + PUSHORT Port = Context; + + DPRINT("EHCI_RH_PortResetComplete: *Port - %x\n", *Port); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG; + + do + { + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortReset = 0; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + for (ix = 0; ix <= 500; ix += 20) + { + KeStallExecutionProcessor(20); + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + DPRINT("EHCI_RH_PortResetComplete: Reset port - %x\n", Port); + + if (PortSC.PortReset == 0) + break; + } + } + while (PortSC.PortReset == 1 && (PortSC.AsULONG != -1)); + + RegPacket.UsbPortRequestAsyncCallback(EhciExtension, + 50, // TimerValue + Port, + sizeof(Port), + EHCI_RH_FinishReset); +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortReset(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_SetFeaturePortReset: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + 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), + EHCI_RH_PortResetComplete); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortPower(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_RH("EHCI_RH_SetFeaturePortPower: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + 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 MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortEnable(IN PVOID ehciExtension, + IN USHORT Port) +{ + DPRINT_RH("EHCI_RH_SetFeaturePortEnable: Not supported\n"); + ASSERT(Port != 0); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_SetFeaturePortSuspend(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_SetFeaturePortSuspend: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + 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 MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortEnable(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortEnable: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + 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 MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortPower(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortPower: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + PortSC.PortPower = 0; + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +EHCI_RH_PortResumeComplete(IN PVOID ehciExtension, + IN PVOID Context) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + PUSHORT Port = Context; + + DPRINT("EHCI_RH_PortResumeComplete: *Port - %x\n", *Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG; + + 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 = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortSuspend: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + 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), + EHCI_RH_PortResumeComplete); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortEnableChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT("EHCI_RH_ClearFeaturePortEnableChange: Port - %p\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.OverCurrentChange = 0; + PortSC.PortEnableDisableChange = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortConnectChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_RH("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + 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 MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortResetChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + + DPRINT("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port); + ASSERT(Port != 0); + + EhciExtension->FinishResetPortBits &= ~(1 << (Port - 1)); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortSuspendChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + + DPRINT("EHCI_RH_ClearFeaturePortSuspendChange: Port - %x\n", Port); + ASSERT(Port != 0); + + EhciExtension->SuspendPortBits &= ~(1 << (Port - 1)); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_RH_ClearFeaturePortOvercurrentChange(IN PVOID ehciExtension, + IN USHORT Port) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG PortStatusReg; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_RH("EHCI_RH_ClearFeaturePortOvercurrentChange: Port - %x\n", Port); + ASSERT(Port != 0); + + PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG; + + PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg); + + PortSC.ConnectStatusChange = 0; + PortSC.PortEnableDisableChange = 0; + PortSC.OverCurrentChange = 1; + + WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG); + + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +EHCI_RH_DisableIrq(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PULONG IntrStsReg; + EHCI_INTERRUPT_ENABLE IntrSts; + + DPRINT_RH("EHCI_RH_DisableIrq: ... \n"); + + IntrStsReg = &EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG; + 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 = ehciExtension; + PULONG IntrStsReg; + EHCI_INTERRUPT_ENABLE IntrSts; + + DPRINT_RH("EHCI_RH_EnableIrq: ... \n"); + + IntrStsReg = &EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG; + 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/drivers/usb/usbehci_new/usbehci.c b/drivers/usb/usbehci_new/usbehci.c new file mode 100644 index 0000000..56abb36 --- /dev/null +++ b/drivers/usb/usbehci_new/usbehci.c @@ -0,0 +1,3699 @@ +#include "usbehci.h" + +#define NDEBUG +#include + +#define NDEBUG_EHCI_TRACE +#include "dbg_ehci.h" + +USBPORT_REGISTRATION_PACKET RegPacket; + +static const UCHAR ClassicPeriod[8] = { + ENDPOINT_INTERRUPT_1ms - 1, + ENDPOINT_INTERRUPT_2ms - 1, + ENDPOINT_INTERRUPT_4ms - 1, + ENDPOINT_INTERRUPT_8ms - 1, + ENDPOINT_INTERRUPT_16ms - 1, + ENDPOINT_INTERRUPT_32ms - 1, + ENDPOINT_INTERRUPT_32ms - 1, + ENDPOINT_INTERRUPT_32ms - 1 +}; + +static EHCI_PERIOD pTable[INTERRUPT_ENDPOINTs + 1] = { + { ENDPOINT_INTERRUPT_1ms, 0x00, 0xFF }, + { ENDPOINT_INTERRUPT_2ms, 0x00, 0x55 }, + { ENDPOINT_INTERRUPT_2ms, 0x00, 0xAA }, + { ENDPOINT_INTERRUPT_4ms, 0x00, 0x11 }, + { ENDPOINT_INTERRUPT_4ms, 0x00, 0x44 }, + { ENDPOINT_INTERRUPT_4ms, 0x00, 0x22 }, + { ENDPOINT_INTERRUPT_4ms, 0x00, 0x88 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x01 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x10 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x04 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x40 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x02 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x20 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x08 }, + { ENDPOINT_INTERRUPT_8ms, 0x00, 0x80 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x01 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x01 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x10 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x10 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x04 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x04 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x40 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x40 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x02 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x02 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x20 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x20 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x08 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x08 }, + { ENDPOINT_INTERRUPT_16ms, 0x01, 0x80 }, + { ENDPOINT_INTERRUPT_16ms, 0x02, 0x80 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x01 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x01 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x01 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x01 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x10 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x10 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x10 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x10 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x04 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x04 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x04 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x04 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x40 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x40 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x40 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x40 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x02 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x02 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x02 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x02 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x20 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x20 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x20 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x20 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x08 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x08 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x08 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x08 }, + { ENDPOINT_INTERRUPT_32ms, 0x03, 0x80 }, + { ENDPOINT_INTERRUPT_32ms, 0x05, 0x80 }, + { ENDPOINT_INTERRUPT_32ms, 0x04, 0x80 }, + { ENDPOINT_INTERRUPT_32ms, 0x06, 0x80 }, + { 0x00, 0x00, 0x00 } +}; + +static const UCHAR Balance[EHCI_FRAMES] = { + 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}; + +static const UCHAR LinkTable[INTERRUPT_ENDPOINTs + 1] = { + 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}; + +PEHCI_HCD_TD +NTAPI +EHCI_AllocTd(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_HCD_TD TD; + ULONG ix; + + DPRINT_EHCI("EHCI_AllocTd: ... \n"); + + if (EhciEndpoint->MaxTDs == 0) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return NULL; + } + + TD = EhciEndpoint->FirstTD; + + for (ix = 1; 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(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN PEHCI_HCD_QH QH, + IN ULONG 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((QhPA & ~LINK_POINTER_MASK) == 0); + + QH->sqh.PhysicalAddress = QhPA; + + QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress; + QH->sqh.HwQH.EndpointParams.EndpointNumber = EndpointProperties->EndpointAddress; + + DeviceSpeed = EndpointProperties->DeviceSpeed; + + switch (DeviceSpeed) + { + case UsbLowSpeed: + QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_LOW_SPEED; + break; + + case UsbFullSpeed: + QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_FULL_SPEED; + break; + + case UsbHighSpeed: + QH->sqh.HwQH.EndpointParams.EndpointSpeed = EHCI_QH_EP_HIGH_SPEED; + break; + + default: + DPRINT1("EHCI_InitializeQH: Unknown DeviceSpeed - %x\n", DeviceSpeed); + ASSERT(FALSE); + break; + } + + QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize; + 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; + QH->sqh.HwQH.EndpointCaps.PortNumber = EndpointProperties->PortNumber; + + if (EndpointProperties->TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + QH->sqh.HwQH.EndpointParams.ControlEndpointFlag = 1; + } + + QH->sqh.HwQH.NextTD = TERMINATE_POINTER; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + + 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; + ULONG QhPA; + PEHCI_HCD_TD TdVA; + ULONG TdPA; + PEHCI_HCD_TD TD; + ULONG TdCount; + ULONG ix; + + DPRINT("EHCI_OpenBulkOrControlEndpoint: EhciEndpoint - %p, IsControl - %x\n", + EhciEndpoint, + IsControl); + + InitializeListHead(&EhciEndpoint->ListTDs); + + EhciEndpoint->DmaBufferVA = (PVOID)EndpointProperties->BufferVA; + EhciEndpoint->DmaBufferPA = EndpointProperties->BufferPA; + + RtlZeroMemory(EhciEndpoint->DmaBufferVA, sizeof(EHCI_HCD_TD)); + + QH = (PEHCI_HCD_QH)EhciEndpoint->DmaBufferVA + 1; + QhPA = EhciEndpoint->DmaBufferPA + sizeof(EHCI_HCD_TD); + + 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 |= USBPORT_ENDPOINT_CONTROL; + + EhciEndpoint->MaxTDs = TdCount; + EhciEndpoint->RemainTDs = TdCount; + + TdVA = EhciEndpoint->FirstTD; + TdPA = QhPA + sizeof(EHCI_HCD_QH); + + for (ix = 0; ix < TdCount; ix++) + { + DPRINT_EHCI("EHCI_OpenBulkOrControlEndpoint: TdVA - %p, TdPA - %p\n", + TdVA, + TdPA); + + RtlZeroMemory(TdVA, sizeof(EHCI_HCD_TD)); + + ASSERT((TdPA & ~LINK_POINTER_MASK) == 0); + + TdVA->PhysicalAddress = TdPA; + TdVA->EhciEndpoint = EhciEndpoint; + TdVA->EhciTransfer = NULL; + + TdPA += sizeof(EHCI_HCD_TD); + TdVA += 1; + } + + 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 MP_STATUS_NO_RESOURCES; + + TD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY; + TD->HwTD.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + + TD->HwTD.NextTD = TERMINATE_POINTER; + TD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + TD->NextHcdTD = NULL; + TD->AltNextHcdTD = NULL; + + EhciEndpoint->HcdTailP = TD; + EhciEndpoint->HcdHeadP = TD; + + QH->sqh.HwQH.CurrentTD = TD->PhysicalAddress; + QH->sqh.HwQH.NextTD = TERMINATE_POINTER; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + + QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + QH->sqh.HwQH.Token.TransferBytes = 0; + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_OpenInterruptEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_HCD_QH QH; + ULONG QhPA; + PEHCI_HCD_TD FirstTD; + ULONG FirstTdPA; + PEHCI_HCD_TD TD; + PEHCI_HCD_TD DummyTD; + ULONG TdCount; + ULONG ix; + PEHCI_PERIOD PeriodTable = NULL; + ULONG ScheduleOffset; + ULONG Idx = 0; + UCHAR Period; + + DPRINT("EHCI_OpenInterruptEndpoint: EhciExtension - %p, EndpointProperties - %p, EhciEndpoint - %p\n", + EhciExtension, + EndpointProperties, + EhciEndpoint); + + Period = EndpointProperties->Period; + ScheduleOffset = EndpointProperties->ScheduleOffset; + + ASSERT(Period < (INTERRUPT_ENDPOINTs + 1)); + + while (!(Period & 1)) + { + Idx++; + Period >>= 1; + } + + ASSERT(Idx < 8); + + InitializeListHead(&EhciEndpoint->ListTDs); + + if (EhciEndpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed) + { + PeriodTable = &pTable[ClassicPeriod[Idx] + ScheduleOffset]; + EhciEndpoint->PeriodTable = PeriodTable; + + DPRINT("EHCI_OpenInterruptEndpoint: EhciEndpoint - %p, ScheduleMask - %X, Index - %X\n", + EhciEndpoint, + PeriodTable->ScheduleMask, + ClassicPeriod[Idx]); + + EhciEndpoint->StaticQH = EhciExtension->PeriodicHead[PeriodTable->PeriodIdx]; + } + else + { + EhciEndpoint->PeriodTable = NULL; + + DPRINT("EHCI_OpenInterruptEndpoint: EhciEndpoint - %p, Index - %X\n", + EhciEndpoint, + ClassicPeriod[Idx]); + + EhciEndpoint->StaticQH = EhciExtension->PeriodicHead[ClassicPeriod[Idx] + + ScheduleOffset]; + } + + EhciEndpoint->DmaBufferVA = (PVOID)EndpointProperties->BufferVA; + EhciEndpoint->DmaBufferPA = EndpointProperties->BufferPA; + + RtlZeroMemory((PVOID)EndpointProperties->BufferVA, sizeof(EHCI_HCD_TD)); + + QH = (PEHCI_HCD_QH)(EndpointProperties->BufferVA + sizeof(EHCI_HCD_TD)); + QhPA = EndpointProperties->BufferPA + sizeof(EHCI_HCD_TD); + + FirstTD = (PEHCI_HCD_TD)(EndpointProperties->BufferVA + + sizeof(EHCI_HCD_TD) + + sizeof(EHCI_HCD_QH)); + + FirstTdPA = EndpointProperties->BufferPA + + sizeof(EHCI_HCD_TD) + + sizeof(EHCI_HCD_QH); + + TdCount = (EndpointProperties->BufferLength - + (sizeof(EHCI_HCD_TD) + sizeof(EHCI_HCD_QH))) / + sizeof(EHCI_HCD_TD); + + ASSERT(TdCount >= EHCI_MAX_INTERRUPT_TD_COUNT + 1); + + EhciEndpoint->FirstTD = FirstTD; + EhciEndpoint->MaxTDs = TdCount; + + for (ix = 0; ix < TdCount; ix++) + { + TD = EhciEndpoint->FirstTD + ix; + + RtlZeroMemory(TD, sizeof(EHCI_HCD_TD)); + + ASSERT((FirstTdPA & ~LINK_POINTER_MASK) == 0); + + TD->PhysicalAddress = FirstTdPA; + TD->EhciEndpoint = EhciEndpoint; + TD->EhciTransfer = NULL; + + FirstTdPA += sizeof(EHCI_HCD_TD); + } + + EhciEndpoint->RemainTDs = TdCount; + + EhciEndpoint->QH = EHCI_InitializeQH(EhciExtension, + EhciEndpoint, + QH, + QhPA); + + if (EhciEndpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed) + { + QH->sqh.HwQH.EndpointCaps.InterruptMask = PeriodTable->ScheduleMask; + } + else + { + QH->sqh.HwQH.EndpointCaps.InterruptMask = + EndpointProperties->InterruptScheduleMask; + + QH->sqh.HwQH.EndpointCaps.SplitCompletionMask = + EndpointProperties->SplitCompletionMask; + } + + DummyTD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + DummyTD->TdFlags |= EHCI_HCD_TD_FLAG_DUMMY; + DummyTD->NextHcdTD = NULL; + DummyTD->AltNextHcdTD = NULL; + + DummyTD->HwTD.Token.Status &= ~EHCI_TOKEN_STATUS_ACTIVE; + + DummyTD->HwTD.NextTD = TERMINATE_POINTER; + DummyTD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + EhciEndpoint->HcdTailP = DummyTD; + EhciEndpoint->HcdHeadP = DummyTD; + + QH->sqh.HwQH.CurrentTD = DummyTD->PhysicalAddress; + QH->sqh.HwQH.NextTD = TERMINATE_POINTER; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + + QH->sqh.HwQH.Token.Status &= ~EHCI_TOKEN_STATUS_ACTIVE; + QH->sqh.HwQH.Token.TransferBytes = 0; + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_OpenHsIsoEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_OpenHsIsoEndpoint: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_NOT_SUPPORTED; +} + +MPSTATUS +NTAPI +EHCI_OpenIsoEndpoint(IN PEHCI_EXTENSION EhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + DPRINT1("EHCI_OpenIsoEndpoint: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_NOT_SUPPORTED; +} + +MPSTATUS +NTAPI +EHCI_OpenEndpoint(IN PVOID ehciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PVOID ehciEndpoint) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint; + ULONG TransferType; + MPSTATUS MPStatus; + + DPRINT("EHCI_OpenEndpoint: ... \n"); + + RtlCopyMemory(&EhciEndpoint->EndpointProperties, + EndpointProperties, + sizeof(EhciEndpoint->EndpointProperties)); + + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + MPStatus = EHCI_OpenHsIsoEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint); + } + else + { + MPStatus = EHCI_OpenIsoEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint); + } + + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + MPStatus = EHCI_OpenBulkOrControlEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint, + TRUE); + break; + + case USBPORT_TRANSFER_TYPE_BULK: + MPStatus = EHCI_OpenBulkOrControlEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint, + FALSE); + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + MPStatus = EHCI_OpenInterruptEndpoint(EhciExtension, + EndpointProperties, + EhciEndpoint); + break; + + default: + MPStatus = MP_STATUS_NOT_SUPPORTED; + break; + } + + return MPStatus; +} + +MPSTATUS +NTAPI +EHCI_ReopenEndpoint(IN PVOID ehciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PVOID ehciEndpoint) +{ + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + PEHCI_HCD_QH QH; + MPSTATUS MPStatus; + + EhciEndpoint = ehciEndpoint; + + 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"); + MPStatus = MP_STATUS_NOT_SUPPORTED; + } + else + { + DPRINT1("EHCI_ReopenEndpoint: Iso. UNIMPLEMENTED. FIXME\n"); + MPStatus = MP_STATUS_NOT_SUPPORTED; + } + + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + case USBPORT_TRANSFER_TYPE_BULK: + case USBPORT_TRANSFER_TYPE_INTERRUPT: + RtlCopyMemory(&EhciEndpoint->EndpointProperties, + EndpointProperties, + sizeof(EhciEndpoint->EndpointProperties)); + + QH = EhciEndpoint->QH; + + QH->sqh.HwQH.EndpointParams.DeviceAddress = EndpointProperties->DeviceAddress; + QH->sqh.HwQH.EndpointParams.MaximumPacketLength = EndpointProperties->MaxPacketSize; + + QH->sqh.HwQH.EndpointCaps.HubAddr = EndpointProperties->HubAddr; + + break; + + default: + DPRINT1("EHCI_ReopenEndpoint: Unknown TransferType\n"); + MPStatus = MP_STATUS_SUCCESS; + break; + } + + return MPStatus; +} + +VOID +NTAPI +EHCI_QueryEndpointRequirements(IN PVOID ehciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PUSBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements) +{ + ULONG TransferType; + + DPRINT("EHCI_QueryEndpointRequirements: ... \n"); + + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + DPRINT("EHCI_QueryEndpointRequirements: IsoTransfer\n"); + + if (EndpointProperties->DeviceSpeed == UsbHighSpeed) + { + EndpointRequirements->HeaderBufferSize = EHCI_MAX_HS_ISO_HEADER_BUFFER_SIZE; + EndpointRequirements->MaxTransferSize = EHCI_MAX_HS_ISO_TRANSFER_SIZE; + } + else + { + EndpointRequirements->HeaderBufferSize = EHCI_MAX_FS_ISO_HEADER_BUFFER_SIZE; + EndpointRequirements->MaxTransferSize = EHCI_MAX_FS_ISO_TRANSFER_SIZE; + } + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + DPRINT("EHCI_QueryEndpointRequirements: ControlTransfer\n"); + EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) + + sizeof(EHCI_HCD_QH) + + EHCI_MAX_CONTROL_TD_COUNT * sizeof(EHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = EHCI_MAX_CONTROL_TRANSFER_SIZE; + break; + + case USBPORT_TRANSFER_TYPE_BULK: + DPRINT("EHCI_QueryEndpointRequirements: BulkTransfer\n"); + EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) + + sizeof(EHCI_HCD_QH) + + EHCI_MAX_BULK_TD_COUNT * sizeof(EHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = EHCI_MAX_BULK_TRANSFER_SIZE; + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + DPRINT("EHCI_QueryEndpointRequirements: InterruptTransfer\n"); + EndpointRequirements->HeaderBufferSize = sizeof(EHCI_HCD_TD) + + sizeof(EHCI_HCD_QH) + + EHCI_MAX_INTERRUPT_TD_COUNT * sizeof(EHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = EHCI_MAX_INTERRUPT_TRANSFER_SIZE; + break; + + default: + DPRINT1("EHCI_QueryEndpointRequirements: Unknown TransferType - %x\n", + TransferType); + DbgBreakPoint(); + break; + } +} + +VOID +NTAPI +EHCI_DisablePeriodicList(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND Command; + + DPRINT("EHCI_DisablePeriodicList: ... \n"); + + if (EhciExtension->Flags & EHCI_FLAGS_IDLE_SUPPORT) + { + OperationalRegs = EhciExtension->OperationalRegs; + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.PeriodicEnable = 0; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + } +} + +VOID +NTAPI +EHCI_CloseEndpoint(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN BOOLEAN IsDoDisablePeriodic) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint; + ULONG TransferType; + + DPRINT1("EHCI_CloseEndpoint: EhciEndpoint - %p, IsDoDisablePeriodic - %X\n", + EhciEndpoint, + IsDoDisablePeriodic); + + if (IsDoDisablePeriodic) + { + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + EHCI_DisablePeriodicList(EhciExtension); + } + } +} + +PEHCI_STATIC_QH +NTAPI +EHCI_GetQhForFrame(IN PEHCI_EXTENSION EhciExtension, + IN ULONG FrameIdx) +{ + //DPRINT_EHCI("EHCI_GetQhForFrame: FrameIdx - %x, Balance[FrameIdx] - %x\n", + // FrameIdx, + // Balance[FrameIdx & 0x1F]); + + return EhciExtension->PeriodicHead[Balance[FrameIdx & (EHCI_FRAMES - 1)]]; +} + +PEHCI_HCD_QH +NTAPI +EHCI_GetDummyQhForFrame(IN PEHCI_EXTENSION EhciExtension, + IN ULONG Idx) +{ + return (PEHCI_HCD_QH)((ULONG_PTR)EhciExtension->IsoDummyQHListVA + + 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 - %X, *VirtualAddress - %X, 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 - %X, PAddress - %X\n", + VAddress, + PAddress); + } + + *VirtualAddress = VAddress; + *PhysicalAddress = PAddress; +} + +VOID +NTAPI +EHCI_AddDummyQHs(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_HC_RESOURCES HcResourcesVA; + PEHCI_HCD_QH DummyQH; + ULONG DummyQhPA; + EHCI_QH_EP_PARAMS EndpointParams; + EHCI_LINK_POINTER PAddress; + ULONG Frame; + + DPRINT("EHCI_AddDummyQueueHeads: EhciExtension - %p\n", EhciExtension); + + HcResourcesVA = EhciExtension->HcResourcesVA; + + DummyQH = EhciExtension->IsoDummyQHListVA; + DummyQhPA = EhciExtension->IsoDummyQHListPA; + + for (Frame = 0; Frame < EHCI_FRAME_LIST_MAX_ENTRIES; Frame++) + { + RtlZeroMemory(DummyQH, sizeof(EHCI_HCD_QH)); + + PAddress.AsULONG = (ULONG)HcResourcesVA->PeriodicFrameList[Frame]; + + DummyQH->sqh.HwQH.HorizontalLink.AsULONG = PAddress.AsULONG; + DummyQH->sqh.HwQH.CurrentTD = 0; + DummyQH->sqh.HwQH.NextTD = TERMINATE_POINTER; + DummyQH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + + EndpointParams = DummyQH->sqh.HwQH.EndpointParams; + EndpointParams.DeviceAddress = 0; + EndpointParams.EndpointSpeed = 0; + EndpointParams.MaximumPacketLength = EHCI_DUMMYQH_MAX_PACKET_LENGTH; + DummyQH->sqh.HwQH.EndpointParams = EndpointParams; + + DummyQH->sqh.HwQH.EndpointCaps.AsULONG = 0; + DummyQH->sqh.HwQH.EndpointCaps.InterruptMask = 0; + DummyQH->sqh.HwQH.EndpointCaps.SplitCompletionMask = 0; + DummyQH->sqh.HwQH.EndpointCaps.PipeMultiplier = 1; + + DummyQH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + + DummyQH->sqh.PhysicalAddress = DummyQhPA; + DummyQH->sqh.StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame); + + PAddress.AsULONG = DummyQhPA; + PAddress.Reserved = 0; + PAddress.Type = EHCI_LINK_TYPE_QH; + + HcResourcesVA->PeriodicFrameList[Frame] = (PEHCI_STATIC_QH)PAddress.AsULONG; + + DummyQH++; + DummyQhPA += sizeof(EHCI_HCD_QH); + } +} + +VOID +NTAPI +EHCI_InitializeInterruptSchedule(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_STATIC_QH StaticQH; + ULONG ix; + + DPRINT("EHCI_InitializeInterruptSchedule: ... \n"); + + for (ix = 0; ix < INTERRUPT_ENDPOINTs; ix++) + { + StaticQH = EhciExtension->PeriodicHead[ix]; + + StaticQH->HwQH.EndpointParams.HeadReclamationListFlag = 0; + StaticQH->HwQH.NextTD |= TERMINATE_POINTER; + StaticQH->HwQH.Token.Status |= (UCHAR)EHCI_TOKEN_STATUS_HALTED; + } + + for (ix = 1; ix < INTERRUPT_ENDPOINTs; ix++) + { + StaticQH = EhciExtension->PeriodicHead[ix]; + + StaticQH->PrevHead = NULL; + StaticQH->NextHead = (PEHCI_HCD_QH)EhciExtension->PeriodicHead[LinkTable[ix]]; + + StaticQH->HwQH.HorizontalLink.AsULONG = + EhciExtension->PeriodicHead[LinkTable[ix]]->PhysicalAddress; + + StaticQH->HwQH.HorizontalLink.Type = EHCI_LINK_TYPE_QH; + StaticQH->HwQH.EndpointCaps.InterruptMask = 0xFF; + + StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC; + + if (ix < (ENDPOINT_INTERRUPT_8ms - 1)) + StaticQH->QhFlags |= EHCI_QH_FLAG_STATIC_FAST; + } + + EhciExtension->PeriodicHead[0]->HwQH.HorizontalLink.Terminate = 1; + + EhciExtension->PeriodicHead[0]->QhFlags |= (EHCI_QH_FLAG_STATIC | + EHCI_QH_FLAG_STATIC_FAST); +} + +MPSTATUS +NTAPI +EHCI_InitializeSchedule(IN PEHCI_EXTENSION EhciExtension, + IN ULONG_PTR BaseVA, + IN ULONG BasePA) +{ + PEHCI_HW_REGISTERS OperationalRegs; + PEHCI_HC_RESOURCES HcResourcesVA; + PEHCI_HC_RESOURCES HcResourcesPA; + PEHCI_STATIC_QH AsyncHead; + ULONG AsyncHeadPA; + PEHCI_STATIC_QH PeriodicHead; + ULONG PeriodicHeadPA; + PEHCI_STATIC_QH StaticQH; + EHCI_LINK_POINTER NextLink; + EHCI_LINK_POINTER StaticHeadPA; + ULONG Frame; + ULONG ix; + + DPRINT("EHCI_InitializeSchedule: BaseVA - %p, BasePA - %p\n", + BaseVA, + BasePA); + + OperationalRegs = EhciExtension->OperationalRegs; + + HcResourcesVA = (PEHCI_HC_RESOURCES)BaseVA; + HcResourcesPA = (PEHCI_HC_RESOURCES)BasePA; + + EhciExtension->HcResourcesVA = HcResourcesVA; + EhciExtension->HcResourcesPA = BasePA; + + /* Asynchronous Schedule */ + + AsyncHead = &HcResourcesVA->AsyncHead; + AsyncHeadPA = (ULONG)&HcResourcesPA->AsyncHead; + + RtlZeroMemory(AsyncHead, sizeof(EHCI_STATIC_QH)); + + NextLink.AsULONG = AsyncHeadPA; + NextLink.Type = EHCI_LINK_TYPE_QH; + + AsyncHead->HwQH.HorizontalLink = NextLink; + AsyncHead->HwQH.EndpointParams.HeadReclamationListFlag = 1; + AsyncHead->HwQH.EndpointCaps.PipeMultiplier = 1; + AsyncHead->HwQH.NextTD |= TERMINATE_POINTER; + AsyncHead->HwQH.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_HALTED; + + AsyncHead->PhysicalAddress = AsyncHeadPA; + AsyncHead->PrevHead = AsyncHead->NextHead = (PEHCI_HCD_QH)AsyncHead; + + EhciExtension->AsyncHead = AsyncHead; + + /* Periodic Schedule */ + + PeriodicHead = &HcResourcesVA->PeriodicHead[0]; + PeriodicHeadPA = (ULONG)&HcResourcesPA->PeriodicHead[0]; + + for (ix = 0; ix < (INTERRUPT_ENDPOINTs + 1); ix++) + { + EHCI_AlignHwStructure(EhciExtension, + &PeriodicHeadPA, + (PULONG)&PeriodicHead, + 80); + + EhciExtension->PeriodicHead[ix] = PeriodicHead; + EhciExtension->PeriodicHead[ix]->PhysicalAddress = PeriodicHeadPA; + + PeriodicHead += 1; + PeriodicHeadPA += sizeof(EHCI_STATIC_QH); + } + + EHCI_InitializeInterruptSchedule(EhciExtension); + + for (Frame = 0; Frame < EHCI_FRAME_LIST_MAX_ENTRIES; Frame++) + { + StaticQH = EHCI_GetQhForFrame(EhciExtension, Frame); + + StaticHeadPA.AsULONG = StaticQH->PhysicalAddress; + StaticHeadPA.Type = EHCI_LINK_TYPE_QH; + + //DPRINT_EHCI("EHCI_InitializeSchedule: StaticHeadPA[%x] - %X\n", + // Frame, + // StaticHeadPA); + + HcResourcesVA->PeriodicFrameList[Frame] = (PEHCI_STATIC_QH)StaticHeadPA.AsULONG; + } + + EhciExtension->IsoDummyQHListVA = &HcResourcesVA->IsoDummyQH[0]; + EhciExtension->IsoDummyQHListPA = (ULONG)&HcResourcesPA->IsoDummyQH[0]; + + EHCI_AddDummyQHs(EhciExtension); + + WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase, + EhciExtension->HcResourcesPA); + + WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase, + NextLink.AsULONG); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_InitializeHardware(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters; + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND Command; + LARGE_INTEGER EndTime; + LARGE_INTEGER CurrentTime; + EHCI_HC_STRUCTURAL_PARAMS StructuralParams; + + DPRINT("EHCI_InitializeHardware: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + CapabilityRegisters = EhciExtension->CapabilityRegisters; + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.Reset = 1; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 10000; // 100 msec + + DPRINT("EHCI_InitializeHardware: Start reset ... \n"); + + while (TRUE) + { + KeQuerySystemTime(&CurrentTime); + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + + if (Command.Reset != 1) + break; + + if (CurrentTime.QuadPart >= EndTime.QuadPart) + { + if (Command.Reset == 1) + { + DPRINT1("EHCI_InitializeHardware: Reset failed!\n"); + return MP_STATUS_HW_ERROR; + } + + break; + } + } + + DPRINT("EHCI_InitializeHardware: Reset - OK\n"); + + StructuralParams.AsULONG = READ_REGISTER_ULONG(&CapabilityRegisters->StructParameters.AsULONG); + + EhciExtension->NumberOfPorts = StructuralParams.PortCount; + EhciExtension->PortPowerControl = StructuralParams.PortPowerControl; + + DPRINT("EHCI_InitializeHardware: StructuralParams - %X\n", StructuralParams.AsULONG); + DPRINT("EHCI_InitializeHardware: PortPowerControl - %x\n", EhciExtension->PortPowerControl); + DPRINT("EHCI_InitializeHardware: N_PORTS - %x\n", EhciExtension->NumberOfPorts); + + WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase, 0); + WRITE_REGISTER_ULONG(&OperationalRegs->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 MP_STATUS_SUCCESS; +} + +UCHAR +NTAPI +EHCI_GetOffsetEECP(IN PEHCI_EXTENSION EhciExtension, + IN UCHAR CapabilityID) +{ + EHCI_LEGACY_EXTENDED_CAPABILITY LegacyCapability; + EHCI_HC_CAPABILITY_PARAMS CapParameters; + UCHAR OffsetEECP; + + DPRINT("EHCI_GetOffsetEECP: CapabilityID - %x\n", CapabilityID); + + CapParameters = EhciExtension->CapabilityRegisters->CapParameters; + + OffsetEECP = CapParameters.ExtCapabilitiesPointer; + + if (!OffsetEECP) + return 0; + + while (TRUE) + { + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + TRUE, + &LegacyCapability.AsULONG, + OffsetEECP, + sizeof(LegacyCapability)); + + DPRINT("EHCI_GetOffsetEECP: OffsetEECP - %x\n", OffsetEECP); + + if (LegacyCapability.CapabilityID == CapabilityID) + break; + + OffsetEECP = LegacyCapability.NextCapabilityPointer; + + if (!OffsetEECP) + return 0; + } + + return OffsetEECP; +} + +MPSTATUS +NTAPI +EHCI_TakeControlHC(IN PEHCI_EXTENSION EhciExtension) +{ + LARGE_INTEGER EndTime; + LARGE_INTEGER CurrentTime; + EHCI_LEGACY_EXTENDED_CAPABILITY LegacyCapability; + UCHAR OffsetEECP; + + DPRINT("EHCI_TakeControlHC: EhciExtension - %p\n", EhciExtension); + + OffsetEECP = EHCI_GetOffsetEECP(EhciExtension, 1); + + if (OffsetEECP == 0) + return MP_STATUS_SUCCESS; + + DPRINT("EHCI_TakeControlHC: OffsetEECP - %X\n", OffsetEECP); + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + TRUE, + &LegacyCapability.AsULONG, + OffsetEECP, + sizeof(LegacyCapability)); + + if (LegacyCapability.BiosOwnedSemaphore == 0) + return MP_STATUS_SUCCESS; + + LegacyCapability.OsOwnedSemaphore = 1; + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + FALSE, + &LegacyCapability.AsULONG, + OffsetEECP, + sizeof(LegacyCapability)); + + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 10000; + + do + { + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + TRUE, + &LegacyCapability.AsULONG, + OffsetEECP, + sizeof(LegacyCapability)); + KeQuerySystemTime(&CurrentTime); + + if (LegacyCapability.BiosOwnedSemaphore) + { + DPRINT("EHCI_TakeControlHC: Ownership is ok\n"); + break; + } + } + while (CurrentTime.QuadPart <= EndTime.QuadPart); + + return MP_STATUS_SUCCESS; +} + +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 = ehciExtension; + PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters; + PEHCI_HW_REGISTERS OperationalRegs; + MPSTATUS MPStatus; + EHCI_USB_COMMAND Command; + UCHAR CapabilityRegLength; + UCHAR Fladj; + + DPRINT("EHCI_StartController: ... \n"); + + if ((Resources->ResourcesTypes & (USBPORT_RESOURCES_MEMORY | USBPORT_RESOURCES_INTERRUPT)) != + (USBPORT_RESOURCES_MEMORY | USBPORT_RESOURCES_INTERRUPT)) + { + DPRINT1("EHCI_StartController: Resources->ResourcesTypes - %x\n", + Resources->ResourcesTypes); + + return MP_STATUS_ERROR; + } + + CapabilityRegisters = (PEHCI_HC_CAPABILITY_REGISTERS)Resources->ResourceBase; + EhciExtension->CapabilityRegisters = CapabilityRegisters; + + CapabilityRegLength = READ_REGISTER_UCHAR(&CapabilityRegisters->RegistersLength); + + OperationalRegs = (PEHCI_HW_REGISTERS)((ULONG_PTR)CapabilityRegisters + + CapabilityRegLength); + + EhciExtension->OperationalRegs = OperationalRegs; + + DPRINT("EHCI_StartController: CapabilityRegisters - %p\n", CapabilityRegisters); + DPRINT("EHCI_StartController: OperationalRegs - %p\n", OperationalRegs); + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + TRUE, + &Fladj, + EHCI_FLADJ_PCI_CONFIG_OFFSET, + sizeof(Fladj)); + + 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, + TRUE, + &Fladj, + EHCI_FLADJ_PCI_CONFIG_OFFSET, + sizeof(Fladj)); + + if (Fladj != EhciExtension->FrameLengthAdjustment) + { + Fladj = EhciExtension->FrameLengthAdjustment; + + RegPacket.UsbPortReadWriteConfigSpace(EhciExtension, + FALSE, // write + &Fladj, + EHCI_FLADJ_PCI_CONFIG_OFFSET, + sizeof(Fladj)); + } + + /* Port routing control logic default-routes all ports to this HC */ + WRITE_REGISTER_ULONG(&OperationalRegs->ConfiFlag, 1); + EhciExtension->PortRoutingControl = 1; + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.InterruptThreshold = 1; // one micro-frame + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.Run = 1; // execution of the schedule + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + + EhciExtension->IsStarted = TRUE; + + if (Resources->IsChirpHandled) + { + ULONG Port; + + for (Port = 1; Port <= EhciExtension->NumberOfPorts; Port++) + { + EHCI_RH_SetFeaturePortPower(EhciExtension, Port); + } + + RegPacket.UsbPortWait(EhciExtension, 200); + + for (Port = 1; Port <= EhciExtension->NumberOfPorts; Port++) + { + EHCI_RH_ChirpRootPort(EhciExtension, Port++); + } + } + + 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 = ehciExtension; + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND Command; + EHCI_USB_STATUS Status; + EHCI_INTERRUPT_ENABLE IntrEn; + ULONG ix; + + DPRINT("EHCI_SuspendController: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + EhciExtension->BakupPeriodiclistbase = READ_REGISTER_ULONG(&OperationalRegs->PeriodicListBase); + EhciExtension->BakupAsynclistaddr = READ_REGISTER_ULONG(&OperationalRegs->AsyncListBase); + EhciExtension->BakupCtrlDSSegment = READ_REGISTER_ULONG(&OperationalRegs->SegmentSelector); + EhciExtension->BakupUSBCmd = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.InterruptAdvanceDoorbell = 0; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.Run = 0; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + + KeStallExecutionProcessor(125); + + Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + + Status.HCHalted = 0; + Status.Reclamation = 0; + Status.PeriodicStatus = 0; + Status.AsynchronousStatus = 0; + + if (Status.AsULONG) + WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, Status.AsULONG); + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, 0); + + for (ix = 0; ix < 10; ix++) + { + Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + + if (Status.HCHalted) + break; + + RegPacket.UsbPortWait(EhciExtension, 1); + } + + if (!Status.HCHalted) + DbgBreakPoint(); + + IntrEn.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG); + IntrEn.PortChangeInterrupt = 1; + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, IntrEn.AsULONG); + + EhciExtension->Flags |= EHCI_FLAGS_CONTROLLER_SUSPEND; +} + +MPSTATUS +NTAPI +EHCI_ResumeController(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_HW_REGISTERS OperationalRegs; + ULONG RoutingControl; + EHCI_USB_COMMAND Command; + + DPRINT("EHCI_ResumeController: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + RoutingControl = EhciExtension->PortRoutingControl; + + if (!(RoutingControl & 1)) + { + EhciExtension->PortRoutingControl = RoutingControl | 1; + WRITE_REGISTER_ULONG(&OperationalRegs->ConfiFlag, RoutingControl | 1); + + return MP_STATUS_HW_ERROR; + } + + WRITE_REGISTER_ULONG(&OperationalRegs->SegmentSelector, + EhciExtension->BakupCtrlDSSegment); + + WRITE_REGISTER_ULONG(&OperationalRegs->PeriodicListBase, + EhciExtension->BakupPeriodiclistbase); + + WRITE_REGISTER_ULONG(&OperationalRegs->AsyncListBase, + EhciExtension->BakupAsynclistaddr); + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + + 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->HcCommand.AsULONG, + Command.AsULONG); + + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + EhciExtension->InterruptMask.AsULONG); + + EhciExtension->Flags &= ~EHCI_FLAGS_CONTROLLER_SUSPEND; + + return MP_STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +EHCI_HardwarePresent(IN PEHCI_EXTENSION EhciExtension, + IN BOOLEAN IsInvalidateController) +{ + PEHCI_HW_REGISTERS OperationalRegs = EhciExtension->OperationalRegs; + + if (READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG) != -1) + return TRUE; + + DPRINT1("EHCI_HardwarePresent: IsInvalidateController - %x\n", + IsInvalidateController); + + if (!IsInvalidateController) + return FALSE; + + RegPacket.UsbPortInvalidateController(EhciExtension, + USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE); + return FALSE; +} + +BOOLEAN +NTAPI +EHCI_InterruptService(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_HW_REGISTERS OperationalRegs; + BOOLEAN Result = FALSE; + EHCI_USB_STATUS IntrSts; + EHCI_INTERRUPT_ENABLE IntrEn; + EHCI_INTERRUPT_ENABLE iStatus; + EHCI_USB_COMMAND Command; + ULONG FrameIndex; + + OperationalRegs = EhciExtension->OperationalRegs; + + DPRINT_EHCI("EHCI_InterruptService: ... \n"); + + Result = EHCI_HardwarePresent(EhciExtension, FALSE); + + if (!Result) + return FALSE; + + IntrEn.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG); + IntrSts.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + + iStatus.AsULONG = (IntrEn.AsULONG & IntrSts.AsULONG) & EHCI_INTERRUPT_MASK; + + if (!iStatus.AsULONG) + return FALSE; + + EhciExtension->InterruptStatus = iStatus; + + WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, iStatus.AsULONG); + + if (iStatus.HostSystemError) + { + EhciExtension->HcSystemErrors++; + + if (EhciExtension->HcSystemErrors < EHCI_MAX_HC_SYSTEM_ERRORS) + { + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.Run = 1; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + } + } + + FrameIndex = READ_REGISTER_ULONG(&OperationalRegs->FrameIndex) / EHCI_MICROFRAMES; + FrameIndex &= EHCI_FRINDEX_FRAME_MASK; + + if ((FrameIndex ^ EhciExtension->FrameIndex) & EHCI_FRAME_LIST_MAX_ENTRIES) + { + EhciExtension->FrameHighPart += 2 * EHCI_FRAME_LIST_MAX_ENTRIES; + + EhciExtension->FrameHighPart -= (FrameIndex ^ EhciExtension->FrameHighPart) & + EHCI_FRAME_LIST_MAX_ENTRIES; + } + + EhciExtension->FrameIndex = FrameIndex; + + return TRUE; +} + +VOID +NTAPI +EHCI_InterruptDpc(IN PVOID ehciExtension, + IN BOOLEAN IsDoEnableInterrupts) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_INTERRUPT_ENABLE iStatus; + + OperationalRegs = EhciExtension->OperationalRegs; + + DPRINT_EHCI("EHCI_InterruptDpc: [%p] IsDoEnableInterrupts - %x\n", + EhciExtension, IsDoEnableInterrupts); + + iStatus = EhciExtension->InterruptStatus; + EhciExtension->InterruptStatus.AsULONG = 0; + + if (iStatus.Interrupt == 1 || + iStatus.ErrorInterrupt == 1 || + iStatus.InterruptOnAsyncAdvance == 1) + { + DPRINT_EHCI("EHCI_InterruptDpc: [%p] InterruptStatus - %X\n", EhciExtension, iStatus.AsULONG); + RegPacket.UsbPortInvalidateEndpoint(EhciExtension, NULL); + } + + if (iStatus.PortChangeInterrupt == 1) + { + DPRINT_EHCI("EHCI_InterruptDpc: [%p] PortChangeInterrupt\n", EhciExtension); + RegPacket.UsbPortInvalidateRootHub(EhciExtension); + } + + if (IsDoEnableInterrupts) + { + WRITE_REGISTER_ULONG(&OperationalRegs->HcInterruptEnable.AsULONG, + 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; + + SgElement = &SgList->SgElement[0]; + + for (SgIdx = 0; SgIdx < SgList->SgElementCount; SgIdx++) + { + if (TransferedLen >= SgElement->SgOffset && + TransferedLen < SgElement->SgOffset + SgElement->SgTransferLength) + { + break; + } + + SgElement += 1; + } + + SgRemain = SgList->SgElementCount - SgIdx; + + if (SgRemain > EHCI_MAX_QTD_BUFFER_PAGES) + { + TD->HwTD.Buffer[0] = SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart - + SgList->SgElement[SgIdx].SgOffset + + TransferedLen; + + LengthThisTD = EHCI_MAX_QTD_BUFFER_PAGES * PAGE_SIZE - + (TD->HwTD.Buffer[0] & (PAGE_SIZE - 1)); + + for (ix = 1; ix < EHCI_MAX_QTD_BUFFER_PAGES; 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); + } + else + { + LengthThisTD = TransferParameters->TransferBufferLength - TransferedLen; + + TD->HwTD.Buffer[0] = TransferedLen + + SgList->SgElement[SgIdx].SgPhysicalAddress.LowPart - + SgList->SgElement[SgIdx].SgOffset; + + for (ix = 1; ix < EHCI_MAX_QTD_BUFFER_PAGES; 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) +{ + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND UsbCmd; + + DPRINT_EHCI("EHCI_EnableAsyncList: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + UsbCmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + UsbCmd.AsynchronousEnable = 1; + WRITE_REGISTER_ULONG((&OperationalRegs->HcCommand.AsULONG), UsbCmd.AsULONG); +} + +VOID +NTAPI +EHCI_DisableAsyncList(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND UsbCmd; + + DPRINT("EHCI_DisableAsyncList: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + UsbCmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + UsbCmd.AsynchronousEnable = 0; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, UsbCmd.AsULONG); +} + +VOID +NTAPI +EHCI_EnablePeriodicList(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND Command; + + DPRINT("EHCI_EnablePeriodicList: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Command.PeriodicEnable = 1; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); +} + +VOID +NTAPI +EHCI_FlushAsyncCache(IN PEHCI_EXTENSION EhciExtension) +{ + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_COMMAND Command; + EHCI_USB_STATUS Status; + LARGE_INTEGER CurrentTime; + LARGE_INTEGER EndTime; + EHCI_USB_COMMAND Cmd; + + DPRINT_EHCI("EHCI_FlushAsyncCache: EhciExtension - %p\n", EhciExtension); + + OperationalRegs = EhciExtension->OperationalRegs; + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + + if (!Status.AsynchronousStatus && !Command.AsynchronousEnable) + return; + + if (Status.AsynchronousStatus && !Command.AsynchronousEnable) + { + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 10000; //100 ms + + do + { + Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + KeQuerySystemTime(&CurrentTime); + + if (CurrentTime.QuadPart > EndTime.QuadPart) + RegPacket.UsbPortBugCheck(EhciExtension); + } + while (Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run); + + return; + } + + if (!Status.AsynchronousStatus && Command.AsynchronousEnable) + { + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 10000; //100 ms + + do + { + Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + KeQuerySystemTime(&CurrentTime); + } + while (!Status.AsynchronousStatus && Command.AsULONG != -1 && Command.Run); + } + + Command.InterruptAdvanceDoorbell = 1; + WRITE_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG, Command.AsULONG); + + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 10000; //100 ms + + Cmd.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + + if (Cmd.InterruptAdvanceDoorbell) + { + while (Cmd.Run) + { + if (Cmd.AsULONG == -1) + break; + + KeStallExecutionProcessor(1); + Command.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + KeQuerySystemTime(&CurrentTime); + + if (!Command.InterruptAdvanceDoorbell) + break; + + Cmd = Command; + } + } + + /* InterruptOnAsyncAdvance */ + WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, 0x20); +} + +VOID +NTAPI +EHCI_LockQH(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QH, + IN ULONG TransferType) +{ + PEHCI_HCD_QH PrevQH; + PEHCI_HCD_QH NextQH; + ULONG QhPA; + ULONG FrameIndexReg; + PEHCI_HW_REGISTERS OperationalRegs; + ULONG Command; + + DPRINT_EHCI("EHCI_LockQH: QH - %p, TransferType - %x\n", + QH, + TransferType); + + OperationalRegs = EhciExtension->OperationalRegs; + + ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_UPDATING) == 0); + ASSERT(EhciExtension->LockQH == NULL); + + PrevQH = QH->sqh.PrevHead; + QH->sqh.QhFlags |= EHCI_QH_FLAG_UPDATING; + + ASSERT(PrevQH); + + NextQH = QH->sqh.NextHead; + + EhciExtension->PrevQH = PrevQH; + EhciExtension->NextQH = NextQH; + EhciExtension->LockQH = QH; + + if (NextQH) + { + QhPA = NextQH->sqh.PhysicalAddress; + QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + QhPA |= (EHCI_LINK_TYPE_QH << 1); + } + else + { + QhPA = TERMINATE_POINTER; + } + + PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA; + + FrameIndexReg = READ_REGISTER_ULONG(&OperationalRegs->FrameIndex); + + if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + do + { + Command = READ_REGISTER_ULONG(&OperationalRegs->HcCommand.AsULONG); + } + while (READ_REGISTER_ULONG(&OperationalRegs->FrameIndex) == + FrameIndexReg && (Command != -1) && (Command & 1)); + } + else + { + EHCI_FlushAsyncCache(EhciExtension); + } +} + +VOID +NTAPI +EHCI_UnlockQH(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QH) +{ + ULONG QhPA; + + DPRINT_EHCI("EHCI_UnlockQH: QH - %p\n", QH); + + ASSERT(QH->sqh.QhFlags & EHCI_QH_FLAG_UPDATING); + ASSERT(EhciExtension->LockQH); + ASSERT(EhciExtension->LockQH == QH); + + QH->sqh.QhFlags &= ~EHCI_QH_FLAG_UPDATING; + + EhciExtension->LockQH = NULL; + + QhPA = QH->sqh.PhysicalAddress; + QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + QhPA |= (EHCI_LINK_TYPE_QH << 1); + + EhciExtension->PrevQH->sqh.HwQH.HorizontalLink.AsULONG = QhPA; +} + +VOID +NTAPI +EHCI_LinkTransferToQueue(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint, + IN 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 = EhciEndpoint->DmaBufferPA; + QH->sqh.HwQH.NextTD = 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 + { + DPRINT_EHCI("EHCI_LinkTransferToQueue: TD - %p, HcdTailP - %p\n", + EhciEndpoint->HcdHeadP, + EhciEndpoint->HcdTailP); + + LinkTD = EhciEndpoint->HcdHeadP; + + while (TD != EhciEndpoint->HcdTailP) + { + LinkTD = TD; + TD = TD->NextHcdTD; + } + + ASSERT(LinkTD != EhciEndpoint->HcdTailP); + + Transfer = LinkTD->EhciTransfer; + + TD = EhciEndpoint->FirstTD; + + for (ix = 0; ix < EhciEndpoint->MaxTDs; ix++) + { + if (TD->EhciTransfer == Transfer) + { + TD->AltNextHcdTD = NextTD; + TD->HwTD.AlternateNextTD = NextTD->PhysicalAddress; + } + + TD += 1; + } + + LinkTD->HwTD.NextTD = NextTD->PhysicalAddress; + LinkTD->NextHcdTD = NextTD; + + if (QH->sqh.HwQH.CurrentTD == LinkTD->PhysicalAddress) + { + QH->sqh.HwQH.NextTD = NextTD->PhysicalAddress; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + } + } +} + +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 < EHCI_MAX_CONTROL_TD_COUNT) + return MP_STATUS_FAILURE; + + EhciExtension->PendingTransfers++; + EhciEndpoint->PendingTDs++; + + EhciTransfer->TransferOnAsyncList = 1; + + FirstTD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!FirstTD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return MP_STATUS_FAILURE; + } + + EhciTransfer->PendingTDs++; + + FirstTD->TdFlags |= EHCI_HCD_TD_FLAG_PROCESSED; + FirstTD->EhciTransfer = EhciTransfer; + + FirstTD->HwTD.Buffer[0] = (ULONG)&((PEHCI_HCD_TD)(FirstTD->PhysicalAddress))->SetupPacket; + 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 = TERMINATE_POINTER; + FirstTD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + FirstTD->HwTD.Token.AsULONG = 0; + FirstTD->HwTD.Token.ErrorCounter = 3; + FirstTD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_SETUP; + FirstTD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + FirstTD->HwTD.Token.TransferBytes = sizeof(FirstTD->SetupPacket); + + RtlCopyMemory(&FirstTD->SetupPacket, + &TransferParameters->SetupPacket, + sizeof(FirstTD->SetupPacket)); + + LastTD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!LastTD) + { + RegPacket.UsbPortBugCheck(EhciExtension); + return MP_STATUS_FAILURE; + } + + 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 = TERMINATE_POINTER; + LastTD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + LastTD->HwTD.Token.AsULONG = 0; + LastTD->HwTD.Token.ErrorCounter = 3; + + FirstTD->AltNextHcdTD = LastTD; + FirstTD->HwTD.AlternateNextTD = LastTD->PhysicalAddress; + + 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 = TERMINATE_POINTER; + TD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + TD->HwTD.Token.AsULONG = 0; + TD->HwTD.Token.ErrorCounter = 3; + + PrevTD->NextHcdTD = TD; + PrevTD->HwTD.NextTD = TD->PhysicalAddress; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN; + else + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT; + + 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->AltNextHcdTD = LastTD; + TD->HwTD.AlternateNextTD = LastTD->PhysicalAddress; + + TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension, + EhciEndpoint->EndpointProperties.MaxPacketSize, + TransferedLen, + &DataToggle, + EhciTransfer, + TD, + SgList); + + PrevTD = TD; + + if (TransferedLen >= TransferParameters->TransferBufferLength) + goto End; + } + + RegPacket.UsbPortBugCheck(EhciExtension); + return MP_STATUS_FAILURE; + } + +End: + + LinkTD->NextHcdTD = LastTD; + LinkTD->HwTD.NextTD = LastTD->PhysicalAddress; + + LastTD->HwTD.Buffer[0] = 0; + LastTD->LengthThisTD = 0; + + Token.AsULONG = 0; + Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + Token.InterruptOnComplete = 1; + Token.DataToggle = 1; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + Token.PIDCode = EHCI_TD_TOKEN_PID_OUT; + else + Token.PIDCode = EHCI_TD_TOKEN_PID_IN; + + LastTD->HwTD.Token = Token; + + LastTD->NextHcdTD = EhciEndpoint->HcdTailP; + LastTD->HwTD.NextTD = EhciEndpoint->HcdTailP->PhysicalAddress; + + EHCI_EnableAsyncList(EhciExtension); + EHCI_LinkTransferToQueue(EhciExtension, EhciEndpoint, FirstTD); + + ASSERT(EhciEndpoint->HcdTailP->NextHcdTD == NULL); + ASSERT(EhciEndpoint->HcdTailP->AltNextHcdTD == NULL); + + return MP_STATUS_SUCCESS; +} + +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 / + ((EHCI_MAX_QTD_BUFFER_PAGES - 1) * PAGE_SIZE)) + 1) > EhciEndpoint->RemainTDs) + { + DPRINT1("EHCI_BulkTransfer: return MP_STATUS_FAILURE\n"); + return MP_STATUS_FAILURE; + } + + 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 MP_STATUS_FAILURE; + } + + 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 = TERMINATE_POINTER; + TD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + TD->HwTD.Token.AsULONG = 0; + TD->HwTD.Token.ErrorCounter = 3; + + if (EhciTransfer->PendingTDs == 1) + { + FirstTD = TD; + } + else + { + PrevTD->HwTD.NextTD = TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + } + + TD->HwTD.AlternateNextTD = EhciEndpoint->HcdTailP->PhysicalAddress; + TD->AltNextHcdTD = EhciEndpoint->HcdTailP; + + TD->HwTD.Token.InterruptOnComplete = 1; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN; + else + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT; + + 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 MP_STATUS_FAILURE; + } + + 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 = TERMINATE_POINTER; + TD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + TD->HwTD.Token.AsULONG = 0; + TD->HwTD.Token.ErrorCounter = 3; + + TD->NextHcdTD = NULL; + + ASSERT(EhciTransfer->PendingTDs == 1); + + FirstTD = TD; + + TD->HwTD.AlternateNextTD = EhciEndpoint->HcdTailP->PhysicalAddress; + TD->AltNextHcdTD = EhciEndpoint->HcdTailP; + + TD->HwTD.Token.InterruptOnComplete = 1; + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN; + else + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT; + + TD->HwTD.Buffer[0] = TD->PhysicalAddress; + + TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + TD->HwTD.Token.DataToggle = 1; + + TD->LengthThisTD = 0; + } + + TD->HwTD.NextTD = 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 MP_STATUS_SUCCESS; +} + +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 = NULL; + ULONG TransferedLen = 0; + + DPRINT_EHCI("EHCI_InterruptTransfer: EhciEndpoint - %p, EhciTransfer - %p\n", + EhciEndpoint, + EhciTransfer); + + if (!EhciEndpoint->RemainTDs) + { + DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint); + DbgBreakPoint(); + return MP_STATUS_FAILURE; + } + + EhciEndpoint->PendingTDs++; + + if (!TransferParameters->TransferBufferLength) + { + DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint); + DbgBreakPoint(); + return MP_STATUS_FAILURE; + } + + do + { + TD = EHCI_AllocTd(EhciExtension, EhciEndpoint); + + if (!TD) + { + DPRINT1("EHCI_InterruptTransfer: EhciEndpoint - %p\n", EhciEndpoint); + RegPacket.UsbPortBugCheck(EhciExtension); + return MP_STATUS_FAILURE; + } + + 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 = TERMINATE_POINTER; + TD->HwTD.AlternateNextTD = TERMINATE_POINTER; + + TD->HwTD.Token.AsULONG = 0; + TD->HwTD.Token.ErrorCounter = 3; + + TD->NextHcdTD = NULL; + + if (EhciTransfer->PendingTDs == 1) + { + FirstTD = TD; + } + else if (PrevTD) + { + PrevTD->HwTD.NextTD = TD->PhysicalAddress; + PrevTD->NextHcdTD = TD; + } + + if (TransferParameters->TransferFlags & USBD_TRANSFER_DIRECTION_IN) + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_IN; + else + TD->HwTD.Token.PIDCode = EHCI_TD_TOKEN_PID_OUT; + + TD->HwTD.Token.Status = (UCHAR)EHCI_TOKEN_STATUS_ACTIVE; + TD->HwTD.Token.DataToggle = 1; + + TransferedLen = EHCI_MapAsyncTransferToTd(EhciExtension, + EhciEndpoint->EndpointProperties.TotalMaxPacketSize, + TransferedLen, + NULL, + EhciTransfer, + TD, + SgList); + + PrevTD = TD; + } + while (TransferedLen < TransferParameters->TransferBufferLength); + + TD->HwTD.Token.InterruptOnComplete = 1; + + DPRINT_EHCI("EHCI_InterruptTransfer: PendingTDs - %x, TD->PhysicalAddress - %p, FirstTD - %p\n", + EhciTransfer->PendingTDs, + TD->PhysicalAddress, + FirstTD); + + TD->HwTD.NextTD = 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 MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_SubmitTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PVOID ehciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint; + PEHCI_TRANSFER EhciTransfer = ehciTransfer; + MPSTATUS MPStatus; + + 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 = MP_STATUS_NOT_SUPPORTED; + break; + } + + return MPStatus; +} + +MPSTATUS +NTAPI +EHCI_SubmitIsoTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PVOID ehciTransfer, + IN PVOID isoParameters) +{ + DPRINT1("EHCI_SubmitIsoTransfer: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +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; + ULONG NextTD; + + DPRINT("EHCI_AbortAsyncTransfer: ... \n"); + + QH = EhciEndpoint->QH; + TD = EhciEndpoint->HcdHeadP; + + EhciEndpoint->PendingTDs--; + + if (TD->EhciTransfer == EhciTransfer) + { + TransferLength = 0; + + while (TD != EhciEndpoint->HcdTailP && + TD->EhciTransfer == EhciTransfer) + { + 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; + } + + if (TransferLength) + EhciTransfer->TransferLen += TransferLength; + + QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA; + QH->sqh.HwQH.NextTD = 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(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 = LastTD->PhysicalAddress; + FirstTD->HwTD.AlternateNextTD = LastTD->PhysicalAddress; + + FirstTD->NextHcdTD = LastTD; + FirstTD->AltNextHcdTD = LastTD; + + if (CurrentTransfer == EhciTransfer) + { + QH->sqh.HwQH.CurrentTD = EhciEndpoint->DmaBufferPA; + + QH->sqh.HwQH.Token.Status = (UCHAR)~EHCI_TOKEN_STATUS_ACTIVE; + QH->sqh.HwQH.Token.TransferBytes = 0; + + QH->sqh.HwQH.NextTD = NextTD; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + + return; + } + + if (FirstTD->EhciTransfer == CurrentTransfer) + { + if (QH->sqh.HwQH.NextTD == FirstTD->PhysicalAddress) + QH->sqh.HwQH.NextTD = NextTD; + + if (QH->sqh.HwQH.AlternateNextTD == FirstTD->PhysicalAddress) + QH->sqh.HwQH.AlternateNextTD = NextTD; + + for (TD = EhciEndpoint->HcdHeadP; + TD; + TD = TD->NextHcdTD) + { + if (TD->EhciTransfer == CurrentTransfer) + { + TD->HwTD.AlternateNextTD = NextTD; + TD->AltNextHcdTD = LastTD; + } + } + } + } +} + +VOID +NTAPI +EHCI_AbortTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PVOID ehciTransfer, + IN PULONG CompletedLength) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint; + PEHCI_TRANSFER EhciTransfer = ehciTransfer; + ULONG TransferType; + + DPRINT("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) +{ + PEHCI_HCD_QH QH; + PEHCI_HCD_QH NextHead; + ULONG NextQhPA; + PEHCI_HCD_QH PrevHead; + + QH = EhciEndpoint->QH; + + if ( !(QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) ) + return; + + DPRINT("EHCI_RemoveQhFromPeriodicList: EhciEndpoint - %p, QH - %X, EhciEndpoint->StaticQH - %p\n", + EhciEndpoint, + QH, + EhciEndpoint->StaticQH); + + NextHead = QH->sqh.NextHead; + PrevHead = QH->sqh.PrevHead; + + PrevHead->sqh.NextHead = NextHead; + + if ( NextHead ) + { + if ( !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC) ) + NextHead->sqh.PrevHead = PrevHead; + + NextQhPA = NextHead->sqh.PhysicalAddress; + NextQhPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + NextQhPA |= (EHCI_LINK_TYPE_QH << 1); + + PrevHead->sqh.HwQH.HorizontalLink.AsULONG = NextQhPA; + } + else + { + PrevHead->sqh.HwQH.HorizontalLink.Terminate = 1; + } + + QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE; + + QH->sqh.NextHead = NULL; + QH->sqh.PrevHead = NULL; +} + +VOID +NTAPI +EHCI_RemoveQhFromAsyncList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QH) +{ + PEHCI_HCD_QH NextHead; + ULONG NextHeadPA; + PEHCI_HCD_QH PrevHead; + PEHCI_STATIC_QH AsyncHead; + ULONG AsyncHeadPA; + + DPRINT("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 = AsyncHead->PhysicalAddress; + AsyncHeadPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + AsyncHeadPA |= (EHCI_LINK_TYPE_QH << 1); + + NextHeadPA = NextHead->sqh.PhysicalAddress; + NextHeadPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + NextHeadPA |= (EHCI_LINK_TYPE_QH << 1); + + PrevHead->sqh.HwQH.HorizontalLink.AsULONG = NextHeadPA; + + PrevHead->sqh.NextHead = NextHead; + NextHead->sqh.PrevHead = PrevHead; + + EHCI_FlushAsyncCache(EhciExtension); + + if (READ_REGISTER_ULONG(&EhciExtension->OperationalRegs->AsyncListBase) == + QH->sqh.PhysicalAddress) + { + WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->AsyncListBase, + AsyncHeadPA); + } + + QH->sqh.QhFlags &= ~EHCI_QH_FLAG_IN_SCHEDULE; + } +} + +VOID +NTAPI +EHCI_InsertQhInPeriodicList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_ENDPOINT EhciEndpoint) +{ + PEHCI_STATIC_QH StaticQH; + PEHCI_HCD_QH QH; + ULONG QhPA; + PEHCI_HCD_QH NextHead; + PEHCI_HCD_QH PrevHead; + + QH = EhciEndpoint->QH; + StaticQH = EhciEndpoint->StaticQH; + + ASSERT((QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE) == 0); + ASSERT(StaticQH->QhFlags & EHCI_QH_FLAG_STATIC); + + NextHead = StaticQH->NextHead; + + QH->sqh.Period = EhciEndpoint->EndpointProperties.Period; + QH->sqh.Ordinal = EhciEndpoint->EndpointProperties.Reserved6; + + DPRINT("EHCI_InsertQhInPeriodicList: EhciEndpoint - %p, QH - %X, EhciEndpoint->StaticQH - %p\n", + EhciEndpoint, + QH, + EhciEndpoint->StaticQH); + + PrevHead = (PEHCI_HCD_QH)StaticQH; + + if ((StaticQH->QhFlags & EHCI_QH_FLAG_STATIC) && + (!NextHead || (NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC))) + { + DPRINT("EHCI_InsertQhInPeriodicList: StaticQH - %p, StaticQH->NextHead - %p\n", + StaticQH, + StaticQH->NextHead); + } + else + { + while (NextHead && + !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC) && + QH->sqh.Ordinal > NextHead->sqh.Ordinal); + { + PrevHead = NextHead; + NextHead = NextHead->sqh.NextHead; + } + } + + QH->sqh.NextHead = NextHead; + QH->sqh.PrevHead = PrevHead; + + if (NextHead && !(NextHead->sqh.QhFlags & EHCI_QH_FLAG_STATIC)) + NextHead->sqh.PrevHead = QH; + + QH->sqh.QhFlags |= EHCI_QH_FLAG_IN_SCHEDULE; + QH->sqh.HwQH.HorizontalLink = PrevHead->sqh.HwQH.HorizontalLink; + + PrevHead->sqh.NextHead = QH; + + QhPA = QH->sqh.PhysicalAddress; + QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + QhPA |= (EHCI_LINK_TYPE_QH << 1); + + PrevHead->sqh.HwQH.HorizontalLink.AsULONG = QhPA; +} + +VOID +NTAPI +EHCI_InsertQhInAsyncList(IN PEHCI_EXTENSION EhciExtension, + IN PEHCI_HCD_QH QH) +{ + PEHCI_STATIC_QH AsyncHead; + ULONG QhPA; + PEHCI_HCD_QH NextHead; + + DPRINT("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; + + QhPA = QH->sqh.PhysicalAddress; + QhPA &= LINK_POINTER_MASK + TERMINATE_POINTER; + QhPA |= (EHCI_LINK_TYPE_QH << 1); + + AsyncHead->HwQH.HorizontalLink.AsULONG = QhPA; + + 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_SetAsyncEndpointState: EhciEndpoint - %p, EndpointState - %x\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_REMOVE: + QH->sqh.QhFlags |= EHCI_QH_FLAG_CLOSED; + + 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_SetEndpointState: ... \n"); + + EhciEndpoint = 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 = ehciExtension; + + DPRINT_EHCI("EHCI_InterruptNextSOF: ... \n"); + + RegPacket.UsbPortInvalidateController(EhciExtension, + USBPORT_INVALIDATE_CONTROLLER_SOFT_INTERRUPT); +} + +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; + PEHCI_HW_REGISTERS 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 & EHCI_HCD_TD_FLAG_ACTIVE) + 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 != EHCI_TD_TOKEN_PID_SETUP) + 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->HcCommand.AsULONG); + + if (!Command.InterruptAdvanceDoorbell && + (EhciExtension->Flags & EHCI_FLAGS_IDLE_SUPPORT)) + { + 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 & LINK_POINTER_MASK; + ASSERT(CurrentTDPhys); + + CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(CurrentTDPhys, + EhciExtension, + EhciEndpoint); + + if (CurrentTD == EhciEndpoint->DmaBufferVA) + 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 != TD->NextHcdTD->PhysicalAddress) + TD->HwTD.NextTD = TD->NextHcdTD->PhysicalAddress; + + if (TD->AltNextHcdTD && + TD->HwTD.AlternateNextTD != TD->AltNextHcdTD->PhysicalAddress) + { + TD->HwTD.AlternateNextTD = TD->AltNextHcdTD->PhysicalAddress; + } + + if (QH->sqh.HwQH.CurrentTD == 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 |= EHCI_HCD_TD_FLAG_ACTIVE; + + 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 = EhciEndpoint->DmaBufferPA; + + CurrentTD->TdFlags |= EHCI_HCD_TD_FLAG_DONE; + InsertTailList(&EhciEndpoint->ListTDs, &CurrentTD->DoneLink); + + if (CurrentTD->HwTD.Token.TransferBytes && + CurrentTD->AltNextHcdTD == EhciEndpoint->HcdTailP) + { + TD = CurrentTD->NextHcdTD; + + while (TD != EhciEndpoint->HcdTailP) + { + TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE; + InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink); + TD = TD->NextHcdTD; + } + } + + QH->sqh.HwQH.CurrentTD = EhciEndpoint->HcdTailP->PhysicalAddress; + QH->sqh.HwQH.NextTD = TERMINATE_POINTER; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + 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 & LINK_POINTER_MASK; + ASSERT(CurrentTdPA); + + IsSheduled = QH->sqh.QhFlags & EHCI_QH_FLAG_IN_SCHEDULE; + + if (!EHCI_HardwarePresent(EhciExtension, 0)) + IsSheduled = 0; + + CurrentTD = RegPacket.UsbPortGetMappedVirtualAddress(CurrentTdPA, + EhciExtension, + EhciEndpoint); + + DPRINT("EHCI_PollHaltedAsyncEndpoint: CurrentTD - %p\n", CurrentTD); + + if (CurrentTD == EhciEndpoint->DmaBufferVA) + return; + + ASSERT(EhciEndpoint->HcdTailP != CurrentTD); + + if (IsSheduled) + { + EHCI_LockQH(EhciExtension, + QH, + EhciEndpoint->EndpointProperties.TransferType); + } + + TD = EhciEndpoint->HcdHeadP; + + while (TD != CurrentTD) + { + 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 |= EHCI_HCD_TD_FLAG_ACTIVE; + + TD->TdFlags |= EHCI_HCD_TD_FLAG_DONE; + + InsertTailList(&EhciEndpoint->ListTDs, &TD->DoneLink); + + TD = TD->NextHcdTD; + } + + TD = CurrentTD; + + Transfer = CurrentTD->EhciTransfer; + + do + { + DPRINT("EHCI_PollHaltedAsyncEndpoint: TD - %p\n", TD); + + if (TD->HwTD.Token.Status & EHCI_TOKEN_STATUS_ACTIVE) + TD->TdFlags |= EHCI_HCD_TD_FLAG_ACTIVE; + + 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 = EhciEndpoint->DmaBufferPA; + QH->sqh.HwQH.NextTD = TD->PhysicalAddress; + QH->sqh.HwQH.AlternateNextTD = TERMINATE_POINTER; + QH->sqh.HwQH.Token.TransferBytes = 0; + + if (IsSheduled) + EHCI_UnlockQH(EhciExtension, QH); + + if (EhciEndpoint->EndpointStatus & USBPORT_ENDPOINT_CONTROL) + { + EhciEndpoint->EndpointStatus &= ~USBPORT_ENDPOINT_HALT; + 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 & EHCI_QH_FLAG_CLOSED) + 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 |= USBPORT_ENDPOINT_HALT; + 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))); + + 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 = ehciExtension; + PEHCI_ENDPOINT EhciEndpoint = ehciEndpoint; + ULONG TransferType; + + //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 = ehciExtension; + + //DPRINT_EHCI("EHCI_CheckController: ... \n"); + + if (EhciExtension->IsStarted) + EHCI_HardwarePresent(EhciExtension, TRUE); +} + +ULONG +NTAPI +EHCI_Get32BitFrameNumber(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + ULONG FrameIdx; + ULONG FrameIndex; + ULONG FrameNumber; + + //DPRINT_EHCI("EHCI_Get32BitFrameNumber: EhciExtension - %p\n", EhciExtension); + + FrameIdx = EhciExtension->FrameIndex; + FrameIndex = READ_REGISTER_ULONG(&EhciExtension->OperationalRegs->FrameIndex); + + FrameNumber = (USHORT)FrameIdx ^ ((FrameIndex / EHCI_MICROFRAMES) & EHCI_FRINDEX_FRAME_MASK); + FrameNumber &= EHCI_FRAME_LIST_MAX_ENTRIES; + FrameNumber += FrameIndex | ((FrameIndex / EHCI_MICROFRAMES) & EHCI_FRINDEX_INDEX_MASK); + + return FrameNumber; +} + +VOID +NTAPI +EHCI_EnableInterrupts(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + + DPRINT("EHCI_EnableInterrupts: EhciExtension->InterruptMask - %x\n", + EhciExtension->InterruptMask.AsULONG); + + WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG, + EhciExtension->InterruptMask.AsULONG); +} + +VOID +NTAPI +EHCI_DisableInterrupts(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + + DPRINT("EHCI_DisableInterrupts: ... \n"); + + WRITE_REGISTER_ULONG(&EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG, + 0); +} + +VOID +NTAPI +EHCI_PollController(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_HW_REGISTERS OperationalRegs; + ULONG Port; + EHCI_PORT_STATUS_CONTROL PortSC; + + DPRINT_EHCI("EHCI_PollController: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + if (!(EhciExtension->Flags & EHCI_FLAGS_CONTROLLER_SUSPEND)) + { + RegPacket.UsbPortInvalidateRootHub(EhciExtension); + return; + } + + if (EhciExtension->NumberOfPorts) + { + for (Port = 0; Port < EhciExtension->NumberOfPorts; Port++) + { + PortSC.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->PortControl[Port].AsULONG); + + 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 = ehciEndpoint; + + DPRINT("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 EndpointStatus = USBPORT_ENDPOINT_RUN; + + EhciEndpoint = ehciEndpoint; + + DPRINT("EHCI_GetEndpointStatus: EhciEndpoint - %p\n", EhciEndpoint); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + return EndpointStatus; + + if (EhciEndpoint->EndpointStatus & USBPORT_ENDPOINT_HALT) + EndpointStatus = USBPORT_ENDPOINT_HALT; + + return EndpointStatus; +} + +VOID +NTAPI +EHCI_SetEndpointStatus(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN ULONG EndpointStatus) +{ + PEHCI_ENDPOINT EhciEndpoint; + ULONG TransferType; + PEHCI_HCD_QH QH; + + EhciEndpoint = ehciEndpoint; + + DPRINT("EHCI_SetEndpointStatus: EhciEndpoint - %p, EndpointStatus - %x\n", + EhciEndpoint, + EndpointStatus); + + TransferType = EhciEndpoint->EndpointProperties.TransferType; + + if (TransferType != USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + + if (EndpointStatus == USBPORT_ENDPOINT_RUN) + { + EhciEndpoint->EndpointStatus &= ~USBPORT_ENDPOINT_HALT; + + QH = EhciEndpoint->QH; + QH->sqh.HwQH.Token.Status &= (UCHAR)~EHCI_TOKEN_STATUS_HALTED; + + return; + } + + if (EndpointStatus == USBPORT_ENDPOINT_HALT) + 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 MP_STATUS_SUCCESS; +} + +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 MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +EHCI_PassThru(IN PVOID ehciExtension, + IN PVOID passThruParameters, + IN ULONG ParameterLength, + IN PVOID pParameters) +{ + DPRINT1("EHCI_PassThru: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +EHCI_RebalanceEndpoint(IN PVOID ohciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PVOID ohciEndpoint) +{ + DPRINT1("EHCI_RebalanceEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_FlushInterrupts(IN PVOID ehciExtension) +{ + PEHCI_EXTENSION EhciExtension = ehciExtension; + PEHCI_HW_REGISTERS OperationalRegs; + EHCI_USB_STATUS Status; + + DPRINT("EHCI_FlushInterrupts: ... \n"); + + OperationalRegs = EhciExtension->OperationalRegs; + + Status.AsULONG = READ_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG); + WRITE_REGISTER_ULONG(&OperationalRegs->HcStatus.AsULONG, Status.AsULONG); +} + +VOID +NTAPI +EHCI_TakePortControl(IN PVOID ohciExtension) +{ + DPRINT1("EHCI_TakePortControl: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +EHCI_Unload(IN PDRIVER_OBJECT DriverObject) +{ +#if DBG + DPRINT1("EHCI_Unload: Not supported\n"); +#endif + return; +} + +NTSTATUS +NTAPI +DriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + DPRINT("DriverEntry: DriverObject - %p, RegistryPath - %wZ\n", + DriverObject, + RegistryPath); + + if (USBPORT_GetHciMn() != USBPORT_HCI_MN) + 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 = TOTAL_USB20_BUS_BANDWIDTH; + + 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 = EHCI_Unload; + + return USBPORT_RegisterUSBPortDriver(DriverObject, + USB20_MINIPORT_INTERFACE_VERSION, + &RegPacket); +} diff --git a/drivers/usb/usbehci_new/usbehci.h b/drivers/usb/usbehci_new/usbehci.h new file mode 100644 index 0000000..d7da30f --- /dev/null +++ b/drivers/usb/usbehci_new/usbehci.h @@ -0,0 +1,318 @@ +#ifndef USBEHCI_H__ +#define USBEHCI_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "hardware.h" + +extern USBPORT_REGISTRATION_PACKET RegPacket; + +#define EHCI_MAX_CONTROL_TRANSFER_SIZE 0x10000 +#define EHCI_MAX_INTERRUPT_TRANSFER_SIZE 0x1000 +#define EHCI_MAX_BULK_TRANSFER_SIZE 0x400000 +#define EHCI_MAX_FS_ISO_TRANSFER_SIZE 0x40000 +#define EHCI_MAX_HS_ISO_TRANSFER_SIZE 0x180000 + +#define EHCI_MAX_FS_ISO_HEADER_BUFFER_SIZE 0x1000 +#define EHCI_MAX_HS_ISO_HEADER_BUFFER_SIZE 0x40000 + +#define EHCI_MAX_CONTROL_TD_COUNT 6 +#define EHCI_MAX_INTERRUPT_TD_COUNT 4 +#define EHCI_MAX_BULK_TD_COUNT 209 + +#define EHCI_FRAMES 32 +#define EHCI_MICROFRAMES 8 + +#define EHCI_MAX_HC_SYSTEM_ERRORS 256 + +typedef struct _EHCI_PERIOD { + UCHAR Period; + UCHAR PeriodIdx; + UCHAR ScheduleMask; +} EHCI_PERIOD, *PEHCI_PERIOD; + +/* Transfer Descriptor */ +#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_ACTIVE 0x10 +#define EHCI_HCD_TD_FLAG_DUMMY 0x20 + +struct _EHCI_HCD_QH; +struct _EHCI_ENDPOINT; +struct _EHCI_TRANSFER; + +typedef struct _EHCI_HCD_TD { + /* Hardware*/ + EHCI_QUEUE_TD HwTD; + /* Software */ + ULONG 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); + +/* Queue Head */ +#define EHCI_QH_FLAG_IN_SCHEDULE 0x01 +#define EHCI_QH_FLAG_CLOSED 0x02 +#define EHCI_QH_FLAG_STATIC 0x04 +#define EHCI_QH_FLAG_STATIC_FAST 0x08 +#define EHCI_QH_FLAG_UPDATING 0x10 +#define EHCI_QH_FLAG_NUKED 0x20 + +typedef struct _EHCI_STATIC_QH { + /* Hardware part */ + EHCI_QUEUE_HEAD HwQH; + /* Software part */ + ULONG QhFlags; + ULONG PhysicalAddress; + struct _EHCI_HCD_QH * PrevHead; +#if !defined(_M_X64) + ULONG Pad2; +#endif + struct _EHCI_HCD_QH * NextHead; +#if !defined(_M_X64) + ULONG Pad3; +#endif + struct _EHCI_STATIC_QH * StaticQH; +#if !defined(_M_X64) + ULONG Pad4; +#endif + ULONG Period; + ULONG Ordinal; + ULONG Pad[13]; +} EHCI_STATIC_QH, *PEHCI_STATIC_QH; + +C_ASSERT(sizeof(EHCI_STATIC_QH) == 0xA0); + +#define EHCI_DUMMYQH_MAX_PACKET_LENGTH 64 + +typedef struct _EHCI_HCD_QH { + EHCI_STATIC_QH sqh; + ULONG Pad[24]; +} EHCI_HCD_QH, *PEHCI_HCD_QH; + +C_ASSERT(sizeof(EHCI_HCD_QH) == 0x100); + +/* EHCI Endpoint follows USBPORT Endpoint */ +typedef struct _EHCI_ENDPOINT { + ULONG Reserved; + ULONG EndpointStatus; + ULONG EndpointState; + USBPORT_ENDPOINT_PROPERTIES EndpointProperties; + PVOID DmaBufferVA; + ULONG 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; + PEHCI_PERIOD PeriodTable; + PEHCI_STATIC_QH StaticQH; +} EHCI_ENDPOINT, *PEHCI_ENDPOINT; + +/* EHCI Transfer follows USBPORT Transfer */ +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[EHCI_FRAME_LIST_MAX_ENTRIES]; // 4K-page aligned array + EHCI_STATIC_QH AsyncHead; + EHCI_STATIC_QH PeriodicHead[64]; + UCHAR Padded[0x160]; + EHCI_HCD_QH IsoDummyQH[EHCI_FRAME_LIST_MAX_ENTRIES]; +} EHCI_HC_RESOURCES, *PEHCI_HC_RESOURCES; + +#define EHCI_FLAGS_CONTROLLER_SUSPEND 0x01 +#define EHCI_FLAGS_IDLE_SUPPORT 0x20 + +/* EHCI Extension follows USBPORT Extension */ +typedef struct _EHCI_EXTENSION { + ULONG Reserved; + ULONG Flags; + PEHCI_HC_CAPABILITY_REGISTERS CapabilityRegisters; + PEHCI_HW_REGISTERS OperationalRegs; + UCHAR FrameLengthAdjustment; + BOOLEAN IsStarted; + USHORT HcSystemErrors; + ULONG PortRoutingControl; + USHORT NumberOfPorts; + USHORT PortPowerControl; + EHCI_INTERRUPT_ENABLE InterruptMask; + EHCI_INTERRUPT_ENABLE InterruptStatus; + /* Shedule */ + PEHCI_HC_RESOURCES HcResourcesVA; + ULONG HcResourcesPA; + PEHCI_STATIC_QH AsyncHead; + PEHCI_STATIC_QH PeriodicHead[64]; + PEHCI_HCD_QH IsoDummyQHListVA; + ULONG IsoDummyQHListPA; + 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; + ULONG BakupAsynclistaddr; + ULONG BakupCtrlDSSegment; + ULONG BakupUSBCmd; +} 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 */ +MPSTATUS +NTAPI +EHCI_RH_ChirpRootPort( + IN PVOID ehciExtension, + IN USHORT Port); + +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 PUSB_PORT_STATUS_AND_CHANGE PortStatus); + +MPSTATUS +NTAPI +EHCI_RH_GetHubStatus( + IN PVOID ohciExtension, + IN PUSB_HUB_STATUS_AND_CHANGE 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); + +#endif /* USBEHCI_H__ */ diff --git a/drivers/usb/usbehci_new/usbehci.rc b/drivers/usb/usbehci_new/usbehci.rc new file mode 100644 index 0000000..8a54ddc --- /dev/null +++ b/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/drivers/usb/usbhub_new/CMakeLists.txt b/drivers/usb/usbhub_new/CMakeLists.txt index a1355df..139487b 100644 --- a/drivers/usb/usbhub_new/CMakeLists.txt +++ b/drivers/usb/usbhub_new/CMakeLists.txt @@ -3,6 +3,7 @@ add_definitions(-DDEBUG_MODE) include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include) list(APPEND SOURCE + blacklst.c debug.c ioctl.c pnp.c diff --git a/drivers/usb/usbhub_new/blacklst.c b/drivers/usb/usbhub_new/blacklst.c new file mode 100644 index 0000000..d2d831e --- /dev/null +++ b/drivers/usb/usbhub_new/blacklst.c @@ -0,0 +1,963 @@ +/* + * PROJECT: ReactOS USB Hub Driver + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: USBHub, "black list" for USB devices not yet supported + * COPYRIGHT: Copyright 2018 Vadim Galyant + */ + +#include "usbhub.h" + +#define NDEBUG +#include + +BOOLEAN +NTAPI +USBH_IsVidPidFromBlackList(IN USHORT IdVendor, + IN USHORT IdProduct, + IN USHORT Revision) +{ + BOOLEAN Result = FALSE; + + DPRINT("USBH_IsVidPidFromBlackList: IdVendor - %X, IdProduct - %X\n", + IdVendor, + IdProduct); + + // This is hack - "black list" USB devices (in the main webcameras) + + switch (IdVendor) + { + case 0x03f0: // Hewlett-Packard + switch (IdProduct) + { + case 0x1b07: // Premium Starter Webcam + case 0x3724: // Webcam + case 0x9207: // HD-4110 Webcam + case 0xb116: // Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0408: // Quanta Computer, Inc. + switch (IdProduct) + { + case 0x030c: // HP Webcam + case 0x03b2: // HP Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x040a: // Kodak Co. + switch (IdProduct) + { + case 0x0200: // Digital Camera + case 0x0402: // Digital Camera + case 0x0535: // EasyShare CX4230 Camera + case 0x0581: // Digital Camera + case 0x0582: // Digital Camera + case 0x0583: // Digital Camera + case 0x0585: // Digital Camera + case 0x0587: // Digital Camera + case 0x0588: // Digital Camera + case 0x0589: // EasyShare C360 + case 0x058b: // Digital Camera + case 0x0590: // Digital Camera + case 0x0591: // Digital Camera + case 0x0592: // Digital Camera + case 0x0593: // Digital Camera + case 0x0594: // Digital Camera + case 0x0595: // Digital Camera + case 0x0596: // Digital Camera + case 0x0597: // Digital Camera + case 0x0598: // EASYSHARE M1033 digital camera + case 0x0599: // Digital Camera + case 0x059a: // Digital Camera + case 0x059b: // Digital Camera + case 0x059c: // Digital Camera + case 0x059d: // Digital Camera + case 0x059e: // Digital Camera + case 0x059f: // Digital Camera + case 0x05a0: // Digital Camera + case 0x05a1: // Digital Camera + case 0x05a2: // Digital Camera + case 0x05a3: // Digital Camera + case 0x05a4: // Digital Camera + case 0x05a5: // Digital Camera + case 0x05a6: // Digital Camera + case 0x05a7: // Digital Camera + case 0x05a8: // Digital Camera + case 0x05a9: // Digital Camera + case 0x05aa: // Digital Camera + case 0x05ab: // Digital Camera + case 0x05ac: // Digital Camera + case 0x05ad: // Digital Camera + case 0x05ae: // Digital Camera + case 0x05af: // Digital Camera + case 0x05b0: // Digital Camera + case 0x05b1: // Digital Camera + case 0x05b2: // Digital Camera + case 0x05b3: // EasyShare Z710 Camera + case 0x05b4: // Digital Camera + case 0x05b5: // Digital Camera + case 0x05b6: // Digital Camera + case 0x05b7: // Digital Camera + case 0x05b8: // Digital Camera + case 0x05b9: // Digital Camera + case 0x05ba: // Digital Camera + case 0x05bb: // Digital Camera + case 0x05bc: // Digital Camera + case 0x05bd: // Digital Camera + case 0x05be: // Digital Camera + case 0x05bf: // Digital Camera + case 0x05c0: // Digital Camera + case 0x05c1: // Digital Camera + case 0x05c2: // Digital Camera + case 0x05c3: // Digital Camera + case 0x05c4: // Digital Camera + case 0x05c5: // Digital Camera + case 0x05c8: // EASYSHARE Z1485 IS Digital Camera + case 0x05d3: // EasyShare M320 Camera + case 0x05d4: // EasyShare C180 Digital Camera + Result = TRUE; + break; + default: + break; + } + break; + + case 0x041e: // Creative Technology, Ltd + switch (IdProduct) + { + case 0x4005: // Webcam Blaster Go ES + case 0x400a: // PC-Cam 300 + case 0x400b: // PC-Cam 600 + case 0x400c: // Webcam 5 [pwc] + case 0x400d: // Webcam PD1001 + case 0x400f: // PC-CAM 550 (Composite) + case 0x4011: // Webcam PRO eX + case 0x4012: // PC-CAM350 + case 0x4013: // PC-Cam 750 + case 0x4015: // CardCam Value + case 0x4016: // CardCam + case 0x4017: // Webcam Mobile [PD1090] + case 0x4018: // Webcam Vista [PD1100] + case 0x401a: // Webcam Vista [PD1100] + case 0x401c: // Webcam NX [PD1110] + case 0x401d: // Webcam NX Ultra + case 0x401e: // Webcam NX Pro + case 0x401f: // Webcam Notebook [PD1171] + case 0x4020: // Webcam NX + case 0x4021: // Webcam NX Ultra + case 0x4022: // Webcam NX Pro + case 0x4028: // Vista Plus cam [VF0090] + case 0x4029: // Webcam Live! + case 0x402f: // DC-CAM 3000Z + case 0x4034: // Webcam Instant + case 0x4035: // Webcam Instant + case 0x4036: // Webcam Live!/Live! Pro + case 0x4037: // Webcam Live! + case 0x4038: // ORITE CCD Webcam [PC370R] + case 0x4039: // Webcam Live! Effects + case 0x403a: // Webcam NX Pro 2 + case 0x403b: // Creative Webcam Vista [VF0010] + case 0x403c: // Webcam Live! Ultra + case 0x403d: // Webcam Notebook Ultra + case 0x403e: // Webcam Vista Plus + case 0x4041: // Webcam Live! Motion + case 0x4043: // Vibra Plus Webcam + case 0x4045: // Live! Cam Voice + case 0x4049: // Live! Cam Voice + case 0x4051: // Live! Cam Notebook Pro [VF0250] + case 0x4052: // Live! Cam Vista IM + case 0x4053: // Live! Cam Video IM + case 0x4054: // Live! Cam Video IM + case 0x4055: // Live! Cam Video IM Pro + case 0x4056: // Live! Cam Video IM Pro + case 0x4057: // Live! Cam Optia + case 0x4058: // Live! Cam Optia AF + case 0x405f: // WebCam Vista (VF0330) + case 0x4061: // Live! Cam Notebook Pro [VF0400] + case 0x4063: // Live! Cam Video IM Pro + case 0x4068: // Live! Cam Notebook [VF0470] + case 0x406c: // Live! Cam Sync [VF0520] + case 0x4083: // Live! Cam Socialize [VF0640] + case 0x4087: // Live! Cam Socialize HD 1080 [VF0680] + case 0x4088: // Live! Cam Chat HD [VF0700] + case 0x4095: // Live! Cam Sync HD [VF0770] + case 0x4097: // Live! Cam Chat HD [VF0700] + case 0xffff: // Webcam Live! Ultra + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0458: // KYE Systems Corp. (Mouse Systems) + switch (IdProduct) + { + case 0x7004: // VideoCAM Express V2 + case 0x7006: // Dsc 1.3 Smart Camera Device + case 0x7007: // VideoCAM Web + case 0x7009: // G-Shot G312 Still Camera Device + case 0x700c: // VideoCAM Web V3 + case 0x700d: // G-Shot G511 Composite Device + case 0x700f: // VideoCAM Web + case 0x7012: // WebCAM USB2.0 + case 0x7014: // VideoCAM Live V3 + case 0x701c: // G-Shot G512 Still Camera + case 0x7020: // Sim 321C + case 0x7025: // Eye 311Q Camera + case 0x7029: // Genius Look 320s (SN9C201 + HV7131R) + case 0x702f: // Genius Slim 322 + case 0x7035: // i-Look 325T Camera + case 0x7045: // Genius Look 1320 V2 + case 0x704c: // Genius i-Look 1321 + case 0x704d: // Slim 1322AF + case 0x7055: // Slim 2020AF camera + case 0x705a: // Asus USB2.0 Webcam + case 0x705c: // Genius iSlim 1300AF + case 0x7061: // Genius iLook 1321 V2 + case 0x7066: // Acer Crystal Eye Webcam + case 0x7067: // Genius iSlim 1300AF V2 + case 0x7068: // Genius eFace 1325R + case 0x706d: // Genius iSlim 2000AF V2 + case 0x7076: // Genius FaceCam 312 + case 0x7079: // FaceCam 2025R + case 0x707f: // TVGo DVB-T03 [RTL2832] + case 0x7088: // WideCam 1050 + case 0x7089: // Genius FaceCam 320 + case 0x708c: // Genius WideCam F100 + Result = TRUE; + break; + default: + break; + } + break; + + case 0x045e: // Microsoft Corp. + switch (IdProduct) + { + case 0x00f4: // LifeCam VX-6000 (SN9C20x + OV9650) + case 0x00f5: // LifeCam VX-3000 + case 0x00f7: // LifeCam VX-1000 + case 0x00f8: // LifeCam NX-6000 + case 0x0721: // LifeCam NX-3000 (UVC-compliant) + case 0x0723: // LifeCam VX-7000 (UVC-compliant) + case 0x0728: // LifeCam VX-5000 + case 0x074a: // LifeCam VX-500 [1357] + case 0x075d: // LifeCam Cinema // USB\VID_045E&PID_075D&REV_0105 + case 0x0761: // LifeCam VX-2000 + case 0x0766: // LifeCam VX-800 + case 0x076d: // LifeCam HD-5000 + case 0x0770: // LifeCam VX-700 + case 0x0772: // LifeCam Studio + case 0x0779: // LifeCam HD-3000 + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0461: // Primax Electronics, Ltd + switch (IdProduct) + { + case 0x0813: // IBM UltraPort Camera + case 0x0815: // Micro Innovations IC200 Webcam + case 0x0819: // Fujifilm IX-30 Camera [webcam mode] + case 0x081a: // Fujifilm IX-30 Camera [storage mode] + case 0x081c: // Elitegroup ECS-C11 Camera + case 0x0a00: // Micro Innovations Web Cam 320 + case 0x4de7: // webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x046d: // Logitech, Inc. + switch (IdProduct) + { + case 0x0082: // Acer Aspire 5672 Webcam + case 0x0801: // QuickCam Home + case 0x0802: // Webcam C200 + case 0x0804: // Webcam C250 + case 0x0805: // Webcam C300 + case 0x0807: // Webcam B500 + case 0x0808: // Webcam C600 + case 0x0809: // Webcam Pro 9000 + case 0x080a: // Portable Webcam C905 + case 0x080f: // Webcam C120 + case 0x0810: // QuickCam Pro + case 0x0819: // Webcam C210 + case 0x081b: // Webcam C310 + case 0x081d: // HD Webcam C510 + case 0x0820: // QuickCam VC + case 0x0821: // HD Webcam C910 + case 0x0825: // Webcam C270 + case 0x0826: // HD Webcam C525 + case 0x0828: // HD Webcam B990 + case 0x082b: // Webcam C170 + case 0x082c: // HD Webcam C615 + case 0x082d: // HD Pro Webcam C920 + case 0x0836: // B525 HD Webcam + case 0x0837: // BCC950 ConferenceCam + case 0x0840: // QuickCam Express + case 0x0843: // Webcam C930e + case 0x0850: // QuickCam Web + case 0x085c: // C922 Pro Stream Webcam + case 0x0870: // QuickCam Express + case 0x0890: // QuickCam Traveler + case 0x0892: // OrbiCam + case 0x0894: // CrystalCam + case 0x0895: // QuickCam for Dell Notebooks + case 0x0896: // OrbiCam + case 0x0897: // QuickCam for Dell Notebooks + case 0x0899: // QuickCam for Dell Notebooks + case 0x089d: // QuickCam E2500 series + case 0x08a0: // QuickCam IM + case 0x08a1: // QuickCam IM with sound + case 0x08a2: // Labtec Webcam Pro + case 0x08a3: // QuickCam QuickCam Chat + case 0x08a6: // QuickCam IM + case 0x08a7: // QuickCam Image + case 0x08ac: // QuickCam Cool + case 0x08ad: // QuickCam Communicate STX + case 0x08ae: // QuickCam for Notebooks + case 0x08af: // QuickCam Easy/Cool + case 0x08b0: // QuickCam 3000 Pro [pwc] + case 0x08b1: // QuickCam Notebook Pro + case 0x08b2: // QuickCam Pro 4000 + case 0x08b3: // QuickCam Zoom + case 0x08b4: // QuickCam Zoom + case 0x08b5: // QuickCam Sphere + case 0x08b9: // QuickCam IM + case 0x08c0: // QuickCam Pro 3000 + case 0x08c1: // QuickCam Fusion + case 0x08c2: // QuickCam PTZ + case 0x08c3: // Camera (Notebooks Pro) + case 0x08c5: // QuickCam Pro 5000 + case 0x08c6: // QuickCam for DELL Notebooks + case 0x08c7: // QuickCam OEM Cisco VT Camera II + case 0x08c9: // QuickCam Ultra Vision + case 0x08ce: // QuickCam Pro 5000 + case 0x08cf: // QuickCam UpdateMe + case 0x08d0: // QuickCam Express + case 0x08d7: // QuickCam Communicate STX + case 0x08d8: // QuickCam for Notebook Deluxe + case 0x08d9: // QuickCam IM/Connect + case 0x08da: // QuickCam Messanger + case 0x08dd: // QuickCam for Notebooks + case 0x08e0: // QuickCam Express + case 0x08e1: // Labtec Webcam + case 0x08f0: // QuickCam Messenger + case 0x08f1: // QuickCam Express + case 0x08f3: // QuickCam Express + case 0x08f4: // Labtec Webcam + case 0x08f5: // QuickCam Messenger Communicate + case 0x08f6: // QuickCam Messenger Plus + case 0x0900: // ClickSmart 310 + case 0x0901: // ClickSmart 510 + case 0x0903: // ClickSmart 820 + case 0x0905: // ClickSmart 820 + case 0x0910: // QuickCam Cordless + case 0x0920: // QuickCam Express + case 0x0921: // Labtec Webcam + case 0x0922: // QuickCam Live + case 0x0928: // QuickCam Express + case 0x0929: // Labtec Webcam Pro + case 0x092a: // QuickCam for Notebooks + case 0x092b: // Labtec Webcam Plus + case 0x092c: // QuickCam Chat + case 0x092d: // QuickCam Express / Go + case 0x092e: // QuickCam Chat + case 0x092f: // QuickCam Express Plus + case 0x0950: // Pocket Camera + case 0x0960: // ClickSmart 420 + case 0x0970: // Pocket750 + case 0x0990: // QuickCam Pro 9000 + case 0x0991: // QuickCam Pro for Notebooks + case 0x0992: // QuickCam Communicate Deluxe + case 0x0994: // QuickCam Orbit/Sphere AF + case 0x09a1: // QuickCam Communicate MP/S5500 + case 0x09a2: // QuickCam Communicate Deluxe/S7500 + case 0x09a4: // QuickCam E 3500 + case 0x09a5: // Quickcam 3000 For Business + case 0x09a6: // QuickCam Vision Pro + case 0x09b0: // Acer OrbiCam + case 0x09b2: // Fujitsu Webcam + case 0x09c0: // QuickCam for Dell Notebooks Mic + case 0x09c1: // QuickCam Deluxe for Notebooks + case 0x8801: // Video Camera + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0471: // Philips (or NXP) + switch (IdProduct) + { + case 0x0302: // PCA645VC Webcam [pwc] + case 0x0303: // PCA646VC Webcam [pwc] + case 0x0304: // Askey VC010 Webcam [pwc] + case 0x0307: // PCVC675K Webcam [pwc] + case 0x0308: // PCVC680K Webcam [pwc] + case 0x030b: // PC VGA Camera (Vesta Fun) + case 0x030c: // PCVC690K Webcam [pwc] + case 0x0310: // PCVC730K Webcam [pwc] + case 0x0311: // PCVC740K ToUcam Pro [pwc] + case 0x0312: // PCVC750K Webcam [pwc] + case 0x0321: // FunCam + case 0x0322: // DMVC1300K PC Camera + case 0x0325: // SPC 200NC PC Camera + case 0x0326: // SPC 300NC PC Camera + case 0x0327: // Webcam SPC 6000 NC (Webcam w/ mic) + case 0x0328: // SPC 700NC PC Camera + case 0x0329: // SPC 900NC PC Camera / ORITE CCD Webcam(PC370R) + case 0x032d: // SPC 210NC PC Camera + case 0x032e: // SPC 315NC PC Camera + case 0x0330: // SPC 710NC PC Camera + case 0x0331: // SPC 1300NC PC Camera + case 0x0332: // SPC 1000NC PC Camera + case 0x0333: // SPC 620NC PC Camera + case 0x0334: // SPC 520/525NC PC Camera + case 0x2034: // Webcam SPC530NC + case 0x2036: // Webcam SPC1030NC + case 0x20d0: // SPZ2000 Webcam [PixArt PAC7332] + case 0x262c: // SPC230NC Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0472: // Chicony Electronics Co., Ltd + switch (IdProduct) + { + case 0xb086: // Asus USB2.0 Webcam + case 0xb091: // Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x04ca: // Lite-On Technology Corp. + switch (IdProduct) + { + case 0x300b: // Atheros AR3012 Bluetooth // USB\Vid_04ca&Pid_300b&Rev_0001 + case 0x7025: // HP HD Webcam + case 0x7046: // TOSHIBA Web Camera - HD + Result = TRUE; + break; + default: + break; + } + break; + + case 0x04f2: // Chicony Electronics Co., Ltd + switch (IdProduct) + { + case 0xa001: // E-Video DC-100 Camera + case 0xa120: // ORITE CCD Webcam(PC370R) + case 0xa121: // ORITE CCD Webcam(PC370R) + case 0xa122: // ORITE CCD Webcam(PC370R) + case 0xa123: // ORITE CCD Webcam(PC370R) + case 0xa124: // ORITE CCD Webcam(PC370R) + case 0xa133: // Gateway Webcam + case 0xa136: // LabTec Webcam 5500 + case 0xa147: // Medion Webcam + case 0xb008: // USB 2.0 Camera + case 0xb009: // Integrated Camera + case 0xb010: // Integrated Camera + case 0xb012: // 1.3 MPixel UVC Webcam + case 0xb013: // USB 2.0 Camera + case 0xb015: // VGA 24fps UVC Webcam + case 0xb016: // VGA 30fps UVC Webcam + case 0xb018: // 2M UVC Webcam + case 0xb021: // ViewSonic 1.3M, USB2.0 Webcam + case 0xb022: // Gateway USB 2.0 Webcam + case 0xb023: // Gateway USB 2.0 Webcam + case 0xb024: // USB 2.0 Webcam + case 0xb025: // Camera + case 0xb027: // Gateway USB 2.0 Webcam + case 0xb028: // VGA UVC Webcam + case 0xb029: // 1.3M UVC Webcam + case 0xb036: // Asus Integrated 0.3M UVC Webcam + case 0xb044: // Acer CrystalEye Webcam + case 0xb057: // integrated USB webcam + case 0xb059: // CKF7037 HP webcam + case 0xb064: // CNA7137 Integrated Webcam + case 0xb070: // Camera + case 0xb071: // 2.0M UVC Webcam / CNF7129 // USB\Vid_04f2&Pid_b071 + case 0xb083: // CKF7063 Webcam (HP) + case 0xb091: // Webcam + case 0xb104: // CNF7069 Webcam + case 0xb107: // CNF7070 Webcam + case 0xb14c: // CNF8050 Webcam + case 0xb159: // CNF8243 Webcam + case 0xb15c: // Sony Vaio Integrated Camera + case 0xb1aa: // Webcam-101 + case 0xb1b4: // Lenovo Integrated Camera + case 0xb1b9: // Asus Integrated Webcam + case 0xb1cf: // Lenovo Integrated Camera + case 0xb1d6: // CNF9055 Toshiba Webcam // USB\Vid_04f2&Pid_b1d6 + case 0xb1d8: // 1.3M Webcam + case 0xb1e4: // Toshiba Integrated Webcam + case 0xb213: // Fujitsu Integrated Camera + case 0xb217: // Lenovo Integrated Camera (0.3MP) + case 0xb221: // integrated camera + case 0xb230: // Integrated HP HD Webcam + case 0xb257: // Lenovo Integrated Camera + case 0xb26b: // Sony Visual Communication Camera + case 0xb272: // Lenovo EasyCamera + case 0xb2b0: // Camera + case 0xb2b9: // Lenovo Integrated Camera UVC + case 0xb2da: // thinkpad t430s camera + case 0xb2ea: // Integrated Camera [ThinkPad] + case 0xb330: // Asus 720p CMOS webcam + case 0xb354: // UVC 1.00 device HD UVC WebCam + case 0xb367: // webcamera // USB\Vid_04f2&Pid_b367&Rev_3114 + case 0xb394: // Integrated Camera + case 0xb3d6: // webcamera // USB\Vid_04f2&Pid_b3d6&Rev_3907 + case 0xb3eb: // HP 720p HD Monitor Webcam + case 0xb3f6: // HD WebCam (Acer) + case 0xb3fd: // HD WebCam (Asus N-series) + case 0xb40e: // HP Truevision HD camera + case 0xb444: // Lenovo Integrated Webcam + case 0xb469: // webcamera // USB\Vid_04f2&Pid_b469 + Result = TRUE; + break; + default: + break; + } + break; + + case 0x04e8: // Samsung Electronics Co., Ltd + switch (IdProduct) + { + case 0x1323: // WB700 Camera + case 0x675b: // D900e Camera + Result = TRUE; + break; + default: + break; + } + break; + + case 0x04fc: // Sunplus Technology Co., Ltd + switch (IdProduct) + { + case 0x2080: // ASUS Webcam + case 0x500c: // CA500C Digital Camera + case 0x504a: // Aiptek Mini PenCam 1.3 + case 0x504b: // Aiptek Mega PockerCam 1.3/Maxell MaxPocket LE 1.3 + case 0x5331: // Vivitar Vivicam 10 + case 0x5360: // Sunplus Generic Digital Camera + Result = TRUE; + break; + default: + break; + } + break; + + case 0x05c8: // Cheng Uei Precision Industry Co., Ltd (Foxlink) + switch (IdProduct) + { + case 0x0103: // FO13FF-65 PC-CAM + case 0x010b: // Webcam (UVC) + case 0x021a: // HP Webcam + case 0x0318: // Webcam + case 0x0359: // Webcam // USB\Vid_05c8&Pid_0359 + case 0x0361: // SunplusIT INC. HP Truevision HD Webcam + case 0x036e: // Webcam + case 0x0403: // Webcam + case 0x041b: // HP 2.0MP High Definition Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x064e: // Suyin Corp. + switch (IdProduct) + { + case 0x2100: // Sony Visual Communication Camera + case 0x9700: // Asus Integrated Webcam + case 0xa100: // Acer OrbiCam + case 0xa101: // Acer CrystalEye Webcam + case 0xa102: // Acer/Lenovo Webcam [CN0316] + case 0xa103: // Acer/HP Integrated Webcam [CN0314] + case 0xa110: // HP Webcam + case 0xa114: // Lemote Webcam + case 0xa116: // UVC 1.3MPixel WebCam + case 0xa136: // Asus Integrated Webcam [CN031B] + case 0xa219: // 1.3M WebCam (notebook emachines E730, Acer sub-brand) + case 0xc107: // HP webcam [dv6-1190en] + case 0xc335: // HP TrueVision HD + case 0xd101: // Acer CrystalEye Webcam // USB\Vid_064e&Pid_d101 + case 0xd213: // UVC HD Webcam + case 0xd217: // HP TrueVision HD + case 0xe201: // Lenovo Integrated Webcam + case 0xe203: // Lenovo Integrated Webcam + case 0xe258: // HP TrueVision HD Integrated Webcam + case 0xe263: // HP TrueVision HD Integrated Webcam + case 0xf102: // Lenovo Integrated Webcam [R5U877] + case 0xf103: // Lenovo Integrated Webcam [R5U877] + case 0xf209: // HP Webcam + case 0xf300: // UVC 0.3M Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0a5c: // Broadcom Corp. + switch (IdProduct) + { + case 0x219c: // Bluetooth Device // usb vid_0a5c&pid_219c&rev_0628 + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0ac8: // Z-Star Microelectronics Corp. + switch (IdProduct) + { + case 0x0301: // Web Camera + case 0x0302: // ZC0302 Webcam + case 0x0321: // Vimicro generic vc0321 Camera + case 0x0323: // Luxya WC-1200 USB 2.0 Webcam + case 0x301b: // ZC0301 Webcam + case 0x303b: // ZC0303 Webcam + case 0x305b: // ZC0305 Webcam + case 0x307b: // USB 1.1 Webcam + case 0x332d: // Vega USB 2.0 Camera + case 0x3343: // Sirius USB 2.0 Camera + case 0x3420: // Venus USB2.0 Camera + case 0xc001: // Sony embedded vimicro Camera + case 0xc002: // Visual Communication Camera VGP-VCC1 + case 0xc302: // Vega USB 2.0 Camera + case 0xc303: // Saturn USB 2.0 Camera + case 0xc326: // Namuga 1.3M Webcam + case 0xc33f: // Webcam // USB\Vid_0ac8&Pid_c42b&Rev_0904 + case 0xc429: // Lenovo ThinkCentre Web Camera + case 0xc42b: // Lenovo IdeaCentre Web Camera // USB\Vid_0ac8&Pid_c42b&Rev_0904 + case 0xc42d: // Lenovo IdeaCentre Web Camera + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0bda: // Realtek Semiconductor Corp. + switch (IdProduct) + { + case 0x570c: // Asus laptop camera + case 0x5730: // HP 2.0MP High Definition Webcam + case 0x5751: // Integrated Webcam + case 0x5775: // HP "Truevision HD" laptop camera + case 0x57b3: // Acer 640 ? 480 laptop camera + case 0x57b5: // laptop camera // USB\VID_0BDA&PID_57B5&REV_0012 + case 0x57da: // Built-In Video Camera + case 0x58c0: // Webcam + case 0x58c8: // Integrated Webcam HD + Result = TRUE; + break; + default: + break; + } + break; + + case 0x0c45: // Microdia + switch (IdProduct) + { + case 0x6001: // Genius VideoCAM NB + case 0x6005: // Sweex Mini Webcam + case 0x6007: // VideoCAM Eye + case 0x6009: // VideoCAM ExpressII + case 0x600d: // TwinkleCam USB camera + case 0x6011: // PC Camera (SN9C102) + case 0x6019: // PC Camera (SN9C102) + case 0x6024: // VideoCAM ExpressII + case 0x6025: // VideoCAM ExpressII + case 0x6028: // Typhoon Easycam USB 330K (older) + case 0x6029: // Triplex i-mini PC Camera + case 0x602a: // Meade ETX-105EC Camera + case 0x602b: // VideoCAM NB 300 + case 0x602c: // Clas Ohlson TWC-30XOP Webcam + case 0x602d: // VideoCAM ExpressII + case 0x602e: // VideoCAM Messenger + case 0x6030: // VideoCAM ExpressII + case 0x603f: // VideoCAM ExpressII + case 0x6040: // CCD PC Camera (PC390A) + case 0x606a: // CCD PC Camera (PC390A) + case 0x607a: // CCD PC Camera (PC390A) + case 0x607b: // Win2 PC Camera + case 0x607c: // CCD PC Camera (PC390A) + case 0x607e: // CCD PC Camera (PC390A) + case 0x6082: // VideoCAM Look + case 0x6083: // VideoCAM Look + case 0x608c: // VideoCAM Look + case 0x608e: // VideoCAM Look + case 0x608f: // PC Camera (SN9C103 + OV7630) + case 0x60a8: // VideoCAM Look + case 0x60aa: // VideoCAM Look + case 0x60ab: // PC Camera + case 0x60af: // VideoCAM Look + case 0x60b0: // Genius VideoCam Look + case 0x60c0: // PC Camera with Mic (SN9C105) + case 0x60c8: // Win2 PC Camera + case 0x60cc: // PC Camera with Mic (SN9C105) + case 0x60ec: // PC Camera with Mic (SN9C105) + case 0x60ef: // Win2 PC Camera + case 0x60fa: // PC Camera with Mic (SN9C105) + case 0x60fc: // PC Camera with Mic (SN9C105) + case 0x6108: // Win2 PC Camera + case 0x6122: // PC Camera (SN9C110) + case 0x6123: // PC Camera (SN9C110) + case 0x6128: // PC Camera (SN9C325 + OM6802) + case 0x612a: // PC Camera (SN9C325) + case 0x612c: // PC Camera (SN9C110) + case 0x612e: // PC Camera (SN9C110) + case 0x612f: // PC Camera (SN9C110) + case 0x6130: // PC Camera (SN9C120) + case 0x6138: // Win2 PC Camera + case 0x613a: // PC Camera (SN9C120) + case 0x613b: // Win2 PC Camera + case 0x613c: // PC Camera (SN9C120) + case 0x613e: // PC Camera (SN9C120) + case 0x6143: // PC Camera (SN9C120 + SP80708) + case 0x6240: // PC Camera (SN9C201 + MI1300) + case 0x6242: // PC Camera (SN9C201 + MI1310) + case 0x6243: // PC Camera (SN9C201 + S5K4AAFX) + case 0x6248: // PC Camera (SN9C201 + OV9655) + case 0x624b: // PC Camera (SN9C201 + CX1332) + case 0x624c: // PC Camera (SN9C201 + MI1320) + case 0x624e: // PC Camera (SN9C201 + SOI968) + case 0x624f: // PC Camera (SN9C201 + OV9650) + case 0x6251: // PC Camera (SN9C201 + OV9650) + case 0x6253: // PC Camera (SN9C201 + OV9650) + case 0x6260: // PC Camera (SN9C201 + OV7670ISP) + case 0x6262: // PC Camera (SN9C201 + OM6802) + case 0x6270: // PC Camera (SN9C201 + MI0360/MT9V011 or MI0360SOC/MT9V111) U-CAM PC Camera NE878, Whitcom WHC017, ... + case 0x627a: // PC Camera (SN9C201 + S5K53BEB) + case 0x627b: // PC Camera (SN9C201 + OV7660) + case 0x627c: // PC Camera (SN9C201 + HV7131R) + case 0x627f: // PC Camera (SN9C201 + OV965x + EEPROM) + case 0x6280: // PC Camera with Microphone (SN9C202 + MI1300) + case 0x6282: // PC Camera with Microphone (SN9C202 + MI1310) + case 0x6283: // PC Camera with Microphone (SN9C202 + S5K4AAFX) + case 0x6288: // PC Camera with Microphone (SN9C202 + OV9655) + case 0x628a: // PC Camera with Microphone (SN9C202 + ICM107) + case 0x628b: // PC Camera with Microphone (SN9C202 + CX1332) + case 0x628c: // PC Camera with Microphone (SN9C202 + MI1320) + case 0x628e: // PC Camera with Microphone (SN9C202 + SOI968) + case 0x628f: // PC Camera with Microphone (SN9C202 + OV9650) + case 0x62a0: // PC Camera with Microphone (SN9C202 + OV7670ISP) + case 0x62a2: // PC Camera with Microphone (SN9C202 + OM6802) + case 0x62b0: // PC Camera with Microphone (SN9C202 + MI0360/MT9V011 or MI0360SOC/MT9V111) + case 0x62b3: // PC Camera with Microphone (SN9C202 + OV9655) + case 0x62ba: // PC Camera with Microphone (SN9C202 + S5K53BEB) + case 0x62bb: // PC Camera with Microphone (SN9C202 + OV7660) + case 0x62bc: // PC Camera with Microphone (SN9C202 + HV7131R) + case 0x62be: // PC Camera with Microphone (SN9C202 + OV7663) + case 0x62c0: // Sonix USB 2.0 Camera + case 0x6300: // PC Microscope camera + case 0x6310: // Sonix USB 2.0 Camera + case 0x6340: // Camera + case 0x6341: // Defender G-Lens 2577 HD720p Camera + case 0x63e0: // Sonix Integrated Webcam + case 0x63f1: // Integrated Webcam + case 0x63f8: // Sonix Integrated Webcam + case 0x6409: // Webcam // USB\Vid_0c45&Pid_6409 + case 0x6413: // Integrated Webcam + case 0x6417: // Integrated Webcam + case 0x6419: // Integrated Webcam + case 0x641d: // 1.3 MPixel Integrated Webcam + case 0x6433: // Laptop Integrated Webcam HD (Composite Device) + case 0x643f: // Dell Integrated HD Webcam + case 0x644d: // 1.3 MPixel Integrated Webcam + case 0x6480: // Sonix 1.3 MP Laptop Integrated Webcam + case 0x648b: // Integrated Webcam + case 0x64bd: // Sony Visual Communication Camera + case 0x64d0: // Integrated Webcam + case 0x64d2: // Integrated Webcam + case 0x651b: // HP Webcam + case 0x6705: // Integrated HD Webcam + case 0x6710: // Integrated Webcam + case 0x8006: // Dual Mode Camera (8006 VGA) + case 0x800a: // Vivitar Vivicam3350B + Result = TRUE; + break; + default: + break; + } + break; + + case 0x174f: // Syntek + switch (IdProduct) + { + case 0x110b: // HP Webcam + case 0x1403: // Integrated Webcam + case 0x1404: // USB Camera device, 1.3 MPixel Web Cam + case 0x5212: // USB 2.0 UVC PC Camera + case 0x5a11: // PC Camera // USB\Vid_174f&Pid_5a11 + case 0x5a31: // Sonix USB 2.0 Camera + case 0x5a35: // Sonix 1.3MPixel USB 2.0 Camera + case 0x6a31: // Web Cam - Asus A8J, F3S, F5R, VX2S, V1S + case 0x6a33: // Web Cam - Asus F3SA, F9J, F9S + case 0x6a51: // 2.0MPixel Web Cam - Asus Z96J, Z96S, S96S + case 0x6a54: // Web Cam + case 0x6d51: // 2.0Mpixel Web Cam - Eurocom D900C + case 0x8a12: // Syntek 0.3MPixel USB 2.0 UVC PC Camera + case 0x8a33: // Syntek USB 2.0 UVC PC Camera + case 0xa311: // 1.3MPixel Web Cam - Asus A3A, A6J, A6K, A6M, A6R, A6T, A6V, A7T, A7sv, A7U + case 0xa312: // 1.3MPixel Web Cam + case 0xa821: // Web Cam - Packard Bell BU45, PB Easynote MX66-208W + case 0xaa11: // Web Cam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x17ef: // Lenovo + switch (IdProduct) + { + case 0x1004: // Integrated Webcam + case 0x4802: // Lenovo Vc0323+MI1310_SOC Camera + case 0x4807: // UVC Camera + case 0x480c: // Integrated Webcam + case 0x480d: // Integrated Webcam [R5U877] + case 0x480e: // Integrated Webcam [R5U877] + case 0x480f: // Integrated Webcam [R5U877] + case 0x4810: // Integrated Webcam [R5U877] + case 0x4811: // Integrated Webcam [R5U877] + case 0x4812: // Integrated Webcam [R5U877] + case 0x4813: // Integrated Webcam [R5U877] + case 0x4814: // Integrated Webcam [R5U877] + case 0x4815: // Integrated Webcam [R5U877] + case 0x4816: // Integrated Webcam + case 0x481c: // Integrated Webcam + case 0x481d: // Integrated Webcam + Result = TRUE; + break; + default: + break; + } + break; + + case 0x1bcf: // Sunplus Innovation Technology Inc. + switch (IdProduct) + { + case 0x2880: // Dell HD Webcam + case 0x2885: // ASUS Webcam + case 0x2888: // HP Universal Camera + case 0x28a2: // Dell Integrated Webcam + case 0x28a6: // DELL XPS Integrated Webcam + case 0x28ae: // Laptop Integrated Webcam HD + case 0x28bd: // Dell Integrated HD Webcam + case 0x2985: // Laptop Integrated Webcam HD + case 0x2b83: // Laptop Integrated Webcam FHD + case 0x2c18: // HD WebCam USB\VID_1BCF&PID_2C18&REV_0009&MI_00 + Result = TRUE; + break; + default: + break; + } + break; + + case 0x2232: // Silicon Motion + switch (IdProduct) + { + case 0x1005: // WebCam SCB-0385N + case 0x1020: // WebCam // USB\Vid_2232&Pid_1020 + case 0x1028: // WebCam SC-03FFL11939N // USB\Vid_2232&Pid_1028&Rev_0001 + case 0x1029: // WebCam SC-13HDL11939N + case 0x1037: // WebCam SC-03FFM12339N + Result = TRUE; + break; + default: + break; + } + break; + + case 0x5986: // Acer, Inc + switch (IdProduct) + { + case 0x0100: // Orbicam + case 0x0101: // USB2.0 Camera + case 0x0102: // Crystal Eye Webcam + case 0x01a6: // Lenovo Integrated Webcam + case 0x01a7: // Lenovo Integrated Webcam + case 0x01a9: // Lenovo Integrated Webcam + case 0x0200: // OrbiCam + case 0x0203: // BisonCam NB Pro 1300 + case 0x0241: // BisonCam, NB Pro + case 0x02d0: // Lenovo Integrated Webcam [R5U877] + case 0x03d0: // Lenovo Integrated Webcam [R5U877] + Result = TRUE; + break; + default: + break; + } + break; + + case 0x8086: // Intel Corp. + switch (IdProduct) + { + case 0x0110: // Easy PC Camera + case 0x0120: // PC Camera CS120 + case 0x0630: // Pocket PC Camera + Result = TRUE; + break; + default: + break; + } + break; + + case 0xeb1a: // eMPIA Technology, Inc. + switch (IdProduct) + { + case 0x2571: // M035 Compact Web Cam + case 0x2710: // SilverCrest Webcam + case 0x2750: // ECS Elitegroup G220 integrated Webcam + case 0x2761: // EeePC 701 integrated Webcam + Result = TRUE; + break; + default: + break; + } + break; + + default: + break; + } + + if (Result) + { + DPRINT1("USBH_IsVidPidFromBlackList: IdVendor - %X, IdProduct - %X\n", + IdVendor, + IdProduct); + } + + return Result; +} diff --git a/drivers/usb/usbhub_new/pnp.c b/drivers/usb/usbhub_new/pnp.c index f437752..71ddb7d 100644 --- a/drivers/usb/usbhub_new/pnp.c +++ b/drivers/usb/usbhub_new/pnp.c @@ -14,6 +14,8 @@ #define NDEBUG_USBHUB_ENUM #include "dbg_uhub.h" +#define BOOT_FROM_USB 1 + NTSTATUS NTAPI USBH_IrpCompletion(IN PDEVICE_OBJECT DeviceObject, @@ -1063,6 +1065,15 @@ USBH_FdoQueryBusRelations(IN PUSBHUB_FDO_EXTENSION HubExtension, if (!(HubExtension->HubFlags & USBHUB_FDO_FLAG_DO_ENUMERATION)) { +#if BOOT_FROM_USB + { + LARGE_INTEGER Interval; + Status = STATUS_SUCCESS; + IoInvalidateDeviceRelations(HubExtension->LowerPDO, BusRelations); + Interval.QuadPart = -10000LL * 1000; // 1 sec. + KeDelayExecutionThread(KernelMode, FALSE, &Interval); + } +#endif DPRINT_ENUM("USBH_FdoQueryBusRelations: Skip enumeration\n"); goto RelationsWorker; } @@ -1585,6 +1596,17 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, 0, L"USB\\Vid_0000&Pid_0000"); } + else if (USBH_IsVidPidFromBlackList(DeviceDescriptor->idVendor, + DeviceDescriptor->idProduct, + DeviceDescriptor->bcdDevice)) + { + RtlStringCbPrintfExW(Buffer, + Remaining, + NULL, + &Remaining, + 0, + L"USB\\Vid_0000&Pid_0000"); + } else { RtlStringCbPrintfExW(Buffer, @@ -1597,7 +1619,7 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, DeviceDescriptor->idProduct); } - Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL)); + Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL)); Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG); @@ -1624,6 +1646,17 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, 0, L"USB\\UNKNOWN"); } + else if (USBH_IsVidPidFromBlackList(DeviceDescriptor->idVendor, + DeviceDescriptor->idProduct, + DeviceDescriptor->bcdDevice)) + { + RtlStringCbPrintfExW(Buffer, + Remaining, + NULL, + &Remaining, + 0, + L"USB\\UNKNOWN"); + } else { RtlStringCbPrintfExW(Buffer, @@ -1649,7 +1682,7 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, DeviceDescriptor->idProduct); } - Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL)); + Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL)); Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG); @@ -1662,7 +1695,7 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED) { - DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id); + DPRINT("USBH_PdoQueryId: BusQueryHardwareID - %S\n", Id); } else { @@ -1685,6 +1718,17 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, 0, L"USB\\UNKNOWN"); } + else if (USBH_IsVidPidFromBlackList(DeviceDescriptor->idVendor, + DeviceDescriptor->idProduct, + DeviceDescriptor->bcdDevice)) + { + RtlStringCbPrintfExW(Buffer, + Remaining, + NULL, + &Remaining, + 0, + L"USB\\UNKNOWN"); + } else if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_MULTI_INTERFACE) { RtlStringCbPrintfExW(Buffer, @@ -1766,7 +1810,7 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, InterfaceDescriptor->bInterfaceClass); } - Length = sizeof(Buffer) - (Remaining - sizeof(UNICODE_NULL)); + Length = sizeof(Buffer) - (Remaining - 2 * sizeof(UNICODE_NULL)); Id = ExAllocatePoolWithTag(PagedPool, Length, USB_HUB_TAG); @@ -1779,7 +1823,7 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, if (PortExtension->PortPdoFlags & USBHUB_PDO_FLAG_INIT_PORT_FAILED) { - DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id); + DPRINT("USBH_PdoQueryId: BusQueryHardwareID - %S\n", Id); } else { @@ -1823,7 +1867,7 @@ USBH_PdoQueryId(IN PUSBHUB_PORT_PDO_EXTENSION PortExtension, } } - DPRINT("USBH_PdoQueryId: BusQueryInstanceID - %S\n", Id); + DPRINT("USBH_PdoQueryId: BusQueryHardwareID - %S\n", Id); break; default: diff --git a/drivers/usb/usbhub_new/usbhub.h b/drivers/usb/usbhub_new/usbhub.h index d0f2553..dd97b59 100644 --- a/drivers/usb/usbhub_new/usbhub.h +++ b/drivers/usb/usbhub_new/usbhub.h @@ -654,4 +654,11 @@ DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath); +/* blacklst.c */ +BOOLEAN +NTAPI +USBH_IsVidPidFromBlackList(IN USHORT IdVendor, + IN USHORT IdProduct, + IN USHORT Revision); + #endif /* _USBHUB_H_ */ diff --git a/drivers/usb/usbport/pnp.c b/drivers/usb/usbport/pnp.c index 4e7a545..545b75e 100644 --- a/drivers/usb/usbport/pnp.c +++ b/drivers/usb/usbport/pnp.c @@ -1493,7 +1493,7 @@ USBPORT_GetDeviceHwIds(IN PDEVICE_OBJECT FdoDevice, L"USB\\ROOT_HUB"); } - Length = (sizeof(Buffer) - Remaining + sizeof(UNICODE_NULL)); + Length = (sizeof(Buffer) - Remaining + 2 * sizeof(UNICODE_NULL)); /* for debug only */ if (FALSE) diff --git a/drivers/usb/usbstor_new/CMakeLists.txt b/drivers/usb/usbstor_new/CMakeLists.txt index 3bb2eed..cbe20a3 100644 --- a/drivers/usb/usbstor_new/CMakeLists.txt +++ b/drivers/usb/usbstor_new/CMakeLists.txt @@ -20,6 +20,6 @@ add_library(usbstor SHARED usbstor.rc) set_module_type(usbstor kernelmodedriver) -add_importlibs(usbstor ntoskrnl hal usbd) +add_importlibs(usbstor usbd hal ntoskrnl) add_pch(usbstor usbstor.h SOURCE) add_cd_file(TARGET usbstor DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/usb/usbstor_new/disk.c b/drivers/usb/usbstor_new/disk.c index 604f621..37d0dc6 100644 --- a/drivers/usb/usbstor_new/disk.c +++ b/drivers/usb/usbstor_new/disk.c @@ -14,6 +14,72 @@ #define NDEBUG #include +BOOLEAN +NTAPI +IsRequestValid(PIRP Irp) +{ + ULONG TransferLength; + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK Srb; + + DPRINT("IsRequestValid: ... \n"); + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Srb = IoStack->Parameters.Scsi.Srb; + + if (Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) + { + if ((Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == + SRB_FLAGS_UNSPECIFIED_DIRECTION) + { + DPRINT1("IsRequestValid: Invalid Srb. Srb->SrbFlags - %X\n", Srb->SrbFlags); + return FALSE; + } + + TransferLength = Srb->DataTransferLength; + + if (Irp->MdlAddress == NULL) + { + DPRINT1("IsRequestValid: Invalid Srb. Irp->MdlAddress == NULL\n"); + return FALSE; + } + + if (TransferLength == 0) + { + DPRINT1("IsRequestValid: Invalid Srb. TransferLength == 0\n"); + return FALSE; + } + + if (TransferLength > USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH) + { + DPRINT1("IsRequestValid: Invalid Srb. TransferLength > 0x10000\n"); + return FALSE; + } + } + else + { + if (Srb->DataTransferLength) + { + DPRINT1("IsRequestValid: Invalid Srb. Srb->DataTransferLength != 0\n"); + return FALSE; + } + + if (Srb->DataBuffer) + { + DPRINT1("IsRequestValid: Invalid Srb. Srb->DataBuffer != NULL\n"); + return FALSE; + } + + if (Irp->MdlAddress) + { + DPRINT1("IsRequestValid: Invalid Srb. Irp->MdlAddress != NULL\n"); + return FALSE; + } + } + + return TRUE; +} + NTSTATUS USBSTOR_HandleInternalDeviceControl( IN PDEVICE_OBJECT DeviceObject, @@ -32,7 +98,7 @@ USBSTOR_HandleInternalDeviceControl( // // get request block // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + Request = IoStack->Parameters.Scsi.Srb; // // sanity check @@ -55,42 +121,29 @@ USBSTOR_HandleInternalDeviceControl( { DPRINT("SRB_FUNCTION_EXECUTE_SCSI\n"); - // - // check if request is valid - // - if (Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) + if (!IsRequestValid(Irp)) { - // - // data is transferred with this irp - // - if ((Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) || - Request->DataTransferLength == 0 || - Irp->MdlAddress == NULL) - { - // - // invalid parameter - // - Status = STATUS_INVALID_PARAMETER; - break; - } + DPRINT1("USBSTOR_HandleInternalDeviceControl: Bad Srb!\n"); + Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; } - else + + if (Request->Cdb[0] == SCSIOP_MODE_SENSE) { - // - // sense buffer request - // - if (Request->DataTransferLength || - Request->DataBuffer || - Irp->MdlAddress) - { - // - // invalid parameter - // - Status = STATUS_INVALID_PARAMETER; - break; - } + DPRINT("USBSTOR_Scsi: SRB_FUNCTION_EXECUTE_SCSI - FIXME SCSIOP_MODE_SENSE\n"); + // FIXME Get from registry WriteProtect for StorageDevicePolicies; + // L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\StorageDevicePolicies" + // QueryTable[0].Name = L"WriteProtect" } + IoStack->Parameters.Others.Argument2 = PDODeviceExtension; + + // mark irp pending + IoMarkIrpPending(Irp); + Request->SrbStatus = SRB_STATUS_PENDING; + // // add the request // @@ -170,12 +223,25 @@ USBSTOR_HandleInternalDeviceControl( Status = STATUS_SUCCESS; break; } - case SRB_FUNCTION_SHUTDOWN: + { + // handle this case only for current storage stack + // for proper storage stack it not need + DPRINT1("SRB_FUNCTION_SHUTDOWN - STATUS_SUCCESS FIXME\n"); + Status = STATUS_SUCCESS; + Request->SrbStatus = SRB_STATUS_SUCCESS; + break; + } case SRB_FUNCTION_FLUSH: + { + DPRINT1("SRB_FUNCTION_FLUSH \n"); + Status = STATUS_SUCCESS; + Request->SrbStatus = SRB_STATUS_SUCCESS; + break; + } case SRB_FUNCTION_FLUSH_QUEUE: { - DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE / SRB_FUNCTION_SHUTDOWN\n"); + DPRINT1("SRB_FUNCTION_FLUSH_QUEUE\n"); // HACK: don't flush pending requests #if 0 // we really need a proper storage stack @@ -329,7 +395,7 @@ USBSTOR_HandleQueryProperty( // // get inquiry data // - InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + InquiryData = &PDODeviceExtension->InquiryData; ASSERT(InquiryData); // @@ -502,8 +568,8 @@ USBSTOR_HandleQueryProperty( // AdapterDescriptor->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR); AdapterDescriptor->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR); - AdapterDescriptor->MaximumTransferLength = MAXULONG; //FIXME compute some sane value - AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value + AdapterDescriptor->MaximumTransferLength = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH; + AdapterDescriptor->MaximumPhysicalPages = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH / PAGE_SIZE + 1; // See CORE-10515 and CORE-10755 AdapterDescriptor->AlignmentMask = 0; AdapterDescriptor->AdapterUsesPio = FALSE; AdapterDescriptor->AdapterScansDown = FALSE; @@ -594,8 +660,8 @@ USBSTOR_HandleDeviceControl( if (Capabilities) { - Capabilities->MaximumTransferLength = MAXULONG; - Capabilities->MaximumPhysicalPages = 25; + Capabilities->MaximumTransferLength = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH; + Capabilities->MaximumPhysicalPages = USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH / PAGE_SIZE + 1; // See CORE-10515 and CORE-10755 Capabilities->SupportedAsynchronousEvents = 0; Capabilities->AlignmentMask = 0; Capabilities->TaggedQueuing = FALSE; @@ -628,7 +694,7 @@ USBSTOR_HandleDeviceControl( // // get inquiry data // - UFIInquiryResponse = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + UFIInquiryResponse = &PDODeviceExtension->InquiryData; ASSERT(UFIInquiryResponse); @@ -650,6 +716,8 @@ USBSTOR_HandleDeviceControl( /* Hack for IoReadPartitionTable call in disk.sys */ ScsiInquiryData->RemovableMedia = ((ScsiInquiryData->DeviceType != DIRECT_ACCESS_DEVICE) ? ((UFIInquiryResponse->RMB & 0x80) ? 1 : 0) : 0); + // should be: + //ScsiInquiryData->RemovableMedia = ((ScsiInquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ? ((UFIInquiryResponse->RMB & 0x80) ? 1 : 0) : 0); ScsiInquiryData->Versions = 0x04; ScsiInquiryData->ResponseDataFormat = 0x02; diff --git a/drivers/usb/usbstor_new/error.c b/drivers/usb/usbstor_new/error.c index e920d35..924bdb0 100644 --- a/drivers/usb/usbstor_new/error.c +++ b/drivers/usb/usbstor_new/error.c @@ -15,53 +15,6 @@ #include NTSTATUS -USBSTOR_GetEndpointStatus( - IN PDEVICE_OBJECT DeviceObject, - IN UCHAR bEndpointAddress, - OUT PUSHORT Value) -{ - PURB Urb; - NTSTATUS Status; - - // - // allocate urb - // - DPRINT("Allocating URB\n"); - Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); - if (!Urb) - { - // - // out of memory - // - DPRINT1("OutofMemory!\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // - // build status - // - UsbBuildGetStatusRequest(Urb, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, bEndpointAddress & 0x0F, Value, NULL, NULL); - - // - // send the request - // - DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); - Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); - - // - // free urb - // - FreeItem(Urb); - - // - // done - // - return Status; -} - - - -NTSTATUS USBSTOR_ResetPipeWithHandle( IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeHandle) @@ -107,304 +60,194 @@ USBSTOR_ResetPipeWithHandle( return Status; } - NTSTATUS -USBSTOR_HandleTransferError( - PDEVICE_OBJECT DeviceObject, - PIRP_CONTEXT Context) +NTAPI +USBSTOR_IsDeviceConnected( + IN PDEVICE_OBJECT DeviceObject) { - NTSTATUS Status = STATUS_SUCCESS; - PIO_STACK_LOCATION Stack; - PSCSI_REQUEST_BLOCK Request; - PCDB pCDB; - - // - // sanity checks - // - ASSERT(Context); - ASSERT(Context->PDODeviceExtension); - ASSERT(Context->PDODeviceExtension->Self); - ASSERT(Context->Irp); - - // - // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification - // - Status = USBSTOR_ResetDevice(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension); - if (NT_SUCCESS(Status)) - { - // - // step 2 reset bulk in pipe section 5.3.4 - // - Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); - if (NT_SUCCESS(Status)) - { - // - // finally reset bulk out pipe - // - Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle); - } - } - - // - // get next stack location - // - Stack = IoGetCurrentIrpStackLocation(Context->Irp); - - // - // get request block - // - Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1; - ASSERT(Request); - - // - // obtain request type - // - pCDB = (PCDB)Request->Cdb; - ASSERT(pCDB); - - if (Status != STATUS_SUCCESS || Context->RetryCount >= 1) - { - // - // Complete the master IRP - // - Context->Irp->IoStatus.Status = Status; - Context->Irp->IoStatus.Information = 0; - USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); - IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); - - // - // Start the next request - // - USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); - - // - // srb handling finished - // - Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE; - - // - // clear timer srb - // - Context->FDODeviceExtension->LastTimerActiveSrb = NULL; - } - else - { - DPRINT1("Retrying Count %lu %p\n", Context->RetryCount, Context->PDODeviceExtension->Self); - - // - // re-schedule request - // - USBSTOR_HandleExecuteSCSI(Context->PDODeviceExtension->Self, Context->Irp, Context->RetryCount + 1); - - // - // srb error handling finished - // - Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE; - - // - // srb error handling finished - // - Context->FDODeviceExtension->TimerWorkQueueEnabled = TRUE; - - // - // clear timer srb - // - Context->FDODeviceExtension->LastTimerActiveSrb = NULL; - } - - // - // cleanup irp context - // - FreeItem(Context->cbw); - FreeItem(Context); - + DPRINT1("USBSTOR_IsDeviceConnected: UNIMPLEMENTED. FIXME.\n"); + DbgBreakPoint(); + return 0; +} - DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status); - return Status; +NTSTATUS +NTAPI +USBSTOR_ResetDevice( + IN PDEVICE_OBJECT FdoDevice) +{ + DPRINT1("USBSTOR_ResetDevice: UNIMPLEMENTED. FIXME.\n"); + DbgBreakPoint(); + return 0; } VOID NTAPI -USBSTOR_ResetHandlerWorkItemRoutine( - PVOID Context) +USBSTOR_BulkResetPipeWorkItem( + IN PDEVICE_OBJECT FdoDevice, + IN PVOID Context) { - NTSTATUS Status; - PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + PFDO_DEVICE_EXTENSION FDODeviceExtension; - // - // clear stall on BulkIn pipe - // - Status = USBSTOR_ResetPipeWithHandle(WorkItemData->Context->FDODeviceExtension->LowerDeviceObject, WorkItemData->Context->FDODeviceExtension->InterfaceInformation->Pipes[WorkItemData->Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); - DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status); + DPRINT("USBSTOR_BulkResetPipeWorkItem: \n"); - // - // now resend the csw as the stall got cleared - // - USBSTOR_SendCSW(WorkItemData->Context, WorkItemData->Irp); + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, + FDODeviceExtension->Urb.PipeHandle); + + USBSTOR_CswTransfer(FDODeviceExtension, FdoDevice->CurrentIrp); + + //FIXME RemoveLock } VOID NTAPI -ErrorHandlerWorkItemRoutine( - PVOID Context) +USBSTOR_BulkQueueResetPipe( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension) { - PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + DPRINT("USBSTOR_BulkQueueResetPipe: \n"); - if (WorkItemData->Context->ErrorIndex == 2) - { - // - // reset device - // - USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context); - } - else - { - // - // clear stall - // - USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData); - } + //FIXME RemoveLock - // - // Free Work Item Data - // - ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); + IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, + USBSTOR_BulkResetPipeWorkItem, + CriticalWorkQueue, + 0); } VOID NTAPI -USBSTOR_TimerWorkerRoutine( +USBSTOR_ResetDeviceWorkItem( + IN PDEVICE_OBJECT FdoDevice, IN PVOID Context) { PFDO_DEVICE_EXTENSION FDODeviceExtension; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + ULONG nx; NTSTATUS Status; - PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + KIRQL OldIrql; - // - // get device extension - // - FDODeviceExtension = (PFDO_DEVICE_EXTENSION)WorkItemData->DeviceObject->DeviceExtension; - ASSERT(FDODeviceExtension->Common.IsFDO); + DPRINT("USBSTOR_ResetDeviceWorkItem: \n"); - // - // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification - // - Status = USBSTOR_ResetDevice(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension); - if (NT_SUCCESS(Status)) + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)Context; + FDODeviceExtension = FdoDevice->DeviceExtension; + + if (FDODeviceExtension->CurrentIrp) { - // - // step 2 reset bulk in pipe section 5.3.4 - // - Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle); - if (NT_SUCCESS(Status)) + IoCancelIrp(FDODeviceExtension->CurrentIrp); + + KeWaitForSingleObject(&FDODeviceExtension->TimeOutEvent, + Executive, + KernelMode, + FALSE, + NULL); + + if (!Context) { - // - // finally reset bulk out pipe - // - Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle); + PIO_STACK_LOCATION IoStack; + + IoStack = IoGetCurrentIrpStackLocation(FDODeviceExtension->CurrentIrp); + PDODeviceExtension = IoStack->Parameters.Others.Argument2; } + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + IoCompleteRequest(FDODeviceExtension->CurrentIrp, IO_NO_INCREMENT); + KeLowerIrql(OldIrql); + + FDODeviceExtension->CurrentIrp = NULL; } - DPRINT1("Status %x\n", Status); - // - // clear timer srb - // - FDODeviceExtension->LastTimerActiveSrb = NULL; + for (nx = 0; nx < 3; ++nx) + { + Status = USBSTOR_IsDeviceConnected(FdoDevice); - // - // re-schedule request - // - //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1); + if (!NT_SUCCESS(Status)) + break; + + Status = USBSTOR_ResetDevice(FdoDevice); + + if (NT_SUCCESS(Status)) + break; + } + KeAcquireSpinLock(&FDODeviceExtension->StorSpinLock, &OldIrql); + FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_DEVICE_RESETTING; - // - // do not retry for the same packet again - // - FDODeviceExtension->TimerWorkQueueEnabled = FALSE; + if (!NT_SUCCESS(Status)) + FDODeviceExtension->Flags |= USBSTOR_FDO_FLAGS_DEVICE_ERROR; - // - // Free Work Item Data - // - ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); + KeReleaseSpinLock(&FDODeviceExtension->StorSpinLock, OldIrql); + + if (!FDODeviceExtension->DriverFlags) + FDODeviceExtension->DriverFlags = USBSTOR_DRIVER_FLAGS_BULKONLY; + + if (PDODeviceExtension) + USBSTOR_QueueNextRequest(FdoDevice); + + //FIXME RemoveLock } +VOID +NTAPI +USBSTOR_QueueResetDevice( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, + IN PPDO_DEVICE_EXTENSION PDODeviceExtension) +{ + KIRQL OldIrql; + + DPRINT("USBSTOR_QueueResetDevice: ... \n"); + + KeAcquireSpinLock(&FDODeviceExtension->StorSpinLock, &OldIrql); + FDODeviceExtension->Flags |= USBSTOR_FDO_FLAGS_DEVICE_RESETTING; + KeReleaseSpinLock(&FDODeviceExtension->StorSpinLock, OldIrql); + + //FIXME RemoveLock + + IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, + USBSTOR_ResetDeviceWorkItem, + CriticalWorkQueue, + PDODeviceExtension); +} VOID NTAPI USBSTOR_TimerRoutine( - PDEVICE_OBJECT DeviceObject, - PVOID Context) + IN PDEVICE_OBJECT FdoDevice, + IN PVOID Context) { PFDO_DEVICE_EXTENSION FDODeviceExtension; - BOOLEAN ResetDevice = FALSE; - PERRORHANDLER_WORKITEM_DATA WorkItemData; + BOOLEAN IsResetDevice = FALSE; - // - // get device extension - // - FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Context; - DPRINT1("[USBSTOR] TimerRoutine entered\n"); - DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension->ActiveSrb, FDODeviceExtension->ResetInProgress, FDODeviceExtension->LastTimerActiveSrb); + DPRINT("USBSTOR_TimerRoutine: ... \n"); - // - // acquire spinlock - // - KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock); + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FdoDevice->DeviceExtension; - // - // is there an active srb and no global reset is in progress - // - if (FDODeviceExtension->ActiveSrb && FDODeviceExtension->ResetInProgress == FALSE && FDODeviceExtension->TimerWorkQueueEnabled) + KefAcquireSpinLockAtDpcLevel(&FDODeviceExtension->StorSpinLock); + + if (!(FDODeviceExtension->Flags & USBSTOR_FDO_FLAGS_DEVICE_RESETTING)) { - if (FDODeviceExtension->LastTimerActiveSrb != NULL && FDODeviceExtension->LastTimerActiveSrb == FDODeviceExtension->ActiveSrb) + if (FDODeviceExtension->Flags & USBSTOR_FDO_FLAGS_TRANSFER_FINISHED) { - // - // check if empty - // - DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension->ActiveSrb); - ResetDevice = TRUE; - } - else - { - // - // update pointer - // - FDODeviceExtension->LastTimerActiveSrb = FDODeviceExtension->ActiveSrb; + FDODeviceExtension->SrbTimeOutValue--; + + if (FDODeviceExtension->SrbTimeOutValue == 1) + { + FDODeviceExtension->Flags |= USBSTOR_FDO_FLAGS_DEVICE_RESETTING; + IsResetDevice = TRUE; + } } } - else - { - // - // reset srb - // - FDODeviceExtension->LastTimerActiveSrb = NULL; - } - // - // release lock - // - KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock); + KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->StorSpinLock); - - if (ResetDevice && FDODeviceExtension->TimerWorkQueueEnabled && FDODeviceExtension->SrbErrorHandlingActive == FALSE) + if (IsResetDevice) { - WorkItemData = ExAllocatePoolWithTag(NonPagedPool, - sizeof(ERRORHANDLER_WORKITEM_DATA), - USB_STOR_TAG); - if (WorkItemData) - { - // - // Initialize and queue the work item to handle the error - // - ExInitializeWorkItem(&WorkItemData->WorkQueueItem, - USBSTOR_TimerWorkerRoutine, - WorkItemData); - - WorkItemData->DeviceObject = FDODeviceExtension->FunctionalDeviceObject; + //FIXME RemoveLock - DPRINT1("[USBSTOR] Queing Timer WorkItem\n"); - ExQueueWorkItem(&WorkItemData->WorkQueueItem, DelayedWorkQueue); - } - } + IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, + USBSTOR_ResetDeviceWorkItem, + CriticalWorkQueue, + 0); + } } diff --git a/drivers/usb/usbstor_new/fdo.c b/drivers/usb/usbstor_new/fdo.c index e370704..4fa750a 100644 --- a/drivers/usb/usbstor_new/fdo.c +++ b/drivers/usb/usbstor_new/fdo.c @@ -132,8 +132,9 @@ USBSTOR_FdoHandleRemoveDevice( DPRINT("Handling FDO removal %p\n", DeviceObject); - /* FIXME: wait for devices finished processing */ - for(Index = 0; Index < 16; Index++) + //FIXME RemoveLock + + for (Index = 0; Index < USB_MAXCHILDREN; Index++) { if (DeviceExtension->ChildPDO[Index] != NULL) { @@ -144,6 +145,7 @@ USBSTOR_FdoHandleRemoveDevice( /* Send the IRP down the stack */ IoSkipCurrentIrpStackLocation(Irp); + Irp->IoStatus.Status = STATUS_SUCCESS; Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); /* Detach from the device stack */ @@ -164,6 +166,7 @@ USBSTOR_FdoHandleStartDevice( PUSB_INTERFACE_DESCRIPTOR InterfaceDesc; NTSTATUS Status; UCHAR Index = 0; + PIO_WORKITEM WorkItem; // // forward irp to lower device @@ -178,6 +181,17 @@ USBSTOR_FdoHandleStartDevice( return Status; } + if (!DeviceExtension->ResetDeviceWorkItem) + { + WorkItem = IoAllocateWorkItem(DeviceObject); + DeviceExtension->ResetDeviceWorkItem = WorkItem; + + if (!WorkItem) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + // // initialize irp queue // @@ -211,22 +225,33 @@ USBSTOR_FdoHandleStartDevice( // ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE); ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR)); + ASSERT(InterfaceDesc->bInterfaceClass == USB_CLASS_MASS_STORAGE); DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass); - if (InterfaceDesc->bInterfaceProtocol != 0x50) + + if (InterfaceDesc->bInterfaceClass == USB_CLASS_MASS_STORAGE && + InterfaceDesc->bInterfaceProtocol == USB_PROTOCOL_BULK && + !DeviceExtension->DriverFlags) { - DPRINT1("USB Device is not a bulk only device and is not currently supported\n"); - return STATUS_NOT_SUPPORTED; + DeviceExtension->DriverFlags = USBSTOR_DRIVER_FLAGS_BULKONLY; } - - if (InterfaceDesc->bInterfaceSubClass != 0x06) + else { - // - // FIXME: need to pad CDBs to 12 byte - // mode select commands must be translated from 1AH / 15h to 5AH / 55h - // - DPRINT1("[USBSTOR] Error: need to pad CDBs\n"); - return STATUS_NOT_IMPLEMENTED; + if (InterfaceDesc->bInterfaceProtocol != USB_PROTOCOL_BULK) + { + DPRINT1("USB Device is not a bulk only device and is not currently supported\n"); + return STATUS_NOT_SUPPORTED; + } + + if (InterfaceDesc->bInterfaceSubClass != USB_SUBCLASS_SCSI) + { + // + // FIXME: need to pad CDBs to 12 byte + // mode select commands must be translated from 1AH / 15h to 5AH / 55h + // + DPRINT1("[USBSTOR] Error: need to pad CDBs\n"); + return STATUS_NOT_IMPLEMENTED; + } } // @@ -256,6 +281,11 @@ USBSTOR_FdoHandleStartDevice( } // + // start the timer + // + IoStartTimer(DeviceObject); + + // // get num of lun which are supported // Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension); @@ -313,13 +343,6 @@ USBSTOR_FdoHandleStartDevice( } #endif - - // - // start the timer - // - //IoStartTimer(DeviceObject); - - // // fdo is now initialized // @@ -404,14 +427,18 @@ USBSTOR_FdoHandlePnp( // we can if nothing is pending // if (DeviceExtension->IrpPendingCount != 0 || - DeviceExtension->ActiveSrb != NULL) + DeviceExtension->CurrentSrb != NULL) #else if (TRUE) #endif { - /* We have pending requests */ - DPRINT1("Failing removal/stop request due to pending requests present\n"); - Status = STATUS_UNSUCCESSFUL; + ///* We have pending requests */ + //DPRINT1("Failing removal/stop request due to pending requests present\n"); + //Status = STATUS_UNSUCCESSFUL; + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoSkipCurrentIrpStackLocation(Irp); + return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp); } else { @@ -459,3 +486,155 @@ USBSTOR_FdoHandlePnp( // return Status; } + +VOID +NTAPI +USBSTOR_FdoSetPowerCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN UCHAR MinorFunction, + IN POWER_STATE PowerState, + IN PVOID Context, + IN PIO_STATUS_BLOCK IoStatus) +{ + PDEVICE_OBJECT FdoDevice; + PFDO_DEVICE_EXTENSION FdoExtension; + PIRP CurrentPowerIrp; + + FdoDevice = Context; + FdoExtension = FdoDevice->DeviceExtension; + + CurrentPowerIrp = FdoExtension->CurrentPowerIrp; + FdoExtension->CurrentPowerIrp = NULL; + + PoStartNextPowerIrp(CurrentPowerIrp); + + IoCopyCurrentIrpStackLocationToNext(CurrentPowerIrp); + IoMarkIrpPending(CurrentPowerIrp); + + PoCallDriver(FdoExtension->LowerDeviceObject, CurrentPowerIrp); +} + +NTSTATUS +NTAPI +USBSTOR_FdoSetD0Completion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + NTSTATUS Status; + KIRQL OldIrql; + + Status = Irp->IoStatus.Status; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + IoStartNextPacket(DeviceObject, TRUE); + KeLowerIrql(OldIrql); + + PoStartNextPowerIrp(Irp); + return Status; +} + +NTSTATUS +NTAPI +USBSTOR_FdoSetPower( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PFDO_DEVICE_EXTENSION FdoExtension; + PIO_STACK_LOCATION IoStack; + POWER_STATE_TYPE Type; + POWER_STATE State; + POWER_STATE NewState; + POWER_STATE OldState; + + DPRINT("USBSTOR_FdoSetPower: DeviceObject %p, Irp %p\n", DeviceObject, Irp); + + FdoExtension = DeviceObject->DeviceExtension; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + Type = IoStack->Parameters.Power.Type; + State = IoStack->Parameters.Power.State; + + switch (Type) + { + case SystemPowerState: + { + FdoExtension->SystemState = State.SystemState; + + if (State.SystemState == PowerSystemWorking) + NewState.DeviceState = PowerDeviceD0; + else + NewState.DeviceState = PowerDeviceD3; + + if (FdoExtension->DeviceState != NewState.DeviceState) + { + FdoExtension->CurrentPowerIrp = Irp; + + DPRINT("USBSTOR_FdoSetPower: State.SystemState - %x\n", + State.SystemState); + + return PoRequestPowerIrp(FdoExtension->PhysicalDeviceObject, + IRP_MN_SET_POWER, + NewState, + USBSTOR_FdoSetPowerCompletion, + DeviceObject, + NULL); + } + + break; + } + case DevicePowerState: + { + OldState.DeviceState = FdoExtension->DeviceState; + FdoExtension->DeviceState = State.DeviceState; + + DPRINT("USBSTOR_FdoSetPower: State.DeviceState - %x, OldState.DeviceState - %x\n", + State.DeviceState, + OldState.DeviceState); + + if (OldState.DeviceState == PowerDeviceD0) + { + if (State.DeviceState > PowerDeviceD0) + { + ULONG Key = 0; + IoStartPacket(DeviceObject, Irp, &Key, NULL); + + KeWaitForSingleObject(&FdoExtension->PowerEvent, + Executive, + KernelMode, + FALSE, + NULL); + } + } + else + { + if (OldState.DeviceState > PowerDeviceD0 && + State.DeviceState == PowerDeviceD0) + { + IoCopyCurrentIrpStackLocationToNext(Irp); + + IoSetCompletionRoutine(Irp, + USBSTOR_FdoSetD0Completion, + NULL, + TRUE, + TRUE, + TRUE); + + return PoCallDriver(FdoExtension->LowerDeviceObject, Irp); + } + } + + break; + } + default: + { + ASSERT(FALSE); + break; + } + } + + PoStartNextPowerIrp(Irp); + IoSkipCurrentIrpStackLocation(Irp); + + return PoCallDriver(FdoExtension->LowerDeviceObject, Irp); +} diff --git a/drivers/usb/usbstor_new/misc.c b/drivers/usb/usbstor_new/misc.c index 6b60cf8..c2508df 100644 --- a/drivers/usb/usbstor_new/misc.c +++ b/drivers/usb/usbstor_new/misc.c @@ -27,9 +27,8 @@ USBSTOR_SyncForwardIrpCompletionRoutine( PVOID Context) { if (Irp->PendingReturned) - { KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); - } + return STATUS_MORE_PROCESSING_REQUIRED; } @@ -386,7 +385,7 @@ USBSTOR_GetMaxLUN( // 3.2 Get Max LUN (class-specific request) : // Devices that do not support multiple LUNs may STALL this command. // - USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension); + USBSTOR_BulkResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension); DeviceExtension->MaxLUN = 0; Status = STATUS_SUCCESS; @@ -401,11 +400,10 @@ USBSTOR_GetMaxLUN( // done // return Status; - } NTSTATUS -USBSTOR_ResetDevice( +USBSTOR_BulkResetDevice( IN PDEVICE_OBJECT DeviceObject, IN PFDO_DEVICE_EXTENSION DeviceExtension) { diff --git a/drivers/usb/usbstor_new/pdo.c b/drivers/usb/usbstor_new/pdo.c index 6ce5d8f..5bf62bd 100644 --- a/drivers/usb/usbstor_new/pdo.c +++ b/drivers/usb/usbstor_new/pdo.c @@ -14,64 +14,72 @@ #define NDEBUG #include +NTSTATUS +NTAPI +USBSTOR_SyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + DPRINT("USBSTOR_SyncCompletionRoutine: ... \n"); + KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + LPCSTR USBSTOR_GetDeviceType( IN PUFI_INQUIRY_RESPONSE InquiryData, IN UCHAR IsFloppy) { // - // check if device type is zero + // check device type // - if (InquiryData->DeviceType == 0) + switch (InquiryData->DeviceType) { - if (IsFloppy) + case USBSTOR_SCSI_DEVICE_TYPE_DIRECT: { + if (IsFloppy) + { + // + // floppy device + // + return "SFloppy"; + } + // - // floppy device + // direct access device // - return "SFloppy"; + return "Disk"; } - - // - // direct access device - // - return "Disk"; - } - - // - // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type - // - switch (InquiryData->DeviceType) - { - case 1: + case USBSTOR_SCSI_DEVICE_TYPE_SEQUENTIAL: { // // sequential device, i.e magnetic tape // return "Sequential"; } - case 4: + case USBSTOR_SCSI_DEVICE_TYPE_WORM: { // // write once device // return "Worm"; } - case 5: + case USBSTOR_SCSI_DEVICE_TYPE_CDROM: { // // CDROM device // return "CdRom"; } - case 7: + case USBSTOR_SCSI_DEVICE_TYPE_OPTICAL: { // // optical memory device // return "Optical"; } - case 8: + case USBSTOR_SCSI_DEVICE_TYPE_MEDIA_CHANGER: { // // medium change device @@ -94,58 +102,54 @@ USBSTOR_GetGenericType( IN UCHAR IsFloppy) { // - // check if device type is zero + // check device type // - if (InquiryData->DeviceType == 0) + switch (InquiryData->DeviceType) { - if (IsFloppy) + case USBSTOR_SCSI_DEVICE_TYPE_DIRECT: { + if (IsFloppy) + { + // + // floppy device + // + return "GenSFloppy"; + } + // - // floppy device + // direct access device // - return "GenSFloppy"; + return "GenDisk"; } - - // - // direct access device - // - return "GenDisk"; - } - - // - // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type - // - switch (InquiryData->DeviceType) - { - case 1: + case USBSTOR_SCSI_DEVICE_TYPE_SEQUENTIAL: { // // sequential device, i.e magnetic tape // return "GenSequential"; } - case 4: + case USBSTOR_SCSI_DEVICE_TYPE_WORM: { // // write once device // return "GenWorm"; } - case 5: + case USBSTOR_SCSI_DEVICE_TYPE_CDROM: { // // CDROM device // return "GenCdRom"; } - case 7: + case USBSTOR_SCSI_DEVICE_TYPE_OPTICAL: { // // optical memory device // return "GenOptical"; } - case 8: + case USBSTOR_SCSI_DEVICE_TYPE_MEDIA_CHANGER: { // // medium change device @@ -289,12 +293,12 @@ USBSTOR_PdoHandleQueryDeviceId( // // sanity check // - ASSERT(DeviceExtension->InquiryData); + ASSERT(&DeviceExtension->InquiryData); // // get inquiry data // - InquiryData = (PUFI_INQUIRY_RESPONSE)DeviceExtension->InquiryData; + InquiryData = &DeviceExtension->InquiryData; // // get device type @@ -441,7 +445,7 @@ USBSTOR_PdoHandleQueryHardwareId( // // get inquiry data // - InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; + InquiryData = &PDODeviceExtension->InquiryData; // @@ -603,7 +607,7 @@ USBSTOR_PdoHandleQueryCompatibleId( // // get target device type // - DeviceType = USBSTOR_GetDeviceType((PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy); + DeviceType = USBSTOR_GetDeviceType(&PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy); // // zero memory @@ -970,250 +974,177 @@ USBSTOR_PdoHandlePnp( NTSTATUS NTAPI -USBSTOR_CompletionRoutine( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Ctx) -{ - PKEVENT Event = (PKEVENT)Ctx; - - // - // signal event - // - KeSetEvent(Event, 0, FALSE); - return STATUS_MORE_PROCESSING_REQUIRED; -} - -NTSTATUS -USBSTOR_AllocateIrp( - IN PDEVICE_OBJECT DeviceObject, - IN ULONG DataTransferLength, - IN UCHAR OpCode, - IN PKEVENT Event, - OUT PSCSI_REQUEST_BLOCK *OutRequest, - OUT PIRP *OutIrp) +USBSTOR_SendInternalCdb( + PDEVICE_OBJECT PdoDevice, + PVOID DataBuffer, + PULONG OutDataTransferLength, + PVOID Buffer, + UCHAR CdbLength, + ULONG TimeOutValue) { - PIRP Irp; + PSCSI_REQUEST_BLOCK Srb; + PSENSE_DATA SenseBuffer; PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; - PCDB pCDB; + KEVENT Event; + PIRP Irp = NULL; + PMDL Mdl = NULL; + ULONG ix; + NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; + UCHAR SrbStatus; - // - // allocate irp - // - Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); - if (!Irp) - { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; - } + DPRINT("USBSTOR_IssueInternalCdb: ... \n"); - // - // get next stack location - // - IoStack = IoGetNextIrpStackLocation(Irp); + Srb = ExAllocatePoolWithTag(NonPagedPool, + sizeof(SCSI_REQUEST_BLOCK), + USB_STOR_TAG); - // - // create scsi block - // - Request = ExAllocatePoolWithTag(NonPagedPool, - sizeof(SCSI_REQUEST_BLOCK), - USB_STOR_TAG); - if (!Request) + if (Srb) { - // - // no memory - // - IoFreeIrp(Irp); - return STATUS_INSUFFICIENT_RESOURCES; - } + SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, + SENSE_BUFFER_SIZE, + USB_STOR_TAG); - // - // init request - // - RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK)); + if (SenseBuffer) + { + ix = 0; + + do + { + Irp = IoAllocateIrp(PdoDevice->StackSize, FALSE); + + if (!Irp) + { + break; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + IoStack->Parameters.Scsi.Srb = Srb; + + RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); + + Srb->Length = sizeof(SCSI_REQUEST_BLOCK); + Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; + Srb->CdbLength = CdbLength; + Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; + Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE; + Srb->DataTransferLength = *OutDataTransferLength; + Srb->TimeOutValue = TimeOutValue; + Srb->DataBuffer = DataBuffer; + Srb->SenseInfoBuffer = SenseBuffer; + + RtlCopyMemory(Srb->Cdb, Buffer, CdbLength); + + if (!ix) + { + Mdl = IoAllocateMdl(DataBuffer, + *OutDataTransferLength, + FALSE, + FALSE, + NULL); + + if (!Mdl) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + MmBuildMdlForNonPagedPool(Mdl); + } + + Irp->MdlAddress = Mdl; + + KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + + IoSetCompletionRoutine(Irp, + USBSTOR_SyncCompletionRoutine, + &Event, + TRUE, + TRUE, + TRUE); + + if (IoCallDriver(PdoDevice, Irp) == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + SrbStatus = SRB_STATUS(Srb->SrbStatus); + + if (SrbStatus == SRB_STATUS_SUCCESS || + SrbStatus == SRB_STATUS_DATA_OVERRUN) + { + Status = STATUS_SUCCESS; + *OutDataTransferLength = Srb->DataTransferLength; + break; + } + + Status = STATUS_UNSUCCESSFUL; + + IoFreeIrp(Irp); + + ++ix; + Irp = 0; + } + while (ix < 3); + + if (Mdl) + IoFreeMdl(Mdl); + + ExFreePool(SenseBuffer); + } - // - // allocate data transfer block - // - Request->DataBuffer = ExAllocatePoolWithTag(NonPagedPool, - DataTransferLength, - USB_STOR_TAG); - if (!Request->DataBuffer) - { - // - // no memory - // - IoFreeIrp(Irp); - ExFreePoolWithTag(Request, USB_STOR_TAG); - return STATUS_INSUFFICIENT_RESOURCES; - } + ExFreePool(Srb); - // - // allocate MDL - // - Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL); - if (!Irp->MdlAddress) - { - // - // no memory - // - IoFreeIrp(Irp); - ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG); - ExFreePoolWithTag(Request, USB_STOR_TAG); - return STATUS_INSUFFICIENT_RESOURCES; + if (Irp) + IoFreeIrp(Irp); } - // - // non paged pool - // - MmBuildMdlForNonPagedPool(Irp->MdlAddress); - - // - // init scsi block - // - Request->DataTransferLength = DataTransferLength; - Request->Function = SRB_FUNCTION_EXECUTE_SCSI; - Request->SrbFlags = SRB_FLAGS_DATA_IN; - - RtlZeroMemory(Request->DataBuffer, DataTransferLength); - - - // - // get SCSI command data block - // - pCDB = (PCDB)Request->Cdb; - - // - // set op code - // - pCDB->AsByte[0] = OpCode; - - // - // store result - // - IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IoStack->Parameters.Others.Argument1 = Request; - IoStack->DeviceObject = DeviceObject; - - // - // init event - // - KeInitializeEvent(Event, NotificationEvent, FALSE); - - // - // lets setup a completion routine - // - IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE); - - // - // output result - // - *OutIrp = Irp; - *OutRequest = Request; - return STATUS_SUCCESS; + return Status; } NTSTATUS -USBSTOR_SendIrp( - IN PDEVICE_OBJECT PDODeviceObject, - IN ULONG DataTransferLength, - IN UCHAR OpCode, - OUT PVOID *OutData) +NTAPI +USBSTOR_GetInquiryData( + PDEVICE_OBJECT PdoDevice) { - NTSTATUS Status; - PIRP Irp; - KEVENT Event; PPDO_DEVICE_EXTENSION PDODeviceExtension; - PSCSI_REQUEST_BLOCK Request; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + NTSTATUS Status; + ULONG TransferLength; + CDB Cdb; + PUFI_INQUIRY_RESPONSE Response; - // - // let's allocate an irp - // - Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp); - if (!NT_SUCCESS(Status)) - { - // - // failed - // - DPRINT1("[USBSTOR] Failed to build irp\n"); - return Status; - } + DPRINT("USBSTOR_GetInquiryData: ... \n"); - // - // get device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PdoDevice->DeviceExtension; + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; - // - // send irp - // - ASSERT(Irp); - ASSERT(PDODeviceExtension->LowerDeviceObject); - Status = IoCallDriver(PDODeviceExtension->Self, Irp); + TransferLength = INQUIRYDATABUFFERSIZE; - if (Status == STATUS_PENDING) - { - // - // wait for completion - // - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - Status = Irp->IoStatus.Status; - } + RtlZeroMemory(&Cdb, sizeof(Cdb)); - if (NT_SUCCESS(Status)) - { - // - // store result - // - *OutData = Request->DataBuffer; - } - else - { - // - // free the data - // - ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG); - *OutData = NULL; - } - - // - // free resources - // - ExFreePoolWithTag(Request, USB_STOR_TAG); - IoFreeMdl(Irp->MdlAddress); - IoFreeIrp(Irp); - return Status; -} - -NTSTATUS -USBSTOR_SendInquiryIrp( - IN PDEVICE_OBJECT PDODeviceObject) -{ - NTSTATUS Status; - PPDO_DEVICE_EXTENSION PDODeviceExtension; - PUFI_INQUIRY_RESPONSE Response; + Cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; + Cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE; - // - // get device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; + Status = USBSTOR_SendInternalCdb(PdoDevice, + &PDODeviceExtension->InquiryData, + &TransferLength, + &Cdb, + 0x06, // CdbLength + 20); // TimeOutValue - // - // send request - // - Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response); - if (!NT_SUCCESS(Status)) + if (NT_SUCCESS(Status) && !FDODeviceExtension->DriverFlags) { - // - // command failed - // - DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status); - return Status; + DPRINT("USBSTOR_GetInquiryData: DriverFlags = USBSTOR_DRIVER_FLAGS_UNKNOWN\n"); + FDODeviceExtension->DriverFlags = USBSTOR_DRIVER_FLAGS_UNKNOWN; } + Response = (PUFI_INQUIRY_RESPONSE)&PDODeviceExtension->InquiryData; + DPRINT1("Response %p\n", Response); DPRINT1("DeviceType %x\n", Response->DeviceType); DPRINT1("RMB %x\n", Response->RMB); @@ -1229,52 +1160,19 @@ USBSTOR_SendInquiryIrp( DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]); - // - // store result - // - PDODeviceExtension->InquiryData = (PVOID)Response; return Status; } -NTSTATUS -USBSTOR_SendFormatCapacityIrp( - IN PDEVICE_OBJECT PDODeviceObject) +BOOLEAN +NTAPI +USBSTOR_IsFloppyDevice( + PDEVICE_OBJECT DeviceObject) { - NTSTATUS Status; - PPDO_DEVICE_EXTENSION PDODeviceExtension; - PUCHAR Response; - - // - // get device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; - - // - // send request - // - Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response); - if (!NT_SUCCESS(Status)) - { - // - // command failed - // - return Status; - } - - // - // check if its a floppy - // - PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode); - - // - // free response - // - ExFreePoolWithTag(Response, USB_STOR_TAG); - return Status; + DPRINT1("USBSTOR_IsFloppyDevice: UNIMPLEMENTED. FIXME. \n"); +//ASSERT(FALSE); + return FALSE; } - - NTSTATUS USBSTOR_CreatePDO( IN PDEVICE_OBJECT DeviceObject, @@ -1283,9 +1181,10 @@ USBSTOR_CreatePDO( PDEVICE_OBJECT PDO; NTSTATUS Status; PPDO_DEVICE_EXTENSION PDODeviceExtension; - PUFI_INQUIRY_RESPONSE Response; PFDO_DEVICE_EXTENSION FDODeviceExtension; + DPRINT("USBSTOR_CreatePDO: LUN %x\n", LUN); + // // get device extension // @@ -1295,13 +1194,21 @@ USBSTOR_CreatePDO( // // create child device object // - Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO); + Status = IoCreateDevice(DeviceObject->DriverObject, + sizeof(PDO_DEVICE_EXTENSION), + NULL, + FILE_DEVICE_MASS_STORAGE, + FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, + FALSE, + &PDO); + if (!NT_SUCCESS(Status)) { // // failed to create device // - return Status; + DPRINT1("USBSTOR_CreatePDO: Failed to create PDO Status %x\n", Status); + return Status; } // @@ -1327,7 +1234,7 @@ USBSTOR_CreatePDO( // // set device flags // - PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER; + PDO->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; // // device is initialized @@ -1338,35 +1245,17 @@ USBSTOR_CreatePDO( // output device object // FDODeviceExtension->ChildPDO[LUN] = PDO; + DPRINT("USBSTOR_CreatePDO: ChildPDO[%d] %p\n", LUN, PDO); // // send inquiry command by irp // - Status = USBSTOR_SendInquiryIrp(PDO); - ASSERT(Status == STATUS_SUCCESS); + Status = USBSTOR_GetInquiryData(PDO); - // - // check response data - // - Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData; - ASSERT(Response); - - if (Response->DeviceType == 0) + if (NT_SUCCESS(Status) && + !(PDODeviceExtension->InquiryData.DeviceType & FILE_DEVICE_TAPE)) { - // - // check if it is a floppy - // - Status = USBSTOR_SendFormatCapacityIrp(PDO); - - // - // display result - // - DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode); - - // - // failing command is non critical - // - Status = STATUS_SUCCESS; + PDODeviceExtension->IsFloppy = USBSTOR_IsFloppyDevice(PDO); } // @@ -1374,3 +1263,14 @@ USBSTOR_CreatePDO( // return Status; } + +NTSTATUS +NTAPI +USBSTOR_PdoSetPower( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + DPRINT1("USBSTOR_PdoSetPower: UNIMPLEMENTED\n"); + ASSERT(FALSE); + return STATUS_SUCCESS; +} diff --git a/drivers/usb/usbstor_new/queue.c b/drivers/usb/usbstor_new/queue.c index a945ab9..764bf6e 100644 --- a/drivers/usb/usbstor_new/queue.c +++ b/drivers/usb/usbstor_new/queue.c @@ -151,7 +151,7 @@ USBSTOR_QueueAddIrp( BOOLEAN IrpListFreeze; BOOLEAN SrbProcessing; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); - PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + PSCSI_REQUEST_BLOCK Request = IoStack->Parameters.Scsi.Srb; // // get FDO device extension @@ -164,11 +164,6 @@ USBSTOR_QueueAddIrp( ASSERT(FDODeviceExtension->Common.IsFDO); // - // mark irp pending - // - IoMarkIrpPending(Irp); - - // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); @@ -217,15 +212,15 @@ USBSTOR_QueueAddIrp( // if (SrbProcessing) { - ASSERT(FDODeviceExtension->ActiveSrb != NULL); + ASSERT(FDODeviceExtension->CurrentSrb != NULL); OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel); } else { - ASSERT(FDODeviceExtension->ActiveSrb == NULL); + ASSERT(FDODeviceExtension->CurrentSrb == NULL); - FDODeviceExtension->ActiveSrb = Request; + FDODeviceExtension->CurrentSrb = Request; OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo); } @@ -338,7 +333,7 @@ USBSTOR_QueueTerminateRequest( KIRQL OldLevel; PFDO_DEVICE_EXTENSION FDODeviceExtension; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); - PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + PSCSI_REQUEST_BLOCK Request = IoStack->Parameters.Scsi.Srb; // // get FDO device extension @@ -363,19 +358,19 @@ USBSTOR_QueueTerminateRequest( // // check if this was our current active SRB // - if (FDODeviceExtension->ActiveSrb == Request) + if (FDODeviceExtension->CurrentSrb == Request) { // // indicate processing is completed // - FDODeviceExtension->ActiveSrb = NULL; + FDODeviceExtension->CurrentSrb = NULL; } // // Set the event if nothing else is pending // if (FDODeviceExtension->IrpPendingCount == 0 && - FDODeviceExtension->ActiveSrb == NULL) + FDODeviceExtension->CurrentSrb == NULL) { KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE); } @@ -409,7 +404,7 @@ USBSTOR_QueueNextRequest( // // check first if there's already a request pending or the queue is frozen // - if (FDODeviceExtension->ActiveSrb != NULL || + if (FDODeviceExtension->CurrentSrb != NULL || FDODeviceExtension->IrpListFreeze) { // @@ -443,7 +438,7 @@ USBSTOR_QueueNextRequest( // // get srb // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + Request = IoStack->Parameters.Scsi.Srb; // // sanity check @@ -453,7 +448,7 @@ USBSTOR_QueueNextRequest( // // set the active SRB // - FDODeviceExtension->ActiveSrb = Request; + FDODeviceExtension->CurrentSrb = Request; // // start next packet @@ -525,7 +520,7 @@ USBSTOR_QueueRelease( // // get srb // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + Request = IoStack->Parameters.Scsi.Srb; // // start new packet @@ -536,7 +531,6 @@ USBSTOR_QueueRelease( USBSTOR_CancelIo); } - VOID NTAPI USBSTOR_StartIo( @@ -548,6 +542,7 @@ USBSTOR_StartIo( PPDO_DEVICE_EXTENSION PDODeviceExtension; KIRQL OldLevel; BOOLEAN ResetInProgress; + PSCSI_REQUEST_BLOCK Srb; DPRINT("USBSTOR_StartIo\n"); @@ -562,6 +557,16 @@ USBSTOR_StartIo( ASSERT(FDODeviceExtension->Common.IsFDO); // + // get current irp stack location + // + IoStack = IoGetCurrentIrpStackLocation(Irp); + if (IoStack->MajorFunction == IRP_MJ_POWER) + { + KeSetEvent(&FDODeviceExtension->PowerEvent, IO_NO_INCREMENT, FALSE); + return; + } + + // // acquire cancel spinlock // IoAcquireCancelSpinLock(&OldLevel); @@ -629,10 +634,9 @@ USBSTOR_StartIo( // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); - // - // get current irp stack location - // - IoStack = IoGetCurrentIrpStackLocation(Irp); + Srb = IoStack->Parameters.Scsi.Srb; + FDODeviceExtension->CurrentSrb = Srb; + DPRINT("USBSTOR_StartIo: Srb - %p\n", Srb); // // get pdo device extension @@ -652,10 +656,16 @@ USBSTOR_StartIo( // // hard reset is in progress // + Srb->SrbStatus = SRB_STATUS_NO_DEVICE; + Srb->DataTransferLength = 0; + Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; + USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); + USBSTOR_QueueNextRequest(DeviceObject); + return; } diff --git a/drivers/usb/usbstor_new/scsi.c b/drivers/usb/usbstor_new/scsi.c index ee5bfba..ea3c69a 100644 --- a/drivers/usb/usbstor_new/scsi.c +++ b/drivers/usb/usbstor_new/scsi.c @@ -14,937 +14,216 @@ #define NDEBUG #include -NTSTATUS -USBSTOR_BuildCBW( - IN ULONG Tag, - IN ULONG DataTransferLength, - IN UCHAR LUN, - IN UCHAR CommandBlockLength, - IN PUCHAR CommandBlock, - IN OUT PCBW Control) +VOID +DumpCBW( + PUCHAR Block) { - // - // sanity check - // - ASSERT(CommandBlockLength <= 16); - - // - // now initialize CBW - // - Control->Signature = CBW_SIGNATURE; - Control->Tag = Tag; - Control->DataTransferLength = DataTransferLength; - Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00; - Control->LUN = (LUN & MAX_LUN); - Control->CommandBlockLength = CommandBlockLength; - - // - // copy command block - // - RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength); - - // - // done - // - return STATUS_SUCCESS; + DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + Block[0], Block[1], Block[2], Block[3], Block[4], Block[5], Block[6], Block[7], Block[8], Block[9], + Block[10], Block[11], Block[12], Block[13], Block[14], Block[15], Block[16], Block[17], Block[18], Block[19], + Block[20], Block[21], Block[22], Block[23], Block[24], Block[25], Block[26], Block[27], Block[28], Block[29], Block[30]); } -PIRP_CONTEXT -USBSTOR_AllocateIrpContext() +NTSTATUS +NTAPI +USBSTOR_SrbStatusToNtStatus( + IN PSCSI_REQUEST_BLOCK Srb) { - PIRP_CONTEXT Context; + UCHAR SrbStatus; - // - // allocate irp context - // - Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT)); - if (!Context) - { - // - // no memory - // - return NULL; - } + SrbStatus = SRB_STATUS(Srb->SrbStatus); - // - // allocate cbw block - // - Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512); - if (!Context->cbw) - { - // - // no memory - // - FreeItem(Context); - return NULL; - } - - // - // done - // - return Context; - -} + DPRINT("USBSTOR_SrbStatusToNtStatus: Srb - %p, SrbStatus - %x\n", + Srb, + SrbStatus); -BOOLEAN -USBSTOR_IsCSWValid( - PIRP_CONTEXT Context) -{ - // - // sanity checks - // - if (Context->csw->Signature != CSW_SIGNATURE) + switch (SrbStatus) { - DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature); - return FALSE; - } + case SRB_STATUS_DATA_OVERRUN: + return STATUS_BUFFER_OVERFLOW; - if (Context->csw->Tag != (ULONG)Context->csw) - { - DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag); - return FALSE; - } + case SRB_STATUS_BAD_FUNCTION: + case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: + return STATUS_INVALID_DEVICE_REQUEST; - if (Context->csw->Status != 0x00) - { - DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status); - return FALSE; - } - - // - // CSW is valid - // - return TRUE; + case SRB_STATUS_INVALID_LUN: + case SRB_STATUS_INVALID_TARGET_ID: + case SRB_STATUS_NO_HBA: + case SRB_STATUS_NO_DEVICE: + return STATUS_DEVICE_DOES_NOT_EXIST; -} + case SRB_STATUS_TIMEOUT: + return STATUS_IO_TIMEOUT; -NTSTATUS -USBSTOR_QueueWorkItem( - PIRP_CONTEXT Context, - PIRP Irp) -{ - PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData; + case SRB_STATUS_BUS_RESET: + case SRB_STATUS_COMMAND_TIMEOUT: + case SRB_STATUS_SELECTION_TIMEOUT: + return STATUS_DEVICE_NOT_CONNECTED; - // - // Allocate Work Item Data - // - ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG); - if (!ErrorHandlerWorkItemData) - { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; + default: + return STATUS_IO_DEVICE_ERROR; } - - // - // error handling started - // - Context->FDODeviceExtension->SrbErrorHandlingActive = TRUE; - - // - // srb error handling finished - // - Context->FDODeviceExtension->TimerWorkQueueEnabled = FALSE; - - // - // Initialize and queue the work item to handle the error - // - ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, - ErrorHandlerWorkItemRoutine, - ErrorHandlerWorkItemData); - - ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject; - ErrorHandlerWorkItemData->Context = Context; - ErrorHandlerWorkItemData->Irp = Irp; - ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject; - - DPRINT1("Queuing WorkItemROutine\n"); - ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue); - return STATUS_MORE_PROCESSING_REQUIRED; } - -// -// driver verifier -// -IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine; - -NTSTATUS +VOID NTAPI -USBSTOR_CSWCompletionRoutine( - PDEVICE_OBJECT DeviceObject, - PIRP Irp, - PVOID Ctx) +USBSTOR_HandleCDBComplete( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, + IN PIRP Irp, + IN PSCSI_REQUEST_BLOCK Srb) { - PIRP_CONTEXT Context; - PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; - PCDB pCDB; - PREAD_CAPACITY_DATA_EX CapacityDataEx; - PREAD_CAPACITY_DATA CapacityData; - PUFI_CAPACITY_RESPONSE Response; - NTSTATUS Status; + UCHAR OperationCode; + UCHAR SrbStatus; + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; - // - // access context - // - Context = (PIRP_CONTEXT)Ctx; + DPRINT("USBSTOR_HandleCDBComplete: ... \n"); - // - // is there a mdl - // - if (Context->TransferBufferMDL) + InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)( + (ULONG_PTR)FDODeviceExtension->ConfigurationDescriptor + + sizeof(USB_CONFIGURATION_DESCRIPTOR)); + + if (InterfaceDescriptor->bInterfaceSubClass != USB_SUBCLASS_SCSI) { - // - // is there an irp associated - // - if (Context->Irp) + OperationCode = Srb->Cdb[0]; + + if (OperationCode != FDODeviceExtension->CurrentCdb.CDB6GENERIC.OperationCode) { - // - // did we allocate the mdl - // - if (Context->TransferBufferMDL != Context->Irp->MdlAddress) + if (OperationCode == SCSIOP_MODE_SENSE10) { - // - // free mdl - // - IoFreeMdl(Context->TransferBufferMDL); + DPRINT("USBSTOR_HandleCDBComplete: FIXME SCSIOP_MODE_SENSE10\n"); } - } - else - { - // - // free mdl - // - IoFreeMdl(Context->TransferBufferMDL); - } - } - DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status); - - if (!NT_SUCCESS(Irp->IoStatus.Information)) - { - if (Context->ErrorIndex == 0) - { - // - // increment error index - // - Context->ErrorIndex = 1; - - // - // clear stall and resend cbw - // - Status = USBSTOR_QueueWorkItem(Context, Irp); - ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); - return STATUS_MORE_PROCESSING_REQUIRED; + RtlCopyMemory(Srb->Cdb, + &FDODeviceExtension->CurrentCdb, + sizeof(CDB)); } - - // - // perform reset recovery - // - Context->ErrorIndex = 2; - IoFreeIrp(Irp); - Status = USBSTOR_QueueWorkItem(Context, NULL); - ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); - return STATUS_MORE_PROCESSING_REQUIRED; } - if (!USBSTOR_IsCSWValid(Context)) + if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS && + !(Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE)) { - // - // perform reset recovery - // - Context->ErrorIndex = 2; - IoFreeIrp(Irp); - Status = USBSTOR_QueueWorkItem(Context, NULL); - ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); - return STATUS_MORE_PROCESSING_REQUIRED; + Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN; + DPRINT("USBSTOR_HandleCDBComplete: FIXME Queue Freeze\n"); } + SrbStatus = SRB_STATUS(Srb->SrbStatus); - // - // get current stack location - // - IoStack = IoGetCurrentIrpStackLocation(Context->Irp); - - // - // get request block - // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; - ASSERT(Request); - - Status = Irp->IoStatus.Status; - - // - // get SCSI command data block - // - pCDB = (PCDB)Request->Cdb; - Request->SrbStatus = SRB_STATUS_SUCCESS; - - // - // read capacity needs special work - // - if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) + if (SrbStatus != SRB_STATUS_SUCCESS) { - // - // get output buffer - // - Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData; - - // - // store in pdo - // - Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength); - Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress); - - if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX)) - { - // - // get input buffer - // - CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer; - - // - // set result - // - CapacityDataEx->BytesPerBlock = Response->BlockLength; - CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress; - Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX); - } - else - { - // - // get input buffer - // - CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer; - - // - // set result - // - CapacityData->BytesPerBlock = Response->BlockLength; - CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress; - Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA); - } - - // - // free response - // - FreeItem(Context->TransferData); + SrbStatus = USBSTOR_SrbStatusToNtStatus(Srb); + Irp->IoStatus.Status = SrbStatus; } - - // - // free cbw - // - FreeItem(Context->cbw); - - // - // FIXME: check status - // - Context->Irp->IoStatus.Status = Irp->IoStatus.Status; - Context->Irp->IoStatus.Information = Context->TransferDataLength; - - // - // terminate current request - // - USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); - - // - // complete request - // - IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); - - // - // start next request - // - USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); - - // - // free our allocated irp - // - IoFreeIrp(Irp); - - // - // free context - // - FreeItem(Context); - - // - // done - // - return STATUS_MORE_PROCESSING_REQUIRED; } -VOID -USBSTOR_SendCSW( - PIRP_CONTEXT Context, - PIRP Irp) -{ - PIO_STACK_LOCATION IoStack; - - // - // get next irp stack location - // - IoStack = IoGetNextIrpStackLocation(Irp); - - // - // now initialize the urb for sending the csw - // - UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, - sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), - Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, - Context->csw, - NULL, - 512, //FIXME - USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, - NULL); - - // - // initialize stack location - // - IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; - IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb; - IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length; - Irp->IoStatus.Status = STATUS_SUCCESS; - - - // - // setup completion routine - // - IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); - - // - // call driver - // - IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); -} - - -// -// driver verifier -// -IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine; - -NTSTATUS -NTAPI -USBSTOR_DataCompletionRoutine( - PDEVICE_OBJECT DeviceObject, - PIRP Irp, - PVOID Ctx) -{ - PIRP_CONTEXT Context; - NTSTATUS Status; - - - DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status); - - // - // access context - // - Context = (PIRP_CONTEXT)Ctx; - - if (!NT_SUCCESS(Irp->IoStatus.Status)) - { - // - // clear stall and resend cbw - // - Context->ErrorIndex = 1; - Status = USBSTOR_QueueWorkItem(Context, Irp); - ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); - return STATUS_MORE_PROCESSING_REQUIRED; - } - - // - // send csw - // - USBSTOR_SendCSW(Context, Irp); - - // - // cancel completion - // - return STATUS_MORE_PROCESSING_REQUIRED; -} - -// -// driver verifier -// -IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine; - -NTSTATUS +BOOLEAN NTAPI -USBSTOR_CBWCompletionRoutine( - PDEVICE_OBJECT DeviceObject, - PIRP Irp, - PVOID Ctx) +USBSTOR_IsRequestTimeOut( + IN PDEVICE_OBJECT FdoDevice, + IN PIRP Irp, + IN OUT NTSTATUS * OutStatus) { - PIRP_CONTEXT Context; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + KIRQL OldIrql; + PSCSI_REQUEST_BLOCK Srb; + BOOLEAN Result; + BOOLEAN IsTimeOut; PIO_STACK_LOCATION IoStack; - UCHAR Code; - USBD_PIPE_HANDLE PipeHandle; - DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status); + DPRINT("USBSTOR_IsRequestTimeOut: ... \n"); - // - // access context - // - Context = (PIRP_CONTEXT)Ctx; + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + IsTimeOut = FALSE; - // - // get next stack location - // - IoStack = IoGetNextIrpStackLocation(Irp); + KeAcquireSpinLock(&FDODeviceExtension->StorSpinLock, &OldIrql); - // - // is there data to be submitted - // - if (Context->TransferDataLength) - { - // - // get command code - // - Code = Context->cbw->CommandBlock[0]; + FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_TRANSFER_FINISHED; - if (Code == SCSIOP_WRITE) - { - // - // write request use bulk out pipe - // - PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle; - } - else - { - // - // default bulk in pipe - // - PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle; - } + if (FDODeviceExtension->Flags & USBSTOR_FDO_FLAGS_DEVICE_RESETTING) + IsTimeOut = TRUE; - // - // now initialize the urb for sending data - // - UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, - sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), - PipeHandle, - NULL, - Context->TransferBufferMDL, - Context->TransferDataLength, - ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)), - NULL); + KeReleaseSpinLock(&FDODeviceExtension->StorSpinLock, OldIrql); - // - // setup completion routine - // - IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE); - } - else + if (IsTimeOut) { - // - // now initialize the urb for sending the csw - // + Srb = FDODeviceExtension->CurrentSrb; - UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, - sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), - Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, - Context->csw, - NULL, - 512, //FIXME - USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK, - NULL); + DPRINT1("USBSTOR_IsRequestTimeOut: Irp - %p, Srb - %p\n", Irp, Srb); - // - // setup completion routine - // - IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); - } + IoStack = IoGetCurrentIrpStackLocation(Irp); + IoStack->Parameters.Scsi.Srb = Srb; - // - // initialize stack location - // - IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; - IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb; - IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length; - Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Status = STATUS_IO_TIMEOUT; + Irp->IoStatus.Information = 0; - // - // call driver - // - IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); + Srb->SrbStatus = SRB_STATUS_TIMEOUT; - return STATUS_MORE_PROCESSING_REQUIRED; -} + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, Srb); -VOID -DumpCBW( - PUCHAR Block) -{ - DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - Block[0] & 0xFF, Block[1] & 0xFF, Block[2] & 0xFF, Block[3] & 0xFF, Block[4] & 0xFF, Block[5] & 0xFF, Block[6] & 0xFF, Block[7] & 0xFF, Block[8] & 0xFF, Block[9] & 0xFF, - Block[10] & 0xFF, Block[11] & 0xFF, Block[12] & 0xFF, Block[13] & 0xFF, Block[14] & 0xFF, Block[15] & 0xFF, Block[16] & 0xFF, Block[17] & 0xFF, Block[18] & 0xFF, Block[19] & 0xFF, - Block[20] & 0xFF, Block[21] & 0xFF, Block[22] & 0xFF, Block[23] & 0xFF, Block[24] & 0xFF, Block[25] & 0xFF, Block[26] & 0xFF, Block[27] & 0xFF, Block[28] & 0xFF, Block[29] & 0xFF, - Block[30] & 0xFF); + *OutStatus = STATUS_MORE_PROCESSING_REQUIRED; -} - -NTSTATUS -USBSTOR_SendCBW( - PIRP_CONTEXT Context, - PIRP Irp) -{ - PIO_STACK_LOCATION IoStack; - - // - // get next stack location - // - IoStack = IoGetNextIrpStackLocation(Irp); - - // - // initialize stack location - // - IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; - IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb; - IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length; - Irp->IoStatus.Status = STATUS_SUCCESS; - - // - // setup completion routine - // - IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE); - - // - // call driver - // - return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp); -} - -NTSTATUS -USBSTOR_SendRequest( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP OriginalRequest, - IN UCHAR CommandLength, - IN PUCHAR Command, - IN ULONG TransferDataLength, - IN PUCHAR TransferData, - IN ULONG RetryCount) -{ - PIRP_CONTEXT Context; - PPDO_DEVICE_EXTENSION PDODeviceExtension; - PFDO_DEVICE_EXTENSION FDODeviceExtension; - PIRP Irp; - PUCHAR MdlVirtualAddress; + KeSetEvent(&FDODeviceExtension->TimeOutEvent, + IO_NO_INCREMENT, + FALSE); - // - // first allocate irp context - // - Context = USBSTOR_AllocateIrpContext(); - if (!Context) - { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; + Result = TRUE; } - - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - // - // get FDO device extension - // - FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; - - // - // now build the cbw - // - USBSTOR_BuildCBW((ULONG)Context->cbw, - TransferDataLength, - PDODeviceExtension->LUN, - CommandLength, - Command, - Context->cbw); - - DPRINT("CBW %p\n", Context->cbw); - DumpCBW((PUCHAR)Context->cbw); - - // - // now initialize the urb - // - UsbBuildInterruptOrBulkTransferRequest(&Context->Urb, - sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), - FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle, - Context->cbw, - NULL, - sizeof(CBW), - USBD_TRANSFER_DIRECTION_OUT, - NULL); - - // - // initialize rest of context - // - Context->Irp = OriginalRequest; - Context->TransferData = TransferData; - Context->TransferDataLength = TransferDataLength; - Context->FDODeviceExtension = FDODeviceExtension; - Context->PDODeviceExtension = PDODeviceExtension; - Context->RetryCount = RetryCount; - - // - // is there transfer data - // - if (Context->TransferDataLength) - { - // - // check if the original request already does have an mdl associated - // - if (OriginalRequest) - { - if ((OriginalRequest->MdlAddress != NULL) && - (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE)) - { - // - // Sanity check that the Mdl does describe the TransferData for read/write - // - if (CommandLength == UFI_READ_WRITE_CMD_LEN) - { - MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress); - - // - // is there an offset - // - if (MdlVirtualAddress != Context->TransferData) - { - // - // lets build an mdl - // - Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL); - if (!Context->TransferBufferMDL) - { - // - // failed to allocate MDL - // - FreeItem(Context->cbw); - FreeItem(Context); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // - // now build the partial mdl - // - IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength); - } - } - - if (!Context->TransferBufferMDL) - { - // - // I/O paging request - // - Context->TransferBufferMDL = OriginalRequest->MdlAddress; - } - } - else - { - // - // allocate mdl for buffer, buffer must be allocated from NonPagedPool - // - Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); - if (!Context->TransferBufferMDL) - { - // - // failed to allocate MDL - // - FreeItem(Context->cbw); - FreeItem(Context); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // - // build mdl for nonpaged pool - // - MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); - } - } - else - { - // - // allocate mdl for buffer, buffer must be allocated from NonPagedPool - // - Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL); - if (!Context->TransferBufferMDL) - { - // - // failed to allocate MDL - // - FreeItem(Context->cbw); - FreeItem(Context); - return STATUS_INSUFFICIENT_RESOURCES; - } - - // - // build mdl for nonpaged pool - // - MmBuildMdlForNonPagedPool(Context->TransferBufferMDL); - } - } - - // - // now allocate the request - // - Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); - if (!Irp) + else { - FreeItem(Context->cbw); - FreeItem(Context); - return STATUS_INSUFFICIENT_RESOURCES; + FDODeviceExtension->CurrentIrp = NULL; + Result = FALSE; } - if (OriginalRequest) - { - // - // mark orignal irp as pending - // - IoMarkIrpPending(OriginalRequest); - } - - // - // send request - // - USBSTOR_SendCBW(Context, Irp); - - // - // done - // - return STATUS_PENDING; -} - -NTSTATUS -USBSTOR_SendFormatCapacity( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN ULONG RetryCount) -{ - UFI_READ_FORMAT_CAPACITY Cmd; - PPDO_DEVICE_EXTENSION PDODeviceExtension; - PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; - - // - // get current stack location - // - IoStack = IoGetCurrentIrpStackLocation(Irp); - - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; - - // - // get request block - // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; - - // - // initialize inquiry cmd - // - RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY)); - Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY; - Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); - Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8; - Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF; - - // - // now send the request - // - return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount); + return Result; } NTSTATUS -USBSTOR_SendInquiry( - IN PDEVICE_OBJECT DeviceObject, +NTAPI +USBSTOR_IssueBulkOrInterruptRequest( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, IN PIRP Irp, - IN ULONG RetryCount) + IN USBD_PIPE_HANDLE PipeHandle, + IN ULONG TransferFlags, + IN ULONG TransferBufferLength, + IN PVOID TransferBuffer, + IN PMDL TransferBufferMDL, + IN PIO_COMPLETION_ROUTINE CompletionRoutine, + IN PVOID Context) { - UFI_INQUIRY_CMD Cmd; - PPDO_DEVICE_EXTENSION PDODeviceExtension; - PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; - - // - // get current stack location - // - IoStack = IoGetCurrentIrpStackLocation(Irp); + PIO_STACK_LOCATION NextStack; + KIRQL OldIrql; - // - // get request block - // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + DPRINT("USBSTOR_IssueBulkOrInterruptRequest: ... \n"); - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + RtlZeroMemory(&FDODeviceExtension->Urb, + sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER)); - // - // initialize inquiry cmd - // - RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD)); - Cmd.Code = SCSIOP_INQUIRY; - Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); - Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE); + FDODeviceExtension->Urb.Hdr.Length = sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER); + FDODeviceExtension->Urb.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; - // - // sanity check - // - ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE)); + FDODeviceExtension->Urb.PipeHandle = PipeHandle; + FDODeviceExtension->Urb.TransferFlags = TransferFlags; + FDODeviceExtension->Urb.TransferBufferLength = TransferBufferLength; + FDODeviceExtension->Urb.TransferBuffer = TransferBuffer; + FDODeviceExtension->Urb.TransferBufferMDL = TransferBufferMDL; - // - // now send the request - // - return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount); -} + NextStack = IoGetNextIrpStackLocation(Irp); + NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + NextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + NextStack->Parameters.Others.Argument1 = &FDODeviceExtension->Urb; -NTSTATUS -USBSTOR_SendCapacity( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN ULONG RetryCount) -{ - UFI_CAPACITY_CMD Cmd; - PUFI_CAPACITY_RESPONSE Response; - PPDO_DEVICE_EXTENSION PDODeviceExtension; + IoSetCompletionRoutine(Irp, + CompletionRoutine, + Context, + TRUE, + TRUE, + TRUE); - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + KeAcquireSpinLock(&FDODeviceExtension->StorSpinLock, &OldIrql); + FDODeviceExtension->Flags |= USBSTOR_FDO_FLAGS_TRANSFER_FINISHED; + FDODeviceExtension->CurrentIrp = Irp; + KeReleaseSpinLock(&FDODeviceExtension->StorSpinLock, OldIrql); - // - // allocate capacity response - // - Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE); - if (!Response) - { - // - // no memory - // - return STATUS_INSUFFICIENT_RESOURCES; - } - - // - // initialize capacity cmd - // - RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD)); - Cmd.Code = SCSIOP_READ_CAPACITY; - Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); - - // - // send request, response will be freed in completion routine - // - return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount); + return IoCallDriver(FDODeviceExtension->LowerDeviceObject, Irp); } NTSTATUS @@ -983,7 +262,7 @@ USBSTOR_SendModeSense( // // get request block // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + Request = IoStack->Parameters.Scsi.Srb; RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength); Request->SrbStatus = SRB_STATUS_SUCCESS; @@ -1115,194 +394,531 @@ USBSTOR_SendModeSense( *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue; // - // copy buffer + // copy buffer + // + RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength); + + // + // free item + // + FreeItem(OutControl); + + // + // free response + // + FreeItem(Response); + + // + // done + // + return Status; +#endif +} + +NTSTATUS +NTAPI +USBSTOR_CswCompletion( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID CompletionContext) +{ + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PSCSI_REQUEST_BLOCK Srb; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + NTSTATUS Status; + PSCSI_REQUEST_BLOCK CurrentSrb; + PDEVICE_OBJECT FdoDevice; + //KIRQL OldIrql; + PIO_STACK_LOCATION IoStack; + + DPRINT("USBSTOR_CswCompletion: ... \n"); + + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); + Srb = IoStack->Parameters.Scsi.Srb; + + FdoDevice = PDODeviceExtension->LowerDeviceObject; + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FdoDevice->DeviceExtension; + + if (USBSTOR_IsRequestTimeOut(FdoDevice, Irp, &Status)) + { + return Status; + } + + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + DPRINT("USBSTOR_CswCompletion: Irp->IoStatus.Status - %p\n", + Irp->IoStatus.Status); + + if (USBD_STATUS(FDODeviceExtension->Urb.Hdr.Status) == + USBD_STATUS(USBD_STATUS_STALL_PID)) + { + if (FDODeviceExtension->RetryCount < 2) + { + ++FDODeviceExtension->RetryCount; + USBSTOR_BulkQueueResetPipe(FDODeviceExtension); + + return STATUS_MORE_PROCESSING_REQUIRED; + } + } + else + { + DPRINT("USBSTOR_CswCompletion: Urb.Hdr.Status - %p\n", + FDODeviceExtension->Urb.Hdr.Status); + + goto ResetRecovery; + } + } + + if (FDODeviceExtension->BulkBuffer.Cbw.Flags == CSW_STATUS_COMMAND_PASSED) + { + if (Srb != FDODeviceExtension->CurrentSrb) + { + FDODeviceExtension->CurrentSrb->SenseInfoBufferLength = Srb->DataTransferLength; + Srb = FDODeviceExtension->CurrentSrb; + IoStack->Parameters.Scsi.Srb = Srb; + Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; + } + + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = Srb->DataTransferLength; + + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, Srb); + } + else + { + if (FDODeviceExtension->BulkBuffer.Cbw.Flags == CSW_STATUS_COMMAND_FAILED && + Srb == FDODeviceExtension->CurrentSrb) + { + Srb->SrbStatus = SRB_STATUS_ERROR; + Srb->ScsiStatus = 2; + + Srb->DataTransferLength = 0; + + if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) && + Srb->SenseInfoBufferLength && + Srb->SenseInfoBuffer) + { + USBSTOR_IssueRequestSense(FDODeviceExtension, Irp); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + Status = STATUS_IO_DEVICE_ERROR; + Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; + Irp->IoStatus.Information = 0; + + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, Srb); + } + else + { + goto ResetRecovery; + } + } + + // + // terminate request // - RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength); + USBSTOR_QueueTerminateRequest(FdoDevice, Irp); // - // free item + // queue next request // - FreeItem(OutControl); + USBSTOR_QueueNextRequest(FdoDevice); - // - // free response - // - FreeItem(Response); + if (Status) + DPRINT("USBSTOR_CswCompletion: Status -%p\n", Status); - // - // done - // return Status; -#endif + +ResetRecovery: + + CurrentSrb = FDODeviceExtension->CurrentSrb; + IoStack->Parameters.Scsi.Srb = CurrentSrb; + Status = STATUS_IO_DEVICE_ERROR; + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; + CurrentSrb->SrbStatus = SRB_STATUS_BUS_RESET; + + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, CurrentSrb); + USBSTOR_QueueResetDevice(FDODeviceExtension, PDODeviceExtension); + + return Status; +} + +NTSTATUS +NTAPI +USBSTOR_CswTransfer( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, + IN PIRP Irp) +{ + PVOID TransferBuffer; + PUSBD_PIPE_INFORMATION PipeIn; + ULONG TransferBufferLength; + ULONG TransferFlags; + UCHAR PipeIndex; + + DPRINT("USBSTOR_CswTransfer: ... \n"); + + TransferBuffer = &FDODeviceExtension->BulkBuffer.Csw; + + PipeIndex = FDODeviceExtension->BulkInPipeIndex; + PipeIn = &FDODeviceExtension->InterfaceInformation->Pipes[PipeIndex]; + + if (PipeIn->MaximumPacketSize == 512) + { + TransferFlags = USBD_SHORT_TRANSFER_OK; + TransferBufferLength = 512; + } + else + { + TransferFlags = 0; + TransferBufferLength = sizeof(CSW); + } + + return USBSTOR_IssueBulkOrInterruptRequest(FDODeviceExtension, + Irp, + PipeIn->PipeHandle, + TransferFlags, + TransferBufferLength, + TransferBuffer, + NULL,//TransferBufferMDL + USBSTOR_CswCompletion, + NULL);//Context } NTSTATUS -USBSTOR_SendReadWrite( +NTAPI +USBSTOR_DataCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, - IN ULONG RetryCount) + IN PVOID Context) { - UFI_READ_WRITE_CMD Cmd; PPDO_DEVICE_EXTENSION PDODeviceExtension; - PCDB pCDB; - ULONG BlockCount, Temp; + PSCSI_REQUEST_BLOCK Srb; + PDEVICE_OBJECT FdoDevice; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + PSCSI_REQUEST_BLOCK CurrentSrb; PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; + NTSTATUS Status; + + DPRINT("USBSTOR_DataCompletion: ... \n"); + + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + FdoDevice = PDODeviceExtension->LowerDeviceObject; + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FdoDevice->DeviceExtension; - // - // get current stack location - // IoStack = IoGetCurrentIrpStackLocation(Irp); + Srb = IoStack->Parameters.Scsi.Srb; - // - // get request block - // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + if (Srb == FDODeviceExtension->CurrentSrb && + FDODeviceExtension->Urb.TransferBufferMDL != Irp->MdlAddress) + { + IoFreeMdl(FDODeviceExtension->Urb.TransferBufferMDL); + } - // - // get SCSI command data block - // - pCDB = (PCDB)Request->Cdb; + if (USBSTOR_IsRequestTimeOut(FdoDevice, Irp, &Status)) + { + return Status; + } - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + if (NT_SUCCESS(Irp->IoStatus.Status)) + { + if (FDODeviceExtension->Urb.TransferBufferLength < Srb->DataTransferLength) + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; + else + Srb->SrbStatus = SRB_STATUS_SUCCESS; - // - // informal debug print - // - DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength); + Srb->DataTransferLength = FDODeviceExtension->Urb.TransferBufferLength; - // - // sanity check - // - ASSERT(PDODeviceExtension->BlockLength); + USBSTOR_CswTransfer(FDODeviceExtension, Irp); - // - // block count - // - BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength; + return STATUS_MORE_PROCESSING_REQUIRED; + } - // - // initialize read cmd - // - RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD)); - Cmd.Code = pCDB->AsByte[0]; - Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); - Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb; - Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb; - Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0; - Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1; - Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2; - Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3; + if (USBD_STATUS(FDODeviceExtension->Urb.Hdr.Status) == + USBD_STATUS(USBD_STATUS_STALL_PID)) + { + ++FDODeviceExtension->RetryCount; - // - // sanity check - // - Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1); - ASSERT(Temp == BlockCount); + Srb->DataTransferLength = FDODeviceExtension->Urb.TransferBufferLength; + Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN; - DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength); + USBSTOR_BulkQueueResetPipe(FDODeviceExtension); - // - // send request - // - return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + CurrentSrb = FDODeviceExtension->CurrentSrb; + IoStack->Parameters.Scsi.Srb = CurrentSrb; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; + + CurrentSrb->SrbStatus = SRB_STATUS_BUS_RESET; + + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, CurrentSrb); + USBSTOR_QueueResetDevice(FDODeviceExtension, PDODeviceExtension); + + return STATUS_IO_DEVICE_ERROR; } NTSTATUS -USBSTOR_SendTestUnit( - IN PDEVICE_OBJECT DeviceObject, - IN OUT PIRP Irp, - IN ULONG RetryCount) +NTAPI +USBSTOR_DataTransfer( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, + IN PIRP Irp) { - UFI_TEST_UNIT_CMD Cmd; - PPDO_DEVICE_EXTENSION PDODeviceExtension; + PSCSI_REQUEST_BLOCK Srb; + PUSBD_PIPE_INFORMATION Pipe; + PMDL Mdl; + ULONG TransferFlags; + PVOID TransferBuffer; PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; + NTSTATUS Status; + UCHAR PipeIndex; + + DPRINT("USBSTOR_DataTransfer: ... \n"); - // - // get current stack location - // IoStack = IoGetCurrentIrpStackLocation(Irp); + Srb = IoStack->Parameters.Scsi.Srb; - // - // get request block - // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + if ((Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == SRB_FLAGS_DATA_IN) + { + PipeIndex = FDODeviceExtension->BulkInPipeIndex; + TransferFlags = USBD_SHORT_TRANSFER_OK; + } + else if ((Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == SRB_FLAGS_DATA_OUT) + { + PipeIndex = FDODeviceExtension->BulkOutPipeIndex; + TransferFlags = 0; + } + else + { + return STATUS_INVALID_PARAMETER; + } - // - // no transfer length - // - ASSERT(Request->DataTransferLength == 0); + Mdl = NULL; + TransferBuffer = NULL; - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + Pipe = &FDODeviceExtension->InterfaceInformation->Pipes[PipeIndex]; - // - // initialize test unit cmd - // - RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD)); - Cmd.Code = SCSIOP_TEST_UNIT_READY; - Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN); + if (Srb == FDODeviceExtension->CurrentSrb) + { + if (MmGetMdlVirtualAddress(Irp->MdlAddress) == Srb->DataBuffer) + { + Mdl = Irp->MdlAddress; + } + else + { + Mdl = IoAllocateMdl(Srb->DataBuffer, + Srb->DataTransferLength, + FALSE, + FALSE, + NULL); - // - // send the request - // - return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount); + if (Mdl) + { + IoBuildPartialMdl(Irp->MdlAddress, + Mdl, + Srb->DataBuffer, + Srb->DataTransferLength); + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (!Mdl) + { + DPRINT("USBSTOR_DataTransfer: Mdl - %p\n", Mdl); + return Status; + } + } + else + { + TransferBuffer = Srb->DataBuffer; + + if (!Srb->DataBuffer) + { + DPRINT("USBSTOR_DataTransfer: Srb->DataBuffer == NULL!!!\n"); + return STATUS_INVALID_PARAMETER; + } + } + + USBSTOR_IssueBulkOrInterruptRequest(FDODeviceExtension, + Irp, + Pipe->PipeHandle, + TransferFlags, + Srb->DataTransferLength, + TransferBuffer, + Mdl, + USBSTOR_DataCompletion, + NULL);//Context + + return STATUS_SUCCESS; } NTSTATUS -USBSTOR_SendUnknownRequest( +NTAPI +USBSTOR_CbwCompletion( IN PDEVICE_OBJECT DeviceObject, - IN OUT PIRP Irp, - IN ULONG RetryCount) + IN PIRP Irp, + IN PVOID Context) { - PPDO_DEVICE_EXTENSION PDODeviceExtension; PIO_STACK_LOCATION IoStack; - PSCSI_REQUEST_BLOCK Request; - UFI_UNKNOWN_CMD Cmd; + PDEVICE_OBJECT FdoDevice; + PSCSI_REQUEST_BLOCK CurrentSrb; + PFDO_DEVICE_EXTENSION FDODeviceExtension; + NTSTATUS Status; + PSCSI_REQUEST_BLOCK Srb; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + + DPRINT("USBSTOR_CbwCompletion: ... \n"); + + PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + FdoDevice = PDODeviceExtension->LowerDeviceObject; + FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FdoDevice->DeviceExtension; - // - // get current stack location - // IoStack = IoGetCurrentIrpStackLocation(Irp); + Srb = IoStack->Parameters.Scsi.Srb; - // - // get request block - // - Request = IoStack->Parameters.Others.Argument1; + if (USBSTOR_IsRequestTimeOut(FdoDevice, Irp, &Status)) + { + return Status; + } - // - // get PDO device extension - // - PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + if (!NT_SUCCESS(Irp->IoStatus.Status)) + { + CurrentSrb = FDODeviceExtension->CurrentSrb; + IoStack->Parameters.Scsi.Srb = CurrentSrb; - // - // check that we're sending to the right LUN - // - ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN)); + Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; + Irp->IoStatus.Information = 0; - // - // sanity check - // - ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD)); + CurrentSrb->SrbStatus = SRB_STATUS_BUS_RESET; - // - // initialize test unit cmd - // - RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength); + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, CurrentSrb); + USBSTOR_QueueResetDevice(FDODeviceExtension, PDODeviceExtension); - // - // send the request - // - return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount); + return STATUS_IO_DEVICE_ERROR; + } + + if (Irp->MdlAddress || Srb != FDODeviceExtension->CurrentSrb) + { + Status = USBSTOR_DataTransfer(FDODeviceExtension, Irp); + + if (!NT_SUCCESS(Status)) + { + CurrentSrb = FDODeviceExtension->CurrentSrb; + IoStack->Parameters.Scsi.Srb = CurrentSrb; + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + + CurrentSrb->SrbStatus = SRB_STATUS_ERROR; + + USBSTOR_HandleCDBComplete(FDODeviceExtension, Irp, CurrentSrb); + USBSTOR_QueueResetDevice(FDODeviceExtension, PDODeviceExtension); + + return Status; + } + } + else + { + Srb->SrbStatus = SRB_STATUS_SUCCESS; + USBSTOR_CswTransfer(FDODeviceExtension, Irp); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +NTAPI +USBSTOR_CbwTransfer( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PPDO_DEVICE_EXTENSION PDODeviceExtension; + PSCSI_REQUEST_BLOCK Srb; + PCBW Cbw; + PUSBD_PIPE_INFORMATION Pipe; + UCHAR PipeIndex; + + DPRINT("USBSTOR_CbwTransfer: ... \n"); + + FDODeviceExtension->RetryCount = 0; + + IoStack = IoGetCurrentIrpStackLocation(Irp); + PDODeviceExtension = IoStack->DeviceObject->DeviceExtension; + Srb = IoStack->Parameters.Scsi.Srb; + + Cbw = &FDODeviceExtension->BulkBuffer.Cbw; + + Cbw->Signature = CBW_SIGNATURE; + Cbw->Tag = (ULONG)Irp; + Cbw->DataTransferLength = Srb->DataTransferLength; + Cbw->Flags = ((UCHAR)Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) << 1; + Cbw->LUN = PDODeviceExtension->LUN; + Cbw->CommandBlockLength = Srb->CdbLength; + + RtlCopyMemory(FDODeviceExtension->BulkBuffer.Cbw.CommandBlock, + Srb->Cdb, + sizeof(CDB)); + + PipeIndex = FDODeviceExtension->BulkOutPipeIndex; + Pipe = &FDODeviceExtension->InterfaceInformation->Pipes[PipeIndex]; + + return USBSTOR_IssueBulkOrInterruptRequest(FDODeviceExtension, + Irp, + Pipe->PipeHandle, + 0,//TransferFlags ?USBD_TRANSFER_DIRECTION_OUT? FIXME + sizeof(CBW), + &FDODeviceExtension->BulkBuffer.Cbw, + NULL,//TransferBufferMDL + USBSTOR_CbwCompletion, + NULL);//Context } NTSTATUS +NTAPI +USBSTOR_IssueRequestSense( + IN PFDO_DEVICE_EXTENSION FDODeviceExtension, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStack; + PSCSI_REQUEST_BLOCK CurrentSrb; + PSCSI_REQUEST_BLOCK SenseSrb; + + DPRINT("USBSTOR_IssueRequestSense: \n"); + + CurrentSrb = FDODeviceExtension->CurrentSrb; + SenseSrb = &FDODeviceExtension->SenseSrb; + IoStack = IoGetCurrentIrpStackLocation(Irp); + IoStack->Parameters.Scsi.Srb = SenseSrb; + + RtlZeroMemory(SenseSrb, sizeof(FDODeviceExtension->SenseSrb)); + + SenseSrb->Function = SRB_FUNCTION_EXECUTE_SCSI; + SenseSrb->Length = sizeof(FDODeviceExtension->SenseSrb); + SenseSrb->CdbLength = 12; + + SenseSrb->SrbFlags = SRB_FLAGS_DATA_IN | + SRB_FLAGS_NO_QUEUE_FREEZE | + SRB_FLAGS_DISABLE_AUTOSENSE; + + SenseSrb->DataTransferLength = CurrentSrb->SenseInfoBufferLength; + SenseSrb->DataBuffer = CurrentSrb->SenseInfoBuffer; + + SenseSrb->Cdb[0] = SCSIOP_REQUEST_SENSE; + SenseSrb->Cdb[4] = CurrentSrb->SenseInfoBufferLength; + + return USBSTOR_CbwTransfer(FDODeviceExtension, Irp); +} + +VOID USBSTOR_HandleExecuteSCSI( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, @@ -1313,11 +929,13 @@ USBSTOR_HandleExecuteSCSI( PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request; PPDO_DEVICE_EXTENSION PDODeviceExtension; + PFDO_DEVICE_EXTENSION FDODeviceExtension; // - // get PDO device extension + // get device extensions // PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + FDODeviceExtension = PDODeviceExtension->LowerDeviceObject->DeviceExtension; // // sanity check @@ -1332,7 +950,7 @@ USBSTOR_HandleExecuteSCSI( // // get request block // - Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; + Request = IoStack->Parameters.Scsi.Srb; // // get SCSI command data block @@ -1341,18 +959,11 @@ USBSTOR_HandleExecuteSCSI( DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]); - if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) - { - // - // sanity checks - // - ASSERT(Request->DataBuffer); - DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength); - Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount); - } - else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) + if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) { + //FIXME CheckModeSenseDataProtect + DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength); ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength); ASSERT(Request->DataBuffer); @@ -1361,6 +972,30 @@ USBSTOR_HandleExecuteSCSI( // send mode sense command // Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount); + return; + } + + if (FDODeviceExtension->DriverFlags == USBSTOR_DRIVER_FLAGS_BULKONLY) + { + Status = USBSTOR_CbwTransfer(FDODeviceExtension, Irp); + DPRINT("USBSTOR_HandleExecuteSCSI: Status - %08X\n", Status); + return; + } + + DPRINT1("USBSTOR_HandleExecuteSCSI: Not BulkOnly. UNIMPLEMENTED. FIXME. \n"); + + ASSERT(FALSE); + +#if 0 // Old code + if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) + { + // + // sanity checks + // + ASSERT(Request->DataBuffer); + + DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength); + Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount); } else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY) { @@ -1407,7 +1042,7 @@ USBSTOR_HandleExecuteSCSI( // USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject); - return STATUS_SUCCESS; + return;// STATUS_SUCCESS; } else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY) { @@ -1418,6 +1053,15 @@ USBSTOR_HandleExecuteSCSI( // Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount); } + else if (pCDB->CDB6INQUIRY.OperationCode == SCSIOP_REQUEST_SENSE) + { + DPRINT("SCSIOP_REQUEST_SENSE\n"); + + // + // send test unit command + // + Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount); + } else { // Unknown request. Simply forward @@ -1425,5 +1069,6 @@ USBSTOR_HandleExecuteSCSI( Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount); } - return Status; + DPRINT("USBSTOR_HandleExecuteSCSI: Status - %08X\n", Status); +#endif } diff --git a/drivers/usb/usbstor_new/usbstor.c b/drivers/usb/usbstor_new/usbstor.c index b13969e..a287b14 100644 --- a/drivers/usb/usbstor_new/usbstor.c +++ b/drivers/usb/usbstor_new/usbstor.c @@ -30,7 +30,13 @@ USBSTOR_AddDevice( // // lets create the device // - Status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_EXTENSION), 0, FILE_DEVICE_BUS_EXTENDER, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); + Status = IoCreateDevice(DriverObject, + sizeof(FDO_DEVICE_EXTENSION), + NULL, + FILE_DEVICE_BUS_EXTENDER, + FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, + FALSE, + &DeviceObject); // // check for success @@ -60,10 +66,25 @@ USBSTOR_AddDevice( DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject; DeviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); + DeviceExtension->SystemState = PowerSystemWorking; + DeviceExtension->DeviceState = PowerDeviceD0; + + //FIXME RemoveLock + + KeInitializeSpinLock(&DeviceExtension->StorSpinLock); + + KeInitializeEvent(&DeviceExtension->TimeOutEvent, + SynchronizationEvent, + FALSE); + + KeInitializeEvent(&DeviceExtension->PowerEvent, + SynchronizationEvent, + FALSE); + // // init timer // - IoInitializeTimer(DeviceObject, USBSTOR_TimerRoutine, (PVOID)DeviceExtension); + IoInitializeTimer(DeviceObject, USBSTOR_TimerRoutine, NULL); // // did attaching fail @@ -81,7 +102,7 @@ USBSTOR_AddDevice( // // set device flags // - DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE; + DeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; // // device is initialized @@ -214,23 +235,47 @@ USBSTOR_DispatchPower( PIRP Irp) { PFDO_DEVICE_EXTENSION DeviceExtension; + PIO_STACK_LOCATION IoStack; + NTSTATUS Status; // get common device extension DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; + IoStack = IoGetCurrentIrpStackLocation(Irp); if (DeviceExtension->Common.IsFDO) { - PoStartNextPowerIrp(Irp); - IoSkipCurrentIrpStackLocation(Irp); - return PoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + if (IoStack->MinorFunction == IRP_MN_SET_POWER) + { + Status = USBSTOR_FdoSetPower(DeviceObject, Irp); + } + else + { + PoStartNextPowerIrp(Irp); + IoSkipCurrentIrpStackLocation(Irp); + Status = PoCallDriver(DeviceExtension->LowerDeviceObject, Irp); + } } else { + if (IoStack->MinorFunction == IRP_MN_SET_POWER) + { + Status = USBSTOR_PdoSetPower(DeviceObject, Irp); + } + else if (IoStack->MinorFunction == IRP_MN_QUERY_POWER) + { + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + { + Status = Irp->IoStatus.Status; + } + PoStartNextPowerIrp(Irp); - Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; } + + return Status; } diff --git a/drivers/usb/usbstor_new/usbstor.h b/drivers/usb/usbstor_new/usbstor.h index f477e9a..25fe129 100644 --- a/drivers/usb/usbstor_new/usbstor.h +++ b/drivers/usb/usbstor_new/usbstor.h @@ -8,7 +8,65 @@ #include #define USB_STOR_TAG 'sbsu' -#define USB_MAXCHILDREN (16) +#define USB_MAXCHILDREN (15) + +/* + * Ported from linux. + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ + +/* Storage class code */ + +#define USB_CLASS_MASS_STORAGE 0x08 + +/* Storage subclass codes */ + +#define USB_SUBCLASS_RBC 0x01 /* Typically, flash devices */ +#define USB_SUBCLASS_8020 0x02 /* CD-ROM */ +#define USB_SUBCLASS_QIC 0x03 /* QIC-157 Tapes */ +#define USB_SUBCLASS_UFI 0x04 /* Floppy */ +#define USB_SUBCLASS_8070 0x05 /* Removable media */ +#define USB_SUBCLASS_SCSI 0x06 /* Transparent */ +#define USB_SUBCLASS_LOCKABLE 0x07 /* Password-protected */ + +#define USB_SUBCLASS_ISD200 0xF0 /* ISD200 ATA */ +#define USB_SUBCLASS_CYP_ATACB 0xF1 /* Cypress ATACB */ +#define USB_SUBCLASS_VENDOR 0xFF /* Use vendor specific */ + +/* Storage protocol codes */ + +#define USB_PROTOCOL_CBI 0x00 /* Control/Bulk/Interrupt */ +#define USB_PROTOCOL_CB 0x01 /* Control/Bulk w/o interrupt */ +#define USB_PROTOCOL_BULK 0x50 /* bulk only */ +#define USB_PROTOCOL_UAS 0x62 /* USB Attached SCSI */ +#define USB_PROTOCOL_USBAT 0x80 /* SCM-ATAPI bridge */ +#define USB_PROTOCOL_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ +#define USB_PROTOCOL_SDDR55 0x82 /* SDDR-55 (made up) */ + +#define USB_PROTOCOL_DPCM_USB 0xF0 /* Combination CB/SDDR09 */ +#define USB_PROTOCOL_FREECOM 0xF1 /* Freecom */ +#define USB_PROTOCOL_DATAFAB 0xF2 /* Datafab chipsets */ +#define USB_PROTOCOL_JUMPSHOT 0xF3 /* Lexar Jumpshot */ +#define USB_PROTOCOL_ALAUDA 0xF4 /* Alauda chipsets */ +#define USB_PROTOCOL_KARMA 0xF5 /* Rio Karma */ +#define USB_PROTOCOL_VENDOR 0xFF /* Use vendor specific */ + +/* Corresponding constants from scsi.h - Inquiry defines, DeviceType field. */ + +#define USBSTOR_SCSI_DEVICE_TYPE_DIRECT 0x00 /* disks */ +#define USBSTOR_SCSI_DEVICE_TYPE_SEQUENTIAL 0x01 /* tapes */ +#define USBSTOR_SCSI_DEVICE_TYPE_PRINTER 0x02 /* printers */ +#define USBSTOR_SCSI_DEVICE_TYPE_PROCESSOR 0x03 /* scanners, printers, etc */ +#define USBSTOR_SCSI_DEVICE_TYPE_WORM 0x04 /* worms */ +#define USBSTOR_SCSI_DEVICE_TYPE_CDROM 0x05 /* cdroms */ +#define USBSTOR_SCSI_DEVICE_TYPE_SCANNER 0x06 /* scanners */ +#define USBSTOR_SCSI_DEVICE_TYPE_OPTICAL 0x07 /* optical disks */ +#define USBSTOR_SCSI_DEVICE_TYPE_MEDIA_CHANGER 0x08 /* jukebox */ +#define USBSTOR_SCSI_DEVICE_TYPE_UNKNOWN 0x1F + +#define USBSTOR_DEFAULT_MAX_TRANSFER_LENGTH 0x10000 #define HTONS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) #define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) @@ -27,12 +85,84 @@ #define USB_RECOVERABLE_ERRORS (USBD_STATUS_STALL_PID | USBD_STATUS_DEV_NOT_RESPONDING \ | USBD_STATUS_ENDPOINT_HALTED | USBD_STATUS_NO_BANDWIDTH) +// +// UFI INQUIRY command response +// +typedef struct +{ + UCHAR DeviceType; // device type + UCHAR RMB; // removable media bit + UCHAR Version; // contains version 0x00 + UCHAR Format; // response format + UCHAR Length; // additional length + UCHAR Reserved[3]; // reserved + UCHAR Vendor[8]; // vendor identification string + UCHAR Product[16]; // product identification string + UCHAR Revision[4]; // product revision code +} UFI_INQUIRY_RESPONSE, *PUFI_INQUIRY_RESPONSE; + +C_ASSERT(sizeof(UFI_INQUIRY_RESPONSE) == 36); + +#include + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 + +typedef struct +{ + ULONG Signature; // CBW signature + ULONG Tag; // CBW Tag of operation + ULONG DataTransferLength; // data transfer length + UCHAR Flags; // CBW Flags endpoint direction + UCHAR LUN; // lun unit + UCHAR CommandBlockLength; // Command block length + UCHAR CommandBlock[16]; +} CBW, *PCBW; + +C_ASSERT(sizeof(CBW) == 31); + +#define CSW_STATUS_COMMAND_PASSED 0x00 +#define CSW_STATUS_COMMAND_FAILED 0x01 +#define CSW_STATUS_PHASE_ERROR 0x02 + +typedef struct +{ + ULONG Signature; // CSW signature + ULONG Tag; // CSW tag + ULONG DataResidue; // CSW data transfer diff + UCHAR Status; // CSW status +} CSW, *PCSW; + +typedef union _USBSTOR_BULK_ONLY_BUFFER +{ + struct + { + CBW Cbw; + UCHAR Pad1[512 - sizeof(CBW)]; + }; + struct + { + CSW Csw; + UCHAR Pad2[512 - sizeof(CSW)]; + }; +} USBSTOR_BULK_ONLY_BUFFER, *PUSBSTOR_BULK_ONLY_BUFFER; + +C_ASSERT(sizeof(USBSTOR_BULK_ONLY_BUFFER) == 512); + typedef struct __COMMON_DEVICE_EXTENSION__ { BOOLEAN IsFDO; }USBSTOR_COMMON_DEVICE_EXTENSION, *PUSBSTOR_COMMON_DEVICE_EXTENSION; +#define USBSTOR_FDO_FLAGS_TRANSFER_FINISHED 0x00000002 +#define USBSTOR_FDO_FLAGS_NEED_SENSE_REQUEST 0x00000004 +#define USBSTOR_FDO_FLAGS_DEVICE_RESETTING 0x00000008 +#define USBSTOR_FDO_FLAGS_DEVICE_ERROR 0x00000010 + +#define USBSTOR_DRIVER_FLAGS_BULKONLY 0x00000001 +#define USBSTOR_DRIVER_FLAGS_UNKNOWN 0x00000003 + typedef struct { USBSTOR_COMMON_DEVICE_EXTENSION Common; // common device extension @@ -49,18 +179,34 @@ typedef struct UCHAR BulkInPipeIndex; // bulk in pipe index UCHAR BulkOutPipeIndex; // bulk out pipe index UCHAR MaxLUN; // max lun for device - PDEVICE_OBJECT ChildPDO[16]; // max 16 child pdo devices + PDEVICE_OBJECT ChildPDO[USB_MAXCHILDREN]; // max 15 child pdo devices KSPIN_LOCK IrpListLock; // irp list lock LIST_ENTRY IrpListHead; // irp list head BOOLEAN IrpListFreeze; // if true the irp list is freezed BOOLEAN ResetInProgress; // if hard reset is in progress ULONG IrpPendingCount; // count of irp pending - PSCSI_REQUEST_BLOCK ActiveSrb; // stores the current active SRB + PSCSI_REQUEST_BLOCK CurrentSrb; // stores the current active SRB KEVENT NoPendingRequests; // set if no pending or in progress requests PSCSI_REQUEST_BLOCK LastTimerActiveSrb; // last timer tick active srb ULONG SrbErrorHandlingActive; // error handling of srb is activated ULONG TimerWorkQueueEnabled; // timer work queue enabled ULONG InstanceCount; // pdo instance count + PIRP CurrentIrp; + struct _URB_BULK_OR_INTERRUPT_TRANSFER Urb; + SCSI_REQUEST_BLOCK SenseSrb; + CDB CurrentCdb; + ULONG SrbTimeOutValue; + ULONG RetryCount; + USBSTOR_BULK_ONLY_BUFFER BulkBuffer; // Transfer Buffer CBW/CSW + PIO_WORKITEM ResetDeviceWorkItem; + ULONG Flags; + ULONG DriverFlags; + KSPIN_LOCK StorSpinLock; + KEVENT TimeOutEvent; + SYSTEM_POWER_STATE SystemState; + DEVICE_POWER_STATE DeviceState; + PIRP CurrentPowerIrp; + KEVENT PowerEvent; }FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION; typedef struct @@ -68,7 +214,7 @@ typedef struct USBSTOR_COMMON_DEVICE_EXTENSION Common; PDEVICE_OBJECT LowerDeviceObject; // points to FDO UCHAR LUN; // lun id - PVOID InquiryData; // USB SCSI inquiry data + UFI_INQUIRY_RESPONSE InquiryData; // USB SCSI inquiry data PUCHAR FormatData; // USB SCSI Read Format Capacity Data UCHAR Claimed; // indicating if it has been claimed by upper driver ULONG BlockLength; // length of block @@ -85,34 +231,8 @@ typedef struct #define USB_BULK_GET_MAX_LUN 0xFE #define USB_BULK_RESET_DEVICE 0xFF -#include -typedef struct -{ - ULONG Signature; // CBW signature - ULONG Tag; // CBW Tag of operation - ULONG DataTransferLength; // data transfer length - UCHAR Flags; // CBW Flags endpoint direction - UCHAR LUN; // lun unit - UCHAR CommandBlockLength; // Command block length - UCHAR CommandBlock[16]; -}CBW, *PCBW; - -C_ASSERT(sizeof(CBW) == 31); - - -#define CBW_SIGNATURE 0x43425355 -#define CSW_SIGNATURE 0x53425355 - #define MAX_LUN 0xF -typedef struct -{ - ULONG Signature; // CSW signature - ULONG Tag; // CSW tag - ULONG DataResidue; // CSW data transfer diff - UCHAR Status; // CSW status -}CSW, *PCSW; - //-------------------------------------------------------------------------------------------------------------------------------------------- // // UFI INQUIRY command @@ -131,24 +251,6 @@ C_ASSERT(sizeof(UFI_INQUIRY_CMD) == 12); #define UFI_INQUIRY_CMD_LEN 0x6 -// -// UFI INQUIRY command response -// -typedef struct -{ - UCHAR DeviceType; // device type - UCHAR RMB; // removable media bit - UCHAR Version; // contains version 0x00 - UCHAR Format; // response format - UCHAR Length; // additional length - UCHAR Reserved[3]; // reserved - UCHAR Vendor[8]; // vendor identification string - UCHAR Product[16]; // product identification string - UCHAR Revision[4]; // product revision code -}UFI_INQUIRY_RESPONSE, *PUFI_INQUIRY_RESPONSE; - -C_ASSERT(sizeof(UFI_INQUIRY_RESPONSE) == 36); - //-------------------------------------------------------------------------------------------------------------------------------------------- // // UFI read cmd @@ -348,6 +450,12 @@ USBSTOR_FdoHandlePnp( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp); +NTSTATUS +NTAPI +USBSTOR_FdoSetPower( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + //--------------------------------------------------------------------- // // pdo.c routines @@ -362,6 +470,12 @@ USBSTOR_CreatePDO( IN PDEVICE_OBJECT DeviceObject, IN UCHAR LUN); +NTSTATUS +NTAPI +USBSTOR_PdoSetPower( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + //--------------------------------------------------------------------- // // misc.c routines @@ -405,7 +519,7 @@ USBSTOR_SyncForwardIrpCompletionRoutine( PVOID Context); NTSTATUS -USBSTOR_ResetDevice( +USBSTOR_BulkResetDevice( IN PDEVICE_OBJECT DeviceObject, IN PFDO_DEVICE_EXTENSION DeviceExtension); @@ -437,7 +551,7 @@ USBSTOR_GetPipeHandles( // // scsi.c routines // -NTSTATUS +VOID USBSTOR_HandleExecuteSCSI( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, @@ -445,22 +559,16 @@ USBSTOR_HandleExecuteSCSI( NTSTATUS NTAPI -USBSTOR_CSWCompletionRoutine( - PDEVICE_OBJECT DeviceObject, - PIRP Irp, - PVOID Ctx); - -NTSTATUS -USBSTOR_SendCBW( - PIRP_CONTEXT Context, +USBSTOR_CswTransfer( + PFDO_DEVICE_EXTENSION FDODeviceExtension, PIRP Irp); -VOID -USBSTOR_SendCSW( - PIRP_CONTEXT Context, +NTSTATUS +NTAPI +USBSTOR_IssueRequestSense( + PFDO_DEVICE_EXTENSION FDODeviceExtension, PIRP Irp); - //--------------------------------------------------------------------- // // disk.c routines @@ -509,18 +617,6 @@ USBSTOR_QueueInitialize( PFDO_DEVICE_EXTENSION FDODeviceExtension); VOID -NTAPI -ErrorHandlerWorkItemRoutine( - PVOID Context); - -VOID -NTAPI -ResetHandlerWorkItemRoutine( - PVOID Context); - - - -VOID USBSTOR_QueueNextRequest( IN PDEVICE_OBJECT DeviceObject); @@ -531,12 +627,6 @@ USBSTOR_QueueTerminateRequest( /* error.c */ NTSTATUS -USBSTOR_GetEndpointStatus( - IN PDEVICE_OBJECT DeviceObject, - IN UCHAR bEndpointAddress, - OUT PUSHORT Value); - -NTSTATUS USBSTOR_ResetPipeWithHandle( IN PDEVICE_OBJECT DeviceObject, IN USBD_PIPE_HANDLE PipeHandle); @@ -545,6 +635,17 @@ VOID NTAPI USBSTOR_TimerRoutine( PDEVICE_OBJECT DeviceObject, - PVOID Context); + PVOID Context); + +VOID +NTAPI +USBSTOR_BulkQueueResetPipe( + PFDO_DEVICE_EXTENSION FDODeviceExtension); + +VOID +NTAPI +USBSTOR_QueueResetDevice( + PFDO_DEVICE_EXTENSION FDODeviceExtension, + PPDO_DEVICE_EXTENSION PDODeviceExtension); #endif /* _USBSTOR_H_ */ diff --git a/drivers/usb/usbuhci_new/CMakeLists.txt b/drivers/usb/usbuhci_new/CMakeLists.txt new file mode 100644 index 0000000..b46c724 --- /dev/null +++ b/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 usbd hal ntoskrnl) +add_pch(usbuhci usbuhci.h SOURCE) +add_cd_file(TARGET usbuhci DESTINATION reactos/system32/drivers NO_CAB FOR all) diff --git a/drivers/usb/usbuhci_new/dbg_uhci.h b/drivers/usb/usbuhci_new/dbg_uhci.h new file mode 100644 index 0000000..50c03ca --- /dev/null +++ b/drivers/usb/usbuhci_new/dbg_uhci.h @@ -0,0 +1,49 @@ +#ifndef DBG_UHCI_H__ +#define DBG_UHCI_H__ + +#if DBG + + #ifndef NDEBUG_UHCI_TRACE + #define DPRINT_UHCI(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_UHCI __noop + #else + #define DPRINT_UHCI(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #endif + #endif + + #ifndef NDEBUG_UHCI_IMPLEMENT + + #define DPRINT_IMPL(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_IMPL __noop + #else + #define DPRINT_IMPL(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #endif + + #endif + + +#else /* not DBG */ + + #if defined(_MSC_VER) + #define DPRINT_UHCI __noop + #define DPRINT_IMPL __noop + #else + #define DPRINT_UHCI(...) do {if(0) {DbgPrint(__VA_ARGS__);}} while(0) + #define DPRINT_IMPL(...) do { if(0) { DbgPrint(__VA_ARGS__); } } while(0) + #endif /* _MSC_VER */ + +#endif /* not DBG */ + +#endif /* DBG_UHCI_H__ */ diff --git a/drivers/usb/usbuhci_new/guid.c b/drivers/usb/usbuhci_new/guid.c new file mode 100644 index 0000000..50a6036 --- /dev/null +++ b/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/drivers/usb/usbuhci_new/hardware.h b/drivers/usb/usbuhci_new/hardware.h new file mode 100644 index 0000000..4d3d67b --- /dev/null +++ b/drivers/usb/usbuhci_new/hardware.h @@ -0,0 +1,218 @@ +#define UHCI_FRAME_LIST_MAX_ENTRIES 1024 // Number of frames in Frame List +#define UHCI_NUM_ROOT_HUB_PORTS 2 + +/* UHCI HC I/O Registers offset (PUSHORT) */ +#define UHCI_USBCMD 0 // USB Command R/W +#define UHCI_USBSTS 1 // USB Status R/WC +#define UHCI_USBINTR 2 // USB Interrupt Enable R/W +#define UHCI_FRNUM 3 // Frame Number R/W WORD writeable only +#define UHCI_FRBASEADD 4 // Frame List Base Address R/W // 32 bit +#define UHCI_SOFMOD 6 // Start Of Frame Modify R/W // 8 bit +#define UHCI_PORTSC1 8 // Port 1 Status/Control R/WC WORD writeable only +#define UHCI_PORTSC2 9 // Port 2 Status/Control R/WC WORD writeable only + +/* PCI Legacy Support */ +#define PCI_LEGSUP 0xC0 // Legacy Support register offset. R/WC +#define PCI_LEGSUP_USBPIRQDEN 0x2000 +#define PCI_LEGSUP_CLEAR_SMI 0x8F00 + +/* LEGSUP Legacy support register (PCI Configuration - Function 2) */ +typedef union _UHCI_PCI_LEGSUP { + struct { + USHORT Smi60Read : 1; // (60REN) Trap/SMI On 60h Read Enable. R/W. + USHORT Smi60Write : 1; // (60WEN) Trap/SMI On 60h Write Enable. R/W. + USHORT Smi64Read : 1; // (64REN) Trap/SMI On 64h Read Enable. R/W. + USHORT Smi64Write : 1; // (64WEN) Trap/SMI On 64h Write Enable. R/W. + USHORT SmiIrq : 1; // (USBSMIEN) Trap/SMI ON IRQ Enable. R/W. + USHORT A20Gate : 1; // (A20PTEN) A20Gate Pass Through Enable. R/W. + USHORT PassThroughStatus : 1; // (PSS) Pass Through Status. RO. + USHORT SmiEndPassThrough : 1; // (SMIEPTE) SMI At End Of Pass Through Enable. R/W. + USHORT TrapBy60ReadStatus : 1; // (TBY60R) Trap By 60h Read Status. R/WC. + USHORT TrapBy60WriteStatus : 1; // (TBY60W) Trap By 60h Write Status. R/WC. + USHORT TrapBy64ReadStatus : 1; // (TBY64R) Trap By 64h Read Status. R/WC. + USHORT TrapBy64WriteStatus : 1; // (TBY64W) Trap By 64h Write Status. R/WC. + USHORT UsbIrqStatus : 1; // (USBIRQS) USB IRQ Status. RO. + USHORT UsbPIRQ : 1; // (USBPIRQDEN) USB PIRQ Enable. R/W. + USHORT Reserved : 1; + USHORT EndA20GateStatus : 1; // (A20PTS) End OF A20GATE Pass Through Status. R/WC. + }; + USHORT AsUSHORT; +} UHCI_PCI_LEGSUP; + +C_ASSERT(sizeof(UHCI_PCI_LEGSUP) == sizeof(USHORT)); + +/* USBCMD 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; + +C_ASSERT(sizeof(UHCI_USB_COMMAND) == sizeof(USHORT)); + +/* USBSTS Status register */ +#define UHCI_USB_STATUS_MASK 0x3F + +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; + +C_ASSERT(sizeof(UHCI_USB_STATUS) == sizeof(USHORT)); + +/* USBINTR 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; + +C_ASSERT(sizeof(UHCI_INTERRUPT_ENABLE) == sizeof(USHORT)); + +/* FRNUM Frame Number register */ +#define UHCI_FRNUM_FRAME_MASK 0x7FF +#define UHCI_FRNUM_INDEX_MASK 0x3FF +#define UHCI_FRNUM_OVERFLOW_LIST 0x400 + +/* PORTSC(1|2) 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; + +C_ASSERT(sizeof(UHCI_PORT_STATUS_CONTROL) == sizeof(USHORT)); + +typedef struct _UHCI_HW_REGISTERS { + UHCI_USB_COMMAND HcCommand; // R/W + UHCI_USB_STATUS HcStatus; // R/WC + UHCI_INTERRUPT_ENABLE HcInterruptEnable; // R/W + USHORT FrameNumber; // R/W WORD writeable only + ULONG FrameAddress; // R/W + UCHAR SOF_Modify; // R/W + UCHAR Reserved[3]; + UHCI_PORT_STATUS_CONTROL PortControl[UHCI_NUM_ROOT_HUB_PORTS]; // R/WC WORD writeable only +} UHCI_HW_REGISTERS, *PUHCI_HW_REGISTERS; + +/* Transfer Descriptor (TD) */ +#define UHCI_TD_STS_ACTIVE (1 << 7) +#define UHCI_TD_STS_STALLED (1 << 6) +#define UHCI_TD_STS_DATA_BUFFER_ERROR (1 << 5) +#define UHCI_TD_STS_BABBLE_DETECTED (1 << 4) +#define UHCI_TD_STS_NAK_RECEIVED (1 << 3) +#define UHCI_TD_STS_TIMEOUT_CRC_ERROR (1 << 2) +#define UHCI_TD_STS_BITSTUFF_ERROR (1 << 1) +//#define UHCI_TD_STS_Reserved (1 << 0) + +#define UHCI_TD_VALID_LENGTH 0x4FF +#define UHCI_TD_LENGTH_INVALID 0x7FE +#define UHCI_TD_LENGTH_NULL 0x7FF + +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; + +C_ASSERT(sizeof(UHCI_CONTROL_STATUS) == sizeof(ULONG)); + +#define UHCI_TD_PID_IN 0x69 +#define UHCI_TD_PID_OUT 0xE1 +#define UHCI_TD_PID_SETUP 0x2D + +#define UHCI_TD_PID_DATA0 0 +#define UHCI_TD_PID_DATA1 1 + +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; + +C_ASSERT(sizeof(UHCI_TD_TOKEN) == sizeof(ULONG)); + +#define UHCI_TD_LINK_PTR_VALID (0 << 0) +#define UHCI_TD_LINK_PTR_TERMINATE (1 << 0) +#define UHCI_TD_LINK_PTR_TD (0 << 1) +#define UHCI_TD_LINK_PTR_QH (1 << 1) +#define UHCI_TD_LINK_PTR_BREADTH_FIRST (0 << 2) +#define UHCI_TD_LINK_PTR_DEPTH_FIRST (1 << 2) +#define UHCI_TD_LINK_POINTER_MASK 0xFFFFFFF0 + +typedef struct _UHCI_TD { // Transfer Descriptors always aligned on 16-byte boundaries + ULONG NextElement; + UHCI_CONTROL_STATUS ControlStatus; + UHCI_TD_TOKEN Token; + ULONG Buffer; +} UHCI_TD, *PUHCI_TD; + +C_ASSERT(sizeof(UHCI_TD) == 16); + +/* Queue Header (QH) */ +#define UHCI_QH_HEAD_LINK_PTR_VALID (0 << 0) +#define UHCI_QH_HEAD_LINK_PTR_TERMINATE (1 << 0) +#define UHCI_QH_HEAD_LINK_PTR_TD (0 << 1) +#define UHCI_QH_HEAD_LINK_PTR_QH (1 << 1) +#define UHCI_QH_HEAD_LINK_POINTER_MASK 0xFFFFFFF0 + +#define UHCI_QH_ELEMENT_LINK_PTR_VALID (0 << 0) +#define UHCI_QH_ELEMENT_LINK_PTR_TERMINATE (1 << 0) +#define UHCI_QH_ELEMENT_LINK_PTR_TD (0 << 1) +#define UHCI_QH_ELEMENT_LINK_PTR_QH (1 << 1) +#define UHCI_QH_ELEMENT_LINK_POINTER_MASK 0xFFFFFFF0 + +typedef struct _UHCI_QH { // Queue Heads must be aligned on a 16-byte boundary + ULONG NextQH; + ULONG NextElement; +} UHCI_QH, *PUHCI_QH; + +C_ASSERT(sizeof(UHCI_QH) == 8); diff --git a/drivers/usb/usbuhci_new/roothub.c b/drivers/usb/usbuhci_new/roothub.c new file mode 100644 index 0000000..8a3bac1 --- /dev/null +++ b/drivers/usb/usbuhci_new/roothub.c @@ -0,0 +1,472 @@ +#include "usbuhci.h" + +#define NDEBUG +#include + +VOID +NTAPI +UhciRHGetRootHubData(IN PVOID uhciExtension, + IN PVOID rootHubData) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUSBPORT_ROOT_HUB_DATA RootHubData = rootHubData; + USBPORT_HUB_11_CHARACTERISTICS HubCharacteristics; + + DPRINT("UhciRHGetRootHubData: ...\n"); + + HubCharacteristics.AsUSHORT = 0; + HubCharacteristics.PowerControlMode = 1; + HubCharacteristics.NoPowerSwitching = 1; + HubCharacteristics.OverCurrentProtectionMode = 1; + + if (UhciExtension->HcFlavor != UHCI_Piix4) + HubCharacteristics.NoOverCurrentProtection = 1; + + RootHubData->NumberOfPorts = UHCI_NUM_ROOT_HUB_PORTS; + RootHubData->HubCharacteristics.Usb11HubCharacteristics = HubCharacteristics; + RootHubData->PowerOnToPowerGood = 1; + RootHubData->HubControlCurrent = 0; +} + +MPSTATUS +NTAPI +UhciRHGetStatus(IN PVOID uhciExtension, + IN PUSHORT Status) +{ + DPRINT("UhciRHGetStatus: ...\n"); + *Status = UHCI_RH_STATUS_SUCCESS; + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHGetPortStatus(IN PVOID uhciExtension, + IN USHORT Port, + IN PUSB_PORT_STATUS_AND_CHANGE PortStatus) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + ULONG PortBit; + USB_20_PORT_STATUS portStatus; + USB_20_PORT_CHANGE portChange; + + //DPRINT("UhciRHGetPortStatus: ...\n"); + + ASSERT(Port); + + BaseRegister = UhciExtension->BaseRegister; + PortControlRegister = &BaseRegister->PortControl[Port-1].AsUSHORT; + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + portStatus.AsUshort16 = 0; + portChange.AsUshort16 = 0; + + portStatus.CurrentConnectStatus = PortControl.CurrentConnectStatus; + portStatus.PortEnabledDisabled = PortControl.PortEnabledDisabled; + + if (PortControl.Suspend == 1 && + PortControl.PortEnabledDisabled == 1) + { + portStatus.Suspend = 1; + } + else + { + portStatus.Suspend = 0; + } + + //if (UhciExtension->HcFlavor == UHCI_Piix4) // check will work after supporting HcFlavor in usbport. + if (TRUE) + { + portStatus.OverCurrent = PortControl.Reserved2 & 1; + portStatus.PortPower = (~PortControl.Reserved2 & 1); + portChange.OverCurrentIndicatorChange = (PortControl.Reserved2 & 2) != 0; + } + else + { + portStatus.OverCurrent = 0; + portStatus.PortPower = 1; + portChange.OverCurrentIndicatorChange = 0; + } + + portStatus.HighSpeedDeviceAttached = 0; + + portStatus.Reset = PortControl.PortReset; + portStatus.LowSpeedDeviceAttached = PortControl.LowSpeedDevice; + portChange.ConnectStatusChange = PortControl.ConnectStatusChange; + + PortBit = 1 << (Port - 1); + + if (UhciExtension->ResetPortMask & PortBit) + { + portChange.ConnectStatusChange = 0; + portChange.PortEnableDisableChange = 0; + } + else + { + portChange.PortEnableDisableChange = PortControl.PortEnableDisableChange; + } + + if (UhciExtension->SuspendChangePortMask & PortBit) + portChange.SuspendChange = 1; + + if (UhciExtension->ResetChangePortMask & PortBit) + portChange.ResetChange = 1; + + PortStatus->PortStatus.Usb20PortStatus = portStatus; + PortStatus->PortChange.Usb20PortChange = portChange; + + //DPRINT("UhciRHGetPortStatus: PortControl.AsUSHORT[%x] - %X, PortStatus - %X\n", + // Port, + // PortControl.AsUSHORT, + // PortStatus->AsUlong32); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHGetHubStatus(IN PVOID uhciExtension, + IN PUSB_HUB_STATUS_AND_CHANGE HubStatus) +{ + //DPRINT("UhciRHGetHubStatus: ...\n"); + HubStatus->AsUlong32 = 0; + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +UhciRHPortResetComplete(IN PVOID uhciExtension, + IN PVOID pPort) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + ULONG ix; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + USHORT Port; + + DPRINT("UhciRHPortResetComplete: ...\n"); + + BaseRegister = UhciExtension->BaseRegister; + + Port = *(PUSHORT)pPort; + ASSERT(Port); + + PortControlRegister = &BaseRegister->PortControl[Port - 1].AsUSHORT; + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + PortControl.ConnectStatusChange = 0; + PortControl.PortEnableDisableChange = 0; + PortControl.PortReset = 0; + + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + + while (UhciHardwarePresent(UhciExtension)) + { + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + if (PortControl.PortReset == 0) + break; + } + + for (ix = 0; ix < 10; ++ix) + { + KeStallExecutionProcessor(50); + + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + if (PortControl.PortEnabledDisabled == 1) + break; + + PortControl.PortEnabledDisabled = 1; + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + } + + PortControl.ConnectStatusChange = 1; + PortControl.PortEnableDisableChange = 1; + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + + if (UhciExtension->HcFlavor == UHCI_VIA && + UhciExtension->HcFlavor == UHCI_VIA_x01 && + UhciExtension->HcFlavor == UHCI_VIA_x02 && + UhciExtension->HcFlavor == UHCI_VIA_x03 && + UhciExtension->HcFlavor == UHCI_VIA_x04) + { + DPRINT("UhciRHPortResetComplete: Via chip. FIXME\n"); + DbgBreakPoint(); + return; + } + + UhciExtension->ResetChangePortMask |= (1 << (Port - 1)); + UhciExtension->ResetPortMask &= ~(1 << (Port - 1)); + + RegPacket.UsbPortInvalidateRootHub(UhciExtension); +} + +VOID +NTAPI +UhciRHSetFeaturePortResetWorker(IN PUHCI_EXTENSION UhciExtension, + IN PUSHORT pPort) +{ + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + USHORT Port; + + DPRINT("UhciRHSetFeaturePortResetWorker: ...\n"); + + BaseRegister = UhciExtension->BaseRegister; + + Port = *(PUSHORT)pPort; + ASSERT(Port); + + PortControlRegister = &BaseRegister->PortControl[Port - 1].AsUSHORT; + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + PortControl.ConnectStatusChange = 0; + PortControl.PortEnableDisableChange = 0; + PortControl.PortReset = 1; + + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + + RegPacket.UsbPortRequestAsyncCallback(UhciExtension, + 10, // TimerValue + pPort, + sizeof(pPort), + UhciRHPortResetComplete); +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortReset(IN PVOID uhciExtension, + IN USHORT Port) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + ULONG ResetPortMask; + ULONG PortBit; + + DPRINT("UhciRHSetFeaturePortReset: ...\n"); + + ASSERT(Port); + + ResetPortMask = UhciExtension->ResetPortMask; + PortBit = 1 << (Port - 1); + + if (ResetPortMask & PortBit) + return MP_STATUS_FAILURE; + + UhciExtension->ResetPortMask = ResetPortMask | PortBit; + + if (UhciExtension->HcFlavor == UHCI_VIA && + UhciExtension->HcFlavor == UHCI_VIA_x01 && + UhciExtension->HcFlavor == UHCI_VIA_x02 && + UhciExtension->HcFlavor == UHCI_VIA_x03 && + UhciExtension->HcFlavor == UHCI_VIA_x04) + { + DPRINT1("UhciRHSetFeaturePortReset: Via chip. FIXME\n"); + return MP_STATUS_SUCCESS; + } + + UhciRHSetFeaturePortResetWorker(UhciExtension, &Port); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortPower(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHSetFeaturePortPower: ...\n"); + ASSERT(Port); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHPortEnable(IN PVOID uhciExtension, + IN USHORT Port, + IN BOOLEAN IsSet) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + + DPRINT("UhciRHPortEnable: ...\n"); + + ASSERT(Port); + + BaseRegister = UhciExtension->BaseRegister; + PortControlRegister = &BaseRegister->PortControl[Port-1].AsUSHORT; + + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + PortControl.ConnectStatusChange = 0; + PortControl.PortEnableDisableChange = 0; + + if (IsSet) + PortControl.PortEnabledDisabled = 1; + else + PortControl.PortEnabledDisabled = 0; + + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortEnable(IN PVOID uhciExtension, + IN USHORT Port) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + DPRINT("UhciRHSetFeaturePortEnable: ...\n"); + ASSERT(Port); + return UhciRHPortEnable(UhciExtension, Port, TRUE); +} + +MPSTATUS +NTAPI +UhciRHSetFeaturePortSuspend(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHSetFeaturePortSuspend: UNIMPLEMENTED. FIXME\n"); + ASSERT(Port); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortEnable(IN PVOID uhciExtension, + IN USHORT Port) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + DPRINT("UhciRHClearFeaturePortEnable: ...\n"); + ASSERT(Port); + return UhciRHPortEnable(UhciExtension, Port, FALSE); +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortPower(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortPower: UNIMPLEMENTED. FIXME\n"); + ASSERT(Port); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortSuspend(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortSuspend: UNIMPLEMENTED. FIXME\n"); + ASSERT(Port); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortEnableChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + + DPRINT("UhciRHClearFeaturePortEnableChange: ...\n"); + + ASSERT(Port); + + BaseRegister = UhciExtension->BaseRegister; + PortControlRegister = (PUSHORT)&BaseRegister->PortControl[Port - 1]; + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + PortControl.ConnectStatusChange = 0; + PortControl.PortEnableDisableChange = 1; + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortConnectChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + + DPRINT("UhciRHClearFeaturePortConnectChange: Port - %04X\n", Port); + + ASSERT(Port); + + BaseRegister = UhciExtension->BaseRegister; + PortControlRegister = (PUSHORT)&BaseRegister->PortControl[Port - 1]; + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + if (PortControl.ConnectStatusChange == 1) + { + /* WC (Write Clear) bits */ + PortControl.PortEnableDisableChange = 0; + PortControl.ConnectStatusChange = 1; + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + } + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortResetChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + DPRINT("UhciRHClearFeaturePortResetChange: ...\n"); + ASSERT(Port); + UhciExtension->ResetChangePortMask &= ~(1 << (Port - 1)); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortSuspendChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortSuspendChange: UNIMPLEMENTED. FIXME\n"); + ASSERT(Port); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciRHClearFeaturePortOvercurrentChange(IN PVOID uhciExtension, + IN USHORT Port) +{ + DPRINT("UhciRHClearFeaturePortOvercurrentChange: UNIMPLEMENTED. FIXME\n"); + ASSERT(Port); + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +UhciRHDisableIrq(IN PVOID uhciExtension) +{ + /* Do nothing */ + return; +} + +VOID +NTAPI +UhciRHEnableIrq(IN PVOID uhciExtension) +{ + /* Do nothing */ + return; +} diff --git a/drivers/usb/usbuhci_new/usbuhci.c b/drivers/usb/usbuhci_new/usbuhci.c new file mode 100644 index 0000000..2bd1422 --- /dev/null +++ b/drivers/usb/usbuhci_new/usbuhci.c @@ -0,0 +1,2791 @@ +#include "usbuhci.h" + +#define NDEBUG +#include + +#define NDEBUG_UHCI_TRACE +#define NDEBUG_UHCI_IMPLEMENT +#include "dbg_uhci.h" + +USBPORT_REGISTRATION_PACKET RegPacket; + +VOID +NTAPI +UhciDumpHcdQH(PUHCI_HCD_QH QH) +{ + DPRINT("QH - %p\n", QH); + DPRINT("NextQH - %p\n", QH->HwQH.NextQH); + DPRINT("NextElement - %p\n", QH->HwQH.NextElement); + + DPRINT("PhysicalAddress - %p\n", QH->PhysicalAddress); + DPRINT("QhFlags - %X\n", QH->QhFlags); + DPRINT("NextHcdQH - %X\n", QH->NextHcdQH); + DPRINT("PrevHcdQH - %X\n", QH->PrevHcdQH); + DPRINT("UhciEndpoint - %X\n", QH->UhciEndpoint); +} + +VOID +NTAPI +UhciDumpHcdTD(PUHCI_HCD_TD TD) +{ + DPRINT("TD - %p\n", TD); + DPRINT("NextElement - %p\n", TD->HwTD.NextElement); + DPRINT("ControlStatus - %08X\n", TD->HwTD.ControlStatus.AsULONG); + DPRINT("Token - %p\n", TD->HwTD.Token.AsULONG); +if (TD->HwTD.Buffer) + DPRINT("Buffer - %p\n", TD->HwTD.Buffer); + +if (TD->SetupPacket.bmRequestType.B) + DPRINT("bmRequestType - %02X\n", TD->SetupPacket.bmRequestType.B); +if (TD->SetupPacket.bRequest) + DPRINT("bRequest - %02X\n", TD->SetupPacket.bRequest); +if (TD->SetupPacket.wValue.W) + DPRINT("wValue - %04X\n", TD->SetupPacket.wValue.W); +if (TD->SetupPacket.wIndex.W) + DPRINT("wIndex - %04X\n", TD->SetupPacket.wIndex.W); +if (TD->SetupPacket.wLength) + DPRINT("wLength - %04X\n", TD->SetupPacket.wLength); + + DPRINT("PhysicalAddress - %p\n", TD->PhysicalAddress); + DPRINT("Flags - %X\n", TD->Flags); + DPRINT("NextHcdTD - %p\n", TD->NextHcdTD); + DPRINT("UhciTransfer - %p\n", TD->UhciTransfer); +} + +VOID +NTAPI +UhciFixDataToggle(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUHCI_HCD_TD TD, + IN BOOL DataToggle) +{ + DPRINT_UHCI("UhciFixDataToggle: UhciExtension - %p, UhciEndpoint - %p, DataToggle - %X\n", + UhciExtension, + UhciEndpoint, + DataToggle); + + while (TD) + { + TD->HwTD.Token.DataToggle = !TD->HwTD.Token.DataToggle; + DataToggle = !DataToggle; + + TD = TD->NextHcdTD; + } + + UhciEndpoint->DataToggle = DataToggle; +} + +VOID +NTAPI +UhciCleanupFrameListEntry(IN PUHCI_EXTENSION UhciExtension, + IN ULONG Index) +{ + PUHCI_HC_RESOURCES UhciResources; + ULONG PhysicalAddress; + ULONG HeadIdx; + + UhciResources = UhciExtension->HcResourcesVA; + + if (Index == 0) + { + PhysicalAddress = UhciExtension->StaticTD->PhysicalAddress; + + UhciResources->FrameList[0] = PhysicalAddress | + UHCI_FRAME_LIST_POINTER_TD; + } + else + { + HeadIdx = (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms) + + (Index & (ENDPOINT_INTERRUPT_32ms - 1)); + + PhysicalAddress = UhciExtension->IntQH[HeadIdx]->PhysicalAddress; + + UhciResources->FrameList[Index] = PhysicalAddress | + UHCI_FRAME_LIST_POINTER_QH; + } +} + +VOID +NTAPI +UhciCleanupFrameList(IN PUHCI_EXTENSION UhciExtension, + IN BOOLEAN IsAllEntries) +{ + ULONG NewFrameNumber; + ULONG OldFrameNumber; + ULONG ix; + + DPRINT_UHCI("UhciCleanupFrameList: [%p] All - %x\n", + UhciExtension, IsAllEntries); + + // FIXME: using UhciExtension->LockFrameList after supporting ISOs. + + NewFrameNumber = UhciGet32BitFrameNumber(UhciExtension); + OldFrameNumber = UhciExtension->FrameNumber; + + if ((NewFrameNumber - OldFrameNumber) < UHCI_FRAME_LIST_MAX_ENTRIES && + IsAllEntries == FALSE) + { + for (ix = OldFrameNumber & UHCI_FRAME_LIST_INDEX_MASK; + ix != (NewFrameNumber & UHCI_FRAME_LIST_INDEX_MASK); + ix = (ix + 1) & UHCI_FRAME_LIST_INDEX_MASK) + { + UhciCleanupFrameListEntry(UhciExtension, ix); + } + } + else + { + for (ix = 0; ix < UHCI_FRAME_LIST_MAX_ENTRIES; ++ix) + { + UhciCleanupFrameListEntry(UhciExtension, ix); + } + } + + UhciExtension->FrameNumber = NewFrameNumber; +} + +VOID +NTAPI +UhciUpdateCounter(IN PUHCI_EXTENSION UhciExtension) +{ + ULONG FrameNumber; + + FrameNumber = READ_PORT_USHORT(&UhciExtension->BaseRegister->FrameNumber); + FrameNumber &= UHCI_FRNUM_FRAME_MASK; + + if ((FrameNumber ^ UhciExtension->FrameHighPart) & UHCI_FRNUM_OVERFLOW_LIST) + { + UhciExtension->FrameHighPart += UHCI_FRAME_LIST_MAX_ENTRIES; + + DPRINT_UHCI("UhciUpdateCounter: UhciExtension->FrameHighPart - %lX\n", + UhciExtension->FrameHighPart); + } +} + +VOID +NTAPI +UhciSetNextQH(IN PUHCI_HCD_QH QH, + IN PUHCI_HCD_QH NextQH) +{ + DPRINT_UHCI("UhciSetNextQH: QH - %p, NextQH - %p\n", QH, NextQH); + + QH->HwQH.NextQH = NextQH->PhysicalAddress | UHCI_QH_HEAD_LINK_PTR_QH; + QH->NextHcdQH = NextQH; + + NextQH->PrevHcdQH = QH; + NextQH->QhFlags |= UHCI_HCD_QH_FLAG_ACTIVE; +} + +MPSTATUS +NTAPI +UhciOpenEndpoint(IN PVOID uhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PVOID uhciEndpoint) +{ + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + ULONG TransferType; + ULONG_PTR BufferVA; + ULONG BufferPA; + ULONG ix; + ULONG TdCount; + PUHCI_HCD_TD TD; + SIZE_T BufferLength; + PUHCI_HCD_QH QH; + + RtlCopyMemory(&UhciEndpoint->EndpointProperties, + EndpointProperties, + sizeof(UhciEndpoint->EndpointProperties)); + + InitializeListHead(&UhciEndpoint->ListTDs); + + UhciEndpoint->EndpointLock = 0; + UhciEndpoint->DataToggle = UHCI_TD_PID_DATA0; + UhciEndpoint->Flags = 0; + + TransferType = EndpointProperties->TransferType; + + DPRINT("UhciOpenEndpoint: UhciEndpoint - %p, TransferType - %x\n", + UhciEndpoint, + TransferType); + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + UhciEndpoint->Flags |= UHCI_ENDPOINT_FLAG_CONTROL_OR_ISO; + } + + BufferVA = EndpointProperties->BufferVA; + BufferPA = EndpointProperties->BufferPA; + + BufferLength = EndpointProperties->BufferLength; + + /* For Isochronous transfers not used QHs (only TDs) */ + if (EndpointProperties->TransferType != USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + /* Initialize HCD Queue Head */ + UhciEndpoint->QH = (PUHCI_HCD_QH)BufferVA; + + QH = UhciEndpoint->QH; + + QH->HwQH.NextElement |= UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + QH->PhysicalAddress = BufferPA; + + QH->NextHcdQH = QH; + QH->PrevHcdQH = QH; + QH->UhciEndpoint = UhciEndpoint; + + BufferVA += sizeof(UHCI_HCD_QH); + BufferPA += sizeof(UHCI_HCD_QH); + + BufferLength -= sizeof(UHCI_HCD_QH); + } + + /* Initialize HCD Transfer Descriptors */ + TdCount = BufferLength / sizeof(UHCI_HCD_TD); + UhciEndpoint->MaxTDs = TdCount; + + UhciEndpoint->FirstTD = (PUHCI_HCD_TD)BufferVA; + UhciEndpoint->AllocatedTDs = 0; + + RtlZeroMemory(UhciEndpoint->FirstTD, TdCount * sizeof(UHCI_HCD_TD)); + + for (ix = 0; ix < UhciEndpoint->MaxTDs; ix++) + { + TD = &UhciEndpoint->FirstTD[ix]; + TD->PhysicalAddress = BufferPA; + BufferPA += sizeof(UHCI_HCD_TD); + } + + UhciEndpoint->TailTD = NULL; + UhciEndpoint->HeadTD = NULL; + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciReopenEndpoint(IN PVOID uhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PVOID uhciEndpoint) +{ + DPRINT_IMPL("Uhci: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +UhciQueryEndpointRequirements(IN PVOID uhciExtension, + IN PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties, + IN PUSBPORT_ENDPOINT_REQUIREMENTS EndpointRequirements) +{ + ULONG TransferType; + ULONG TdCount; + + DPRINT("UhciQueryEndpointRequirements: ... \n"); + + TransferType = EndpointProperties->TransferType; + + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_ISOCHRONOUS: + DPRINT("UhciQueryEndpointRequirements: IsoTransfer\n"); + TdCount = 2 * UHCI_MAX_ISO_TD_COUNT; + + EndpointRequirements->HeaderBufferSize = 0 + // Iso queue is have not Queue Heads + TdCount * sizeof(UHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = UHCI_MAX_ISO_TRANSFER_SIZE; + break; + + case USBPORT_TRANSFER_TYPE_CONTROL: + DPRINT("UhciQueryEndpointRequirements: ControlTransfer\n"); + TdCount = EndpointProperties->MaxTransferSize / + EndpointProperties->TotalMaxPacketSize; + + TdCount += 2; // First + Last TDs + + EndpointRequirements->HeaderBufferSize = sizeof(UHCI_HCD_QH) + + TdCount * sizeof(UHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = EndpointProperties->MaxTransferSize; + break; + + case USBPORT_TRANSFER_TYPE_BULK: + DPRINT("UhciQueryEndpointRequirements: BulkTransfer\n"); + TdCount = 2 * UHCI_MAX_BULK_TRANSFER_SIZE / + EndpointProperties->TotalMaxPacketSize; + + EndpointRequirements->HeaderBufferSize = sizeof(UHCI_HCD_QH) + + TdCount * sizeof(UHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = UHCI_MAX_BULK_TRANSFER_SIZE; + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + DPRINT("UhciQueryEndpointRequirements: InterruptTransfer\n"); + TdCount = 2 * UHCI_MAX_INTERRUPT_TD_COUNT; + + EndpointRequirements->HeaderBufferSize = sizeof(UHCI_HCD_QH) + + TdCount * sizeof(UHCI_HCD_TD); + + EndpointRequirements->MaxTransferSize = UHCI_MAX_INTERRUPT_TD_COUNT * + EndpointProperties->TotalMaxPacketSize; + break; + + default: + DPRINT1("UhciQueryEndpointRequirements: Unknown TransferType - %x\n", + TransferType); + DbgBreakPoint(); + break; + } +} + +VOID +NTAPI +UhciCloseEndpoint(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN BOOLEAN IsDoDisablePeriodic) +{ + DPRINT_IMPL("UhciCloseEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciTakeControlHC(IN PUHCI_EXTENSION UhciExtension, + IN PUSBPORT_RESOURCES Resources) +{ + LARGE_INTEGER EndTime; + LARGE_INTEGER CurrentTime; + ULONG ResourcesTypes; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT StatusRegister; + UHCI_PCI_LEGSUP LegacySupport; + UHCI_PCI_LEGSUP LegacyMask; + UHCI_USB_COMMAND Command; + UHCI_USB_STATUS HcStatus; + MPSTATUS MpStatus = MP_STATUS_SUCCESS; + + DPRINT("UhciTakeControlHC: Resources->ResourcesTypes - %x\n", + Resources->ResourcesTypes); + + ResourcesTypes = Resources->ResourcesTypes; + + if ((ResourcesTypes & (USBPORT_RESOURCES_PORT | USBPORT_RESOURCES_INTERRUPT)) != + (USBPORT_RESOURCES_PORT | USBPORT_RESOURCES_INTERRUPT)) + { + DPRINT1("UhciTakeControlHC: MP_STATUS_ERROR\n"); + MpStatus = MP_STATUS_ERROR; + } + + BaseRegister = UhciExtension->BaseRegister; + StatusRegister = &BaseRegister->HcStatus.AsUSHORT; + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + TRUE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); + + UhciDisableInterrupts(UhciExtension); + + Command.AsUSHORT = READ_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT); + + Command.Run = 0; + Command.GlobalReset = 0; + Command.ConfigureFlag = 0; + + WRITE_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT, Command.AsUSHORT); + + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 10000; // 100 ms + + HcStatus.AsUSHORT = READ_PORT_USHORT(StatusRegister); + DPRINT("UhciTakeControlHC: HcStatus.AsUSHORT - %04X\n", HcStatus.AsUSHORT); + + while (HcStatus.HcHalted == 0) + { + HcStatus.AsUSHORT = READ_PORT_USHORT(StatusRegister); + KeQuerySystemTime(&CurrentTime); + + if (CurrentTime.QuadPart >= EndTime.QuadPart) + break; + } + + WRITE_PORT_USHORT(StatusRegister, UHCI_USB_STATUS_MASK); + + LegacyMask.AsUSHORT = 0; + LegacyMask.Smi60Read = 1; + LegacyMask.Smi60Write = 1; + LegacyMask.Smi64Read = 1; + LegacyMask.Smi64Write = 1; + LegacyMask.SmiIrq = 1; + LegacyMask.A20Gate = 1; + LegacyMask.SmiEndPassThrough = 1; + + if (LegacySupport.AsUSHORT & LegacyMask.AsUSHORT) + { + DPRINT("UhciTakeControlHC: LegacySupport.AsUSHORT - %04X\n", + LegacySupport.AsUSHORT); + + Resources->LegacySupport = 1; + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + TRUE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); + LegacySupport.AsUSHORT = 0; + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + FALSE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); + } + + return MpStatus; +} + +MPSTATUS +NTAPI +UhciInitializeHardware(IN PUHCI_EXTENSION UhciExtension) +{ + PUHCI_HW_REGISTERS BaseRegister; + UHCI_USB_COMMAND Command; + UHCI_USB_STATUS StatusMask; + + DPRINT("UhciInitializeHardware: UhciExtension - %p\n", UhciExtension); + DPRINT("UhciInitializeHardware: VIA HW FIXME\n"); // after supporting HcFlavor in usbport + + BaseRegister = UhciExtension->BaseRegister; + + /* Save SOF Timing Value */ + UhciExtension->SOF_Modify = READ_PORT_UCHAR(&BaseRegister->SOF_Modify); + + RegPacket.UsbPortWait(UhciExtension, 20); + + Command.AsUSHORT = READ_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT); + + /* Global Reset */ + Command.AsUSHORT = 0; + Command.GlobalReset = 1; + WRITE_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT, Command.AsUSHORT); + + RegPacket.UsbPortWait(UhciExtension, 20); + + Command.AsUSHORT = 0; + WRITE_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT, Command.AsUSHORT); + + /* Set MaxPacket for full speed bandwidth reclamation */ + Command.AsUSHORT = 0; + Command.MaxPacket = 1; // 64 bytes + WRITE_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT, Command.AsUSHORT); + + /* Restore SOF Timing Value */ + WRITE_PORT_UCHAR(&BaseRegister->SOF_Modify, UhciExtension->SOF_Modify); + + StatusMask = UhciExtension->StatusMask; + + StatusMask.Interrupt = 1; + StatusMask.ErrorInterrupt = 1; + StatusMask.ResumeDetect = 1; + StatusMask.HostSystemError = 1; + + UhciExtension->StatusMask = StatusMask; + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciInitializeSchedule(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_HC_RESOURCES HcResourcesVA, + IN ULONG hcResourcesPA) +{ + PUHCI_HCD_QH IntQH; + ULONG IntQhPA; + PUHCI_HCD_QH StaticControlHead; + ULONG StaticControlHeadPA; + PUHCI_HCD_QH StaticBulkHead; + ULONG StaticBulkHeadPA; + PUHCI_HCD_TD StaticBulkTD; + ULONG StaticBulkTdPA; + PUHCI_HCD_TD StaticTD; + ULONG StaticTdPA; + PUHCI_HCD_TD StaticSofTD; + ULONG StaticSofTdPA; + ULONG PhysicalAddress; + ULONG Idx; + ULONG HeadIdx; + UCHAR FrameIdx; + PUHCI_HC_RESOURCES HcResourcesPA = (PUHCI_HC_RESOURCES)hcResourcesPA; + + DPRINT("UhciInitializeSchedule: Ext[%p], VA - %p, PA - %p\n", + UhciExtension, + HcResourcesVA, + HcResourcesPA); + + /* Build structure (tree) of static QHs + for interrupt and isochronous transfers */ + for (FrameIdx = 0; FrameIdx < INTERRUPT_ENDPOINTs; FrameIdx++) + { + IntQH = &HcResourcesVA->StaticIntHead[FrameIdx]; + IntQhPA = (ULONG)&HcResourcesPA->StaticIntHead[FrameIdx]; + + RtlZeroMemory(IntQH, sizeof(UHCI_HCD_QH)); + + IntQH->HwQH.NextElement |= UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + IntQH->PhysicalAddress = IntQhPA; + + UhciExtension->IntQH[FrameIdx] = IntQH; + + if (FrameIdx == 0) + UhciSetNextQH(IntQH, UhciExtension->IntQH[0]); + else + UhciSetNextQH(IntQH, UhciExtension->IntQH[(FrameIdx - 1) / 2]); + } + + /* Initialize static QH for control transfers */ + StaticControlHead = &HcResourcesVA->StaticControlHead; + StaticControlHeadPA = (ULONG)&HcResourcesPA->StaticControlHead; + + RtlZeroMemory(StaticControlHead, sizeof(UHCI_HCD_QH)); + + StaticControlHead->HwQH.NextElement |= UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + StaticControlHead->PhysicalAddress = StaticControlHeadPA; + + UhciSetNextQH(UhciExtension->IntQH[0],StaticControlHead); + + UhciExtension->ControlQH = StaticControlHead; + + /* Initialize static QH for bulk transfers */ + StaticBulkHead = &HcResourcesVA->StaticBulkHead; + StaticBulkHeadPA = (ULONG)&HcResourcesPA->StaticBulkHead; + + RtlZeroMemory(StaticBulkHead, sizeof(UHCI_HCD_QH)); + + StaticBulkHead->PhysicalAddress = StaticBulkHeadPA; + PhysicalAddress = StaticBulkHeadPA | UHCI_QH_ELEMENT_LINK_PTR_QH; + PhysicalAddress |= UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + StaticBulkHead->HwQH.NextQH = PhysicalAddress; + + UhciSetNextQH(StaticControlHead, StaticBulkHead); + + UhciExtension->BulkQH = StaticBulkHead; + UhciExtension->BulkTailQH = StaticBulkHead; + + /* Initialize static TD for bulk transfers */ + StaticBulkTD = &HcResourcesVA->StaticBulkTD; + StaticBulkTdPA = (ULONG)&HcResourcesPA->StaticBulkTD; + + StaticBulkTD->HwTD.NextElement = StaticBulkTdPA | UHCI_TD_LINK_PTR_TD; + + StaticBulkTD->HwTD.ControlStatus.AsULONG = 0; + StaticBulkTD->HwTD.ControlStatus.IsochronousType = 1; + + StaticBulkTD->HwTD.Token.AsULONG = 0; + StaticBulkTD->HwTD.Token.Endpoint = 1; + StaticBulkTD->HwTD.Token.MaximumLength = UHCI_TD_LENGTH_NULL; + StaticBulkTD->HwTD.Token.PIDCode = UHCI_TD_PID_OUT; + + StaticBulkTD->HwTD.Buffer = 0; + + StaticBulkTD->PhysicalAddress = StaticBulkTdPA; + StaticBulkTD->NextHcdTD = NULL; + StaticBulkTD->Flags = UHCI_HCD_TD_FLAG_PROCESSED; + + PhysicalAddress = StaticBulkTdPA | UHCI_QH_ELEMENT_LINK_PTR_TD; + UhciExtension->BulkQH->HwQH.NextElement = PhysicalAddress; + + /* Set Frame List pointers */ + for (Idx = 0; Idx < UHCI_FRAME_LIST_MAX_ENTRIES; Idx++) + { + HeadIdx = (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms) + + (Idx & (ENDPOINT_INTERRUPT_32ms - 1)); + + PhysicalAddress = UhciExtension->IntQH[HeadIdx]->PhysicalAddress; + PhysicalAddress |= UHCI_FRAME_LIST_POINTER_QH; + HcResourcesVA->FrameList[Idx] = PhysicalAddress; + } + + /* Initialize static TD for first frame */ + StaticTD = &HcResourcesVA->StaticTD; + StaticTdPA = (ULONG)&HcResourcesPA->StaticTD; + + RtlZeroMemory(StaticTD, sizeof(UHCI_HCD_TD)); + + StaticTD->PhysicalAddress = StaticTdPA; + + HeadIdx = (INTERRUPT_ENDPOINTs - ENDPOINT_INTERRUPT_32ms); + PhysicalAddress = UhciExtension->IntQH[HeadIdx]->PhysicalAddress; + StaticTD->HwTD.NextElement = PhysicalAddress | UHCI_TD_LINK_PTR_QH; + + StaticTD->HwTD.ControlStatus.InterruptOnComplete = 1; + StaticTD->HwTD.Token.PIDCode = UHCI_TD_PID_IN; + + UhciExtension->StaticTD = StaticTD; + + /* Initialize StaticSofTDs for UhciInterruptNextSOF() */ + UhciExtension->SOF_HcdTDs = &HcResourcesVA->StaticSofTD[0]; + StaticSofTdPA = (ULONG)&HcResourcesPA->StaticSofTD[0]; + + for (Idx = 0; Idx < UHCI_MAX_STATIC_SOF_TDS; Idx++) + { + StaticSofTD = UhciExtension->SOF_HcdTDs + Idx; + + RtlZeroMemory(StaticSofTD, sizeof(UHCI_HCD_TD)); + + PhysicalAddress = UhciExtension->IntQH[HeadIdx]->PhysicalAddress; + StaticSofTD->HwTD.NextElement = PhysicalAddress | UHCI_TD_LINK_PTR_QH; + + StaticSofTD->HwTD.ControlStatus.InterruptOnComplete = 1; + StaticSofTD->PhysicalAddress = StaticSofTdPA; + + StaticSofTdPA += sizeof(UHCI_HCD_TD); + } + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciStartController(IN PVOID uhciExtension, + IN PUSBPORT_RESOURCES Resources) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + MPSTATUS MpStatus; + PUSHORT PortControlRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + UHCI_USB_COMMAND Command; + USHORT Port; + + UhciExtension->Flags &= ~UHCI_EXTENSION_FLAG_SUSPENDED; + UhciExtension->BaseRegister = Resources->ResourceBase; + BaseRegister = UhciExtension->BaseRegister; + DPRINT("UhciStartController: UhciExtension - %p, BaseRegister - %p\n", UhciExtension, BaseRegister); + + UhciExtension->HcFlavor = Resources->HcFlavor; + + MpStatus = UhciTakeControlHC(UhciExtension, Resources); + + if (MpStatus == MP_STATUS_SUCCESS) + { + MpStatus = UhciInitializeHardware(UhciExtension); + + if (MpStatus == MP_STATUS_SUCCESS) + { + UhciExtension->HcResourcesVA = (PUHCI_HC_RESOURCES)Resources->StartVA; + UhciExtension->HcResourcesPA = Resources->StartPA; + + MpStatus = UhciInitializeSchedule(UhciExtension, + UhciExtension->HcResourcesVA, + UhciExtension->HcResourcesPA); + + UhciExtension->LockFrameList = 0; + } + } + + WRITE_PORT_ULONG(&BaseRegister->FrameAddress, + (ULONG)((PUHCI_HC_RESOURCES)UhciExtension->HcResourcesPA)->FrameList); + + if (MpStatus == MP_STATUS_SUCCESS) + { + Command.AsUSHORT = READ_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT); + Command.Run = 1; + WRITE_PORT_USHORT(&BaseRegister->HcCommand.AsUSHORT, Command.AsUSHORT); + + for (Port = 0; Port < UHCI_NUM_ROOT_HUB_PORTS; Port++) + { + PortControlRegister = &BaseRegister->PortControl[Port].AsUSHORT; + PortControl.AsUSHORT = READ_PORT_USHORT(PortControlRegister); + + PortControl.ConnectStatusChange = 0; + PortControl.Suspend = 0; + + WRITE_PORT_USHORT(PortControlRegister, PortControl.AsUSHORT); + } + + UhciExtension->HcResourcesVA->FrameList[0] = + UhciExtension->StaticTD->PhysicalAddress; + } + + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +UhciStopController(IN PVOID uhciExtension, + IN BOOLEAN IsDoDisableInterrupts) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT CommandReg; + UHCI_USB_COMMAND Command; + LARGE_INTEGER EndTime; + LARGE_INTEGER CurrentTime; + + DPRINT("UhciStopController: UhciExtension - %p\n", UhciExtension); + + BaseRegister = UhciExtension->BaseRegister; + CommandReg = &BaseRegister->HcCommand.AsUSHORT; + + Command.AsUSHORT = READ_PORT_USHORT(CommandReg); + + if (Command.AsUSHORT == 0xFFFF) + { + DPRINT("UhciStopController: Command == -1\n"); + return; + } + + DPRINT("UhciStopController: Command.AsUSHORT - %p\n", Command.AsUSHORT); + + if (Command.GlobalReset) + { + Command.GlobalReset = 0; + WRITE_PORT_USHORT(CommandReg, Command.AsUSHORT); + } + + Command.HcReset = 1; + + WRITE_PORT_USHORT(CommandReg, Command.AsUSHORT); + + KeQuerySystemTime(&EndTime); + EndTime.QuadPart += 100 * 1000; + + while (Command.AsUSHORT = READ_PORT_USHORT(CommandReg), + Command.HcReset == 1) + { + KeQuerySystemTime(&CurrentTime); + + if (CurrentTime.QuadPart >= CurrentTime.QuadPart) + { + DPRINT1("UhciStopController: Failed to reset\n"); + DbgBreakPoint(); + break; + } + } +} + +VOID +NTAPI +UhciSuspendController(IN PVOID uhciExtension) +{ + DPRINT_IMPL("UhciSuspendController: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciResumeController(IN PVOID uhciExtension) +{ + DPRINT_IMPL("UhciResumeController: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +UhciHardwarePresent(IN PUHCI_EXTENSION UhciExtension) +{ + UHCI_USB_STATUS UhciStatus; + PUSHORT StatusReg; + + StatusReg = &UhciExtension->BaseRegister->HcStatus.AsUSHORT; + UhciStatus.AsUSHORT = READ_PORT_USHORT(StatusReg); + + if (UhciStatus.AsUSHORT == MAXUSHORT) + DPRINT_UHCI("UhciHardwarePresent: HW not present\n"); + + return UhciStatus.AsUSHORT != MAXUSHORT; +} + +BOOLEAN +NTAPI +UhciInterruptService(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT CommandReg; + UHCI_USB_COMMAND Command; + PUSHORT StatusReg; + UHCI_USB_STATUS HcStatus; + PUSHORT InterruptEnableReg; + PUHCI_HCD_QH QH; + PUHCI_HCD_QH BulkTailQH; + ULONG ScheduleError; + BOOLEAN Result = FALSE; + + BaseRegister = UhciExtension->BaseRegister; + StatusReg = &BaseRegister->HcStatus.AsUSHORT; + InterruptEnableReg = &BaseRegister->HcInterruptEnable.AsUSHORT; + CommandReg = &BaseRegister->HcCommand.AsUSHORT; + + if (!UhciHardwarePresent(UhciExtension)) + { + DPRINT1("UhciInterruptService: return FALSE\n"); + return FALSE; + } + + HcStatus.AsUSHORT = READ_PORT_USHORT(StatusReg) & UHCI_USB_STATUS_MASK; + + if (HcStatus.HostSystemError || HcStatus.HcProcessError) + { + DPRINT1("UhciInterruptService: Error [%p] HcStatus %X\n", + UhciExtension, + HcStatus.AsUSHORT); + } + else if (HcStatus.AsUSHORT) + { + UhciExtension->HcScheduleError = 0; + } + + if (HcStatus.HcProcessError) + { + USHORT fn = READ_PORT_USHORT(&BaseRegister->FrameNumber); + USHORT intr = READ_PORT_USHORT(InterruptEnableReg); + USHORT cmd = READ_PORT_USHORT(CommandReg); + + DPRINT1("UhciInterruptService: HC ProcessError!\n"); + DPRINT1("UhciExtension %p, frame %X\n", UhciExtension, fn); + DPRINT1("HcCommand %X\n", cmd); + DPRINT1("HcStatus %X\n", HcStatus.AsUSHORT); + DPRINT1("HcInterruptEnable %X\n", intr); + + DbgBreakPoint(); + } + + if (HcStatus.HcHalted) + { + DPRINT_UHCI("UhciInterruptService: Hc Halted [%p] HcStatus %X\n", + UhciExtension, + HcStatus.AsUSHORT); + } + else if (HcStatus.AsUSHORT) + { + UhciExtension->HcStatus.AsUSHORT = HcStatus.AsUSHORT; + + WRITE_PORT_USHORT(StatusReg, HcStatus.AsUSHORT); + WRITE_PORT_USHORT(InterruptEnableReg, 0); + + if (HcStatus.HostSystemError) + { + DPRINT1("UhciInterruptService: HostSystemError! HcStatus - %X\n", + HcStatus.AsUSHORT); + + DbgBreakPoint(); + } + + Result = TRUE; + } + + if (!HcStatus.Interrupt) + goto NextProcess; + + UhciUpdateCounter(UhciExtension); + + BulkTailQH = UhciExtension->BulkTailQH; + + if (BulkTailQH->HwQH.NextQH & UHCI_QH_HEAD_LINK_PTR_TERMINATE) + goto NextProcess; + + QH = UhciExtension->BulkQH; + + do + { + QH = QH->NextHcdQH; + + if (!QH) + { + BulkTailQH->HwQH.NextQH |= UHCI_QH_HEAD_LINK_PTR_TERMINATE; + goto NextProcess; + } + } + while (QH->HwQH.NextElement & UHCI_QH_ELEMENT_LINK_PTR_TERMINATE); + +NextProcess: + + if (HcStatus.HcProcessError) + { + UhciCleanupFrameList(UhciExtension, TRUE); + + ScheduleError = UhciExtension->HcScheduleError; + UhciExtension->HcScheduleError = ScheduleError + 1; + + DPRINT1("UhciInterruptService: [%p] ScheduleError %X\n", + UhciExtension, + ScheduleError); + + if (ScheduleError < UHCI_MAX_HC_SCHEDULE_ERRORS) + { + Command.AsUSHORT = READ_PORT_USHORT(CommandReg); + Command.Run = 1; + WRITE_PORT_USHORT(CommandReg, Command.AsUSHORT); + } + } + else if (HcStatus.Interrupt && UhciExtension->ExtensionLock) + { + DPRINT1("UhciInterruptService: [%p] HcStatus %X\n", + UhciExtension, + HcStatus.AsUSHORT); + + UhciCleanupFrameList(UhciExtension, FALSE); + } + + return Result; +} + +VOID +NTAPI +UhciInterruptDpc(IN PVOID uhciExtension, + IN BOOLEAN IsDoEnableInterrupts) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + UHCI_USB_STATUS HcStatus; + + DPRINT_UHCI("UhciInterruptDpc: [%p] EnableInt %x, HcStatus %X\n", + uhciExtension, IsDoEnableInterrupts, UhciExtension->HcStatus); + + BaseRegister = UhciExtension->BaseRegister; + + HcStatus = UhciExtension->HcStatus; + UhciExtension->HcStatus.AsUSHORT = 0; + + if ((HcStatus.Interrupt | HcStatus.ErrorInterrupt) != 0) + RegPacket.UsbPortInvalidateEndpoint(UhciExtension, 0); + + if (IsDoEnableInterrupts) + { + WRITE_PORT_USHORT(&BaseRegister->HcInterruptEnable.AsUSHORT, + UhciExtension->StatusMask.AsUSHORT); + } +} + +VOID +NTAPI +UhciQueueTransfer(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUHCI_HCD_TD FirstTD, + IN PUHCI_HCD_TD LastTD) +{ + PUHCI_HCD_QH QH; + PUHCI_HCD_QH BulkTailQH; + PUHCI_HCD_TD TailTD; + ULONG PhysicalAddress; + + DPRINT("UhciQueueTransfer: FirstTD - %p, LastTD - %p\n", FirstTD, LastTD); + + TailTD = UhciEndpoint->TailTD; + QH = UhciEndpoint->QH; + + if (UhciEndpoint->HeadTD) + { + TailTD->NextHcdTD = FirstTD; + + TailTD->HwTD.NextElement = FirstTD->PhysicalAddress; + TailTD->HwTD.NextElement |= UHCI_TD_LINK_PTR_TD; + + PhysicalAddress = QH->HwQH.NextElement; + + PhysicalAddress &= ~(UHCI_TD_LINK_PTR_TERMINATE | + UHCI_TD_LINK_PTR_QH | + UHCI_TD_LINK_PTR_DEPTH_FIRST); + + if (FirstTD->HwTD.ControlStatus.Status & UHCI_TD_STS_ACTIVE) + { + if (PhysicalAddress == TailTD->PhysicalAddress && + !(TailTD->HwTD.ControlStatus.Status & UHCI_TD_STS_ACTIVE)) + { + QH->HwQH.NextElement = FirstTD->PhysicalAddress; + + QH->HwQH.NextElement &= ~(UHCI_QH_ELEMENT_LINK_PTR_TERMINATE | + UHCI_QH_ELEMENT_LINK_PTR_QH); + } + } + } + else + { + if (FirstTD) + { + UhciEndpoint->HeadTD = FirstTD; + } + else + { + UhciEndpoint->TailTD = NULL; + UhciEndpoint->HeadTD = NULL; + } + + if (FirstTD == NULL || UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + { + PhysicalAddress = UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + else + { + PhysicalAddress = FirstTD->PhysicalAddress; + PhysicalAddress &= ~UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + + QH->HwQH.NextElement = PhysicalAddress & ~UHCI_QH_ELEMENT_LINK_PTR_QH; + } + + if (UhciEndpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_BULK) + { + BulkTailQH = UhciExtension->BulkTailQH; + BulkTailQH->HwQH.NextQH &= ~UHCI_QH_HEAD_LINK_PTR_TERMINATE; + } + + UhciEndpoint->TailTD = LastTD; +} + +PUHCI_HCD_TD +NTAPI +UhciAllocateTD(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint) +{ + PUHCI_HCD_TD TD; + ULONG AllocTdCounter; + ULONG ix; + + DPRINT_UHCI("UhciAllocateTD: ...\n"); + + if (UhciEndpoint->MaxTDs == 0) + return NULL; + + AllocTdCounter = UhciEndpoint->AllocTdCounter; + + for (ix = 0; ix < UhciEndpoint->MaxTDs; ++ix) + { + TD = &UhciEndpoint->FirstTD[AllocTdCounter]; + + if (!(TD->Flags & UHCI_HCD_TD_FLAG_ALLOCATED)) + break; + + if (AllocTdCounter < UhciEndpoint->MaxTDs - 1) + AllocTdCounter++; + else + AllocTdCounter = 0; + } + + if (ix >= UhciEndpoint->MaxTDs) + return NULL; + + TD->Flags |= UHCI_HCD_TD_FLAG_ALLOCATED; + + UhciEndpoint->AllocatedTDs++; + UhciEndpoint->AllocTdCounter = AllocTdCounter; + + return TD; +} + +VOID +NTAPI +UhciMapAsyncTransferToTDs(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUHCI_TRANSFER UhciTransfer, + OUT PUHCI_HCD_TD * OutFirstTD, + OUT PUHCI_HCD_TD * OutLastTD, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PUHCI_HCD_TD TD; + PUHCI_HCD_TD LastTD = NULL; + ULONG PhysicalAddress; + USHORT TotalMaxPacketSize; + USHORT DeviceSpeed; + USHORT EndpointAddress; + USHORT DeviceAddress; + ULONG TransferType; + SIZE_T TransferLength = 0; + SIZE_T LengthMapped = 0; + SIZE_T BytesRemaining; + SIZE_T LengthThisTD; + ULONG ix; + BOOL DataToggle; + UCHAR PIDCode; + BOOLEAN IsLastTd = TRUE; + BOOLEAN ZeroLengthTransfer = TRUE; + + DPRINT_UHCI("UhciMapAsyncTransferToTDs: ...\n"); + + TotalMaxPacketSize = UhciEndpoint->EndpointProperties.TotalMaxPacketSize; + DeviceSpeed = UhciEndpoint->EndpointProperties.DeviceSpeed; + EndpointAddress = UhciEndpoint->EndpointProperties.EndpointAddress; + DeviceAddress = UhciEndpoint->EndpointProperties.DeviceAddress; + TransferType = UhciEndpoint->EndpointProperties.TransferType; + + if (SgList->SgElementCount || TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + ZeroLengthTransfer = FALSE; + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + if (UhciTransfer->TransferParameters->TransferFlags & + USBD_TRANSFER_DIRECTION_IN) + { + PIDCode = UHCI_TD_PID_IN; + } + else + { + PIDCode = UHCI_TD_PID_OUT; + } + + DataToggle = UHCI_TD_PID_DATA1; + } + else + { + if (USB_ENDPOINT_DIRECTION_OUT(EndpointAddress)) + PIDCode = UHCI_TD_PID_OUT; + else + PIDCode = UHCI_TD_PID_IN; + + DataToggle = UhciEndpoint->DataToggle; + } + + for (ix = 0; ix < SgList->SgElementCount || ZeroLengthTransfer; ix++) + { + BytesRemaining = SgList->SgElement[ix].SgTransferLength; + PhysicalAddress = SgList->SgElement[ix].SgPhysicalAddress.LowPart; + + if (!IsLastTd) + { + PhysicalAddress += TransferLength; + BytesRemaining -= TransferLength; + } + + IsLastTd = TRUE; + TransferLength = 0; + + while (BytesRemaining || ZeroLengthTransfer) + { + ZeroLengthTransfer = FALSE; + + if (BytesRemaining >= TotalMaxPacketSize) + { + LengthThisTD = TotalMaxPacketSize; + BytesRemaining -= TotalMaxPacketSize; + } + else + { + if (ix >= SgList->SgElementCount - 1) + { + LengthThisTD = BytesRemaining; + } + else + { + IsLastTd = FALSE; + + DPRINT1("UhciMapAsyncTransferToTds: IsLastTd = FALSE. FIXME\n"); + ASSERT(FALSE); + } + + BytesRemaining = 0; + } + + UhciTransfer->PendingTds++; + TD = UhciAllocateTD(UhciExtension, UhciEndpoint); + TD->Flags |= UHCI_HCD_TD_FLAG_PROCESSED; + + TD->HwTD.NextElement = 0; + TD->HwTD.Buffer = PhysicalAddress; + + TD->HwTD.ControlStatus.AsULONG = 0; + TD->HwTD.ControlStatus.LowSpeedDevice = (DeviceSpeed == UsbLowSpeed); + TD->HwTD.ControlStatus.Status = UHCI_TD_STS_ACTIVE; + TD->HwTD.ControlStatus.ErrorCounter = 3; + TD->HwTD.ControlStatus.ActualLength = UHCI_TD_LENGTH_NULL; + TD->HwTD.ControlStatus.ShortPacketDetect = 1; + + TD->HwTD.Token.AsULONG = 0; + TD->HwTD.Token.Endpoint = EndpointAddress; + TD->HwTD.Token.DeviceAddress = DeviceAddress; + TD->HwTD.Token.PIDCode = PIDCode; + + if (LengthThisTD == 0) + TD->HwTD.Token.MaximumLength = UHCI_TD_LENGTH_NULL; + else + TD->HwTD.Token.MaximumLength = LengthThisTD - 1; + + TD->HwTD.Token.DataToggle = (DataToggle == UHCI_TD_PID_DATA1); + + TD->NextHcdTD = 0; + TD->UhciTransfer = UhciTransfer; + + if (!IsLastTd) + ASSERT(FALSE); + + PhysicalAddress += LengthThisTD; + LengthMapped += LengthThisTD; + + if (LastTD) + { + LastTD->HwTD.NextElement = TD->PhysicalAddress & + UHCI_TD_LINK_POINTER_MASK; + LastTD->NextHcdTD = TD; + } + else + { + *OutFirstTD = TD; + } + + LastTD = TD; + DataToggle = DataToggle == UHCI_TD_PID_DATA0; + } + } + + UhciEndpoint->DataToggle = DataToggle; + + *OutLastTD = LastTD; +} + +MPSTATUS +NTAPI +UhciControlTransfer(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PUHCI_TRANSFER UhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PUHCI_HCD_TD FirstTD; + PUHCI_HCD_TD FirstTdPA; + PUHCI_HCD_TD LastTD; + PUHCI_HCD_TD DataFirstTD; + PUHCI_HCD_TD DataLastTD; + UHCI_CONTROL_STATUS ControlStatus; + USB_DEVICE_SPEED DeviceSpeed; + USHORT EndpointAddress; + USHORT DeviceAddress; + ULONG PhysicalAddress; + + DPRINT_UHCI("UhciControlTransfer: UhciTransfer - %p\n", UhciTransfer); + + if (UhciEndpoint->EndpointLock > 1) + { + InterlockedDecrement(&UhciEndpoint->EndpointLock); + + if (UhciEndpoint->EndpointProperties.TransferType == + USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + InterlockedDecrement(&UhciExtension->ExtensionLock); + } + + DPRINT("UhciControlTransfer: end MP_STATUS_FAILURE\n"); + return MP_STATUS_FAILURE; + } + + DeviceSpeed = UhciEndpoint->EndpointProperties.DeviceSpeed; + EndpointAddress = UhciEndpoint->EndpointProperties.EndpointAddress; + DeviceAddress = UhciEndpoint->EndpointProperties.DeviceAddress; + + /* Allocate and setup first TD */ + UhciTransfer->PendingTds++; + FirstTD = UhciAllocateTD(UhciExtension, UhciEndpoint); + FirstTD->Flags |= UHCI_HCD_TD_FLAG_PROCESSED; + DPRINT_UHCI("UhciControlTransfer: FirstTD - %p\n", FirstTD); + + FirstTD->HwTD.NextElement = 0; + + ControlStatus.AsULONG = 0; + ControlStatus.LowSpeedDevice = (DeviceSpeed == UsbLowSpeed); + ControlStatus.Status |= UHCI_TD_STS_ACTIVE; + ControlStatus.ErrorCounter = 3; + FirstTD->HwTD.ControlStatus = ControlStatus; + + FirstTD->HwTD.Token.AsULONG = 0; + FirstTD->HwTD.Token.Endpoint = EndpointAddress; + FirstTD->HwTD.Token.DeviceAddress = DeviceAddress; + + FirstTD->HwTD.Token.MaximumLength = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET); + FirstTD->HwTD.Token.MaximumLength--; + FirstTD->HwTD.Token.PIDCode = UHCI_TD_PID_SETUP; + FirstTD->HwTD.Token.DataToggle = UHCI_TD_PID_DATA0; + + RtlCopyMemory(&FirstTD->SetupPacket, + &TransferParameters->SetupPacket, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + FirstTdPA = (PUHCI_HCD_TD)FirstTD->PhysicalAddress; + FirstTD->HwTD.Buffer = (ULONG)&FirstTdPA->SetupPacket; + + FirstTD->NextHcdTD = NULL; + FirstTD->UhciTransfer = UhciTransfer; + + /* Allocate and setup last TD */ + UhciTransfer->PendingTds++; + LastTD = UhciAllocateTD(UhciExtension, UhciEndpoint); + LastTD->Flags |= UHCI_HCD_TD_FLAG_PROCESSED; + DPRINT_UHCI("UhciControlTransfer: LastTD - %p\n", LastTD); + + LastTD->HwTD.NextElement = 0; + + LastTD->HwTD.ControlStatus.AsULONG = 0; + LastTD->HwTD.ControlStatus.LowSpeedDevice = (DeviceSpeed == UsbLowSpeed); + LastTD->HwTD.ControlStatus.Status |= UHCI_TD_STS_ACTIVE; + LastTD->HwTD.ControlStatus.ErrorCounter = 3; + + LastTD->HwTD.Token.AsULONG = 0; + LastTD->HwTD.Token.Endpoint = EndpointAddress; + LastTD->HwTD.Token.DeviceAddress = DeviceAddress; + + LastTD->UhciTransfer = UhciTransfer; + LastTD->NextHcdTD = NULL; + + /* Allocate and setup TDs for data */ + DataFirstTD = NULL; + DataLastTD = NULL; + + UhciMapAsyncTransferToTDs(UhciExtension, + UhciEndpoint, + UhciTransfer, + &DataFirstTD, + &DataLastTD, + SgList); + + if (DataFirstTD) + { + PhysicalAddress = DataFirstTD->PhysicalAddress; + PhysicalAddress &= UHCI_TD_LINK_POINTER_MASK; + FirstTD->HwTD.NextElement = PhysicalAddress; + FirstTD->NextHcdTD = DataFirstTD; + + PhysicalAddress = LastTD->PhysicalAddress; + PhysicalAddress &= UHCI_TD_LINK_POINTER_MASK; + DataLastTD->HwTD.NextElement = PhysicalAddress; + DataLastTD->NextHcdTD = LastTD; + } + else + { + PhysicalAddress = LastTD->PhysicalAddress; + PhysicalAddress &= UHCI_TD_LINK_POINTER_MASK; + FirstTD->HwTD.NextElement = PhysicalAddress; + FirstTD->NextHcdTD = LastTD; + } + + LastTD->HwTD.Buffer = 0; + LastTD->HwTD.ControlStatus.InterruptOnComplete = 1; + + LastTD->HwTD.Token.DataToggle = UHCI_TD_PID_DATA1; + LastTD->HwTD.Token.MaximumLength = UHCI_TD_LENGTH_NULL; + + if (UhciTransfer->TransferParameters->TransferFlags & + USBD_TRANSFER_DIRECTION_IN) + { + LastTD->HwTD.Token.PIDCode = UHCI_TD_PID_OUT; + } + else + { + LastTD->HwTD.Token.PIDCode = UHCI_TD_PID_IN; + } + + LastTD->HwTD.NextElement = UHCI_TD_LINK_PTR_TERMINATE; + + LastTD->Flags |= UHCI_HCD_TD_FLAG_CONTROLL; + LastTD->NextHcdTD = NULL; + + /* Link this transfer to queue */ + UhciQueueTransfer(UhciExtension, UhciEndpoint, FirstTD, LastTD); + + DPRINT_UHCI("UhciControlTransfer: end MP_STATUS_SUCCESS\n"); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciBulkOrInterruptTransfer(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PUHCI_TRANSFER UhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PUHCI_HCD_TD DataFirstTD; + PUHCI_HCD_TD DataLastTD; + ULONG TotalMaxPacketSize; + ULONG SgCount; + ULONG TransferLength; + ULONG TDs; + ULONG ix; + + DPRINT_UHCI("UhciBulkOrInterruptTransfer: ...\n"); + + TotalMaxPacketSize = UhciEndpoint->EndpointProperties.TotalMaxPacketSize; + + SgCount = SgList->SgElementCount; + + if (SgCount == 0) + { + DPRINT("UhciBulkOrInterruptTransfer: SgCount == 0 \n"); + TDs = 1; + } + else + { + TransferLength = 0; + + for (ix = 0; ix < SgCount; ++ix) + { + TransferLength += SgList->SgElement[ix].SgTransferLength; + } + + DPRINT("UhciBulkOrInterruptTransfer: SgCount - %X, TransferLength - %X\n", + SgList->SgElementCount, + TransferLength); + + if (TransferLength) + { + TDs = TransferLength + (TotalMaxPacketSize - 1); + TDs /= TotalMaxPacketSize; + } + else + { + TDs = 1; + } + } + + if ((UhciEndpoint->MaxTDs - UhciEndpoint->AllocatedTDs) < TDs) + { + DPRINT1("UhciBulkOrInterruptTransfer: Not enough TDs \n"); + return MP_STATUS_FAILURE; + } + + DataFirstTD = NULL; + DataLastTD = NULL; + + UhciMapAsyncTransferToTDs(UhciExtension, + UhciEndpoint, + UhciTransfer, + &DataFirstTD, + &DataLastTD, + SgList); + + if (DataLastTD == NULL || DataFirstTD == NULL) + { + DPRINT1("UhciBulkOrInterruptTransfer: !DataLastTD || !DataFirstTD\n"); + return MP_STATUS_FAILURE; + } + + DataLastTD->HwTD.NextElement = UHCI_TD_LINK_PTR_TERMINATE; + DataLastTD->HwTD.ControlStatus.InterruptOnComplete = 1; + DataLastTD->NextHcdTD = NULL; + + UhciQueueTransfer(UhciExtension, + UhciEndpoint, + DataFirstTD, + DataLastTD); + + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciSubmitTransfer(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PVOID uhciTransfer, + IN PUSBPORT_SCATTER_GATHER_LIST SgList) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + PUHCI_TRANSFER UhciTransfer = uhciTransfer; + ULONG TransferType; + + DPRINT_UHCI("UhciSubmitTransfer: ...\n"); + + InterlockedIncrement(&UhciEndpoint->EndpointLock); + + TransferType = UhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS && + InterlockedIncrement(&UhciExtension->ExtensionLock) == 1) + { + UhciExtension->FrameNumber = UhciGet32BitFrameNumber(UhciExtension); + } + + RtlZeroMemory(UhciTransfer, sizeof(UHCI_TRANSFER)); + + UhciTransfer->TransferParameters = TransferParameters; + UhciTransfer->UhciEndpoint = UhciEndpoint; + UhciTransfer->USBDStatus = USBD_STATUS_SUCCESS; + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL) + { + return UhciControlTransfer(UhciExtension, + UhciEndpoint, + TransferParameters, + UhciTransfer, + SgList); + } + + if (TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + return UhciBulkOrInterruptTransfer(UhciExtension, + UhciEndpoint, + TransferParameters, + UhciTransfer, + SgList); + } + + DPRINT1("UhciSubmitTransfer: Error TransferType - %x\n", TransferType); + + return MP_STATUS_SUCCESS; +} + +USBD_STATUS +NTAPI +UhciGetErrorFromTD(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_HCD_TD TD) +{ + USBD_STATUS USBDStatus; + UCHAR TdStatus; + + //DPRINT("UhciGetErrorFromTD: ...\n"); + + TdStatus = TD->HwTD.ControlStatus.Status; + + if (TdStatus == UHCI_TD_STS_ACTIVE) + { + if (TD->HwTD.Token.MaximumLength == UHCI_TD_LENGTH_NULL) + return USBD_STATUS_SUCCESS; + + if (TD->HwTD.ControlStatus.ActualLength + 1 >= + TD->HwTD.Token.MaximumLength + 1) + { + return USBD_STATUS_SUCCESS; + } + + if (TD->HwTD.ControlStatus.InterruptOnComplete == 1) + return USBD_STATUS_SUCCESS; + + return USBD_STATUS_ERROR_SHORT_TRANSFER; + } + + if (TdStatus & UHCI_TD_STS_BABBLE_DETECTED && + TdStatus & UHCI_TD_STS_STALLED) + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_BUFFER_OVERRUN, TD - %p\n", TD); + return USBD_STATUS_BUFFER_OVERRUN; + } + + if (TdStatus & UHCI_TD_STS_TIMEOUT_CRC_ERROR && + TdStatus & UHCI_TD_STS_STALLED) + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_DEV_NOT_RESPONDING, TD - %p\n", TD); + return USBD_STATUS_DEV_NOT_RESPONDING; + } + + if (TdStatus & UHCI_TD_STS_TIMEOUT_CRC_ERROR) + { + if (TD->HwTD.ControlStatus.ActualLength == UHCI_TD_LENGTH_NULL) + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_DEV_NOT_RESPONDING, TD - %p\n", TD); + return USBD_STATUS_DEV_NOT_RESPONDING; + } + else + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_CRC, TD - %p\n", TD); + return USBD_STATUS_CRC; + } + } + else if (TdStatus & UHCI_TD_STS_DATA_BUFFER_ERROR) + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_DATA_OVERRUN, TD - %p\n", TD); + USBDStatus = USBD_STATUS_DATA_OVERRUN; + } + else if (TdStatus & UHCI_TD_STS_STALLED) + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_STALL_PID, TD - %p\n", TD); + USBDStatus = USBD_STATUS_STALL_PID; + } + else + { + DPRINT1("UhciGetErrorFromTD: USBD_STATUS_INTERNAL_HC_ERROR, TD - %p\n", TD); + USBDStatus = USBD_STATUS_INTERNAL_HC_ERROR; + } + + return USBDStatus; +} + +VOID +NTAPI +UhciProcessDoneNonIsoTD(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_HCD_TD TD) +{ + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + PUHCI_ENDPOINT UhciEndpoint; + PUHCI_TRANSFER UhciTransfer; + USBD_STATUS USBDStatus = USBD_STATUS_SUCCESS; + SIZE_T TransferedLen; + + DPRINT_UHCI("UhciProcessDoneNonIsoTD: TD - %p\n", TD); + + UhciTransfer = TD->UhciTransfer; + UhciTransfer->PendingTds--; + + TransferParameters = UhciTransfer->TransferParameters; + UhciEndpoint = UhciTransfer->UhciEndpoint; + + if (TD->Flags & UHCI_HCD_TD_FLAG_NOT_ACCESSED) + goto ProcessDoneTD; + + if (UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + USBDStatus = UhciGetErrorFromTD(UhciExtension, TD); + + if (USBDStatus != USBD_STATUS_SUCCESS || + (TD->HwTD.ControlStatus.ActualLength == UHCI_TD_LENGTH_NULL)) + { + TransferedLen = 0; + } + else + { + TransferedLen = TD->HwTD.ControlStatus.ActualLength + 1; + } + + if (TD->HwTD.Token.PIDCode != UHCI_TD_PID_SETUP) + UhciTransfer->TransferLen += TransferedLen; + + if (TD->HwTD.Token.PIDCode == UHCI_TD_PID_IN && + TD->Flags & UHCI_HCD_TD_FLAG_DATA_BUFFER) + { + DPRINT_IMPL("UhciProcessDoneNonIsoTD: UNIMPLEMENTED. FIXME\n"); + } + + if (USBDStatus != USBD_STATUS_SUCCESS) + UhciTransfer->USBDStatus = USBDStatus; + +ProcessDoneTD: + + if (TD->Flags & UHCI_HCD_TD_FLAG_DATA_BUFFER) + DPRINT_IMPL("UhciProcessDoneNonIsoTD: UNIMPLEMENTED. FIXME\n"); + + UhciEndpoint->AllocatedTDs--; + + TD->HwTD.NextElement = 0; + TD->UhciTransfer = NULL; + TD->Flags = 0; + + if (UhciTransfer->PendingTds == 0) + { + InterlockedDecrement(&UhciEndpoint->EndpointLock); + + if (UhciEndpoint->EndpointProperties.TransferType == + USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + InterlockedDecrement(&UhciExtension->ExtensionLock); + } + + RegPacket.UsbPortCompleteTransfer(UhciExtension, + UhciEndpoint, + TransferParameters, + UhciTransfer->USBDStatus, + UhciTransfer->TransferLen); + } +} + +MPSTATUS +NTAPI +UhciIsochTransfer(IN PVOID ehciExtension, + IN PVOID ehciEndpoint, + IN PUSBPORT_TRANSFER_PARAMETERS TransferParameters, + IN PVOID ehciTransfer, + IN PVOID isoParameters) +{ + DPRINT_IMPL("UhciIsochTransfer: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +UhciAbortIsoTransfer(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUHCI_TRANSFER UhciTransfer) +{ + DPRINT_IMPL("UhciAbortNonIsoTransfer: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciAbortNonIsoTransfer(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint, + IN PUHCI_TRANSFER UhciTransfer, + IN PULONG CompletedLength) +{ + PUHCI_HCD_TD TD; + PUHCI_HCD_TD PrevTD = NULL; + ULONG PhysicalAddress; + BOOL DataToggle; + BOOLEAN IsHeadTD = FALSE; + + DPRINT("UhciAbortNonIsoTransfer: UhciExtension - %p, QH - %p, UhciTransfer - %p\n", + UhciExtension, + UhciEndpoint->QH, + UhciTransfer); + + for (TD = UhciEndpoint->HeadTD; + TD && TD->UhciTransfer != UhciTransfer; + TD = TD->NextHcdTD) + { + PrevTD = TD; + } + + DataToggle = TD->HwTD.Token.DataToggle; + + if (TD == UhciEndpoint->HeadTD) + IsHeadTD = TRUE; + + while (TD && TD->UhciTransfer == UhciTransfer); + { + DPRINT_UHCI("UhciAbortNonIsoTransfer: TD - %p\n", TD); + + if (TD->HwTD.ControlStatus.Status & UHCI_TD_STS_ACTIVE) + { + if (TD->Flags & UHCI_HCD_TD_FLAG_DATA_BUFFER) + DPRINT_IMPL("UhciAbortNonIsoTransfer: UNIMPLEMENTED. FIXME\n"); + + UhciEndpoint->AllocatedTDs--; + + DPRINT_UHCI("UhciAbortNonIsoTransfer: Active TD - %p\n", TD); + + TD->HwTD.NextElement = 0; + TD->Flags = 0; + TD->UhciTransfer = NULL; + } + else + { + UhciProcessDoneNonIsoTD(UhciExtension, TD); + } + + TD = TD->NextHcdTD; + } + + UhciFixDataToggle(UhciExtension, + UhciEndpoint, + TD, + DataToggle); + + if (IsHeadTD) + { + if (TD) + { + UhciEndpoint->HeadTD = TD; + } + else + { + UhciEndpoint->HeadTD = NULL; + UhciEndpoint->TailTD = NULL; + } + + if (TD == NULL || UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + { + PhysicalAddress = UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + else + { + PhysicalAddress = TD->PhysicalAddress; + PhysicalAddress &= ~UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + + DPRINT_UHCI("UhciPollNonIsoEndpoint: TD - %p\n", TD); + + UhciEndpoint->QH->HwQH.NextElement = PhysicalAddress; + UhciEndpoint->QH->HwQH.NextElement &= ~UHCI_QH_ELEMENT_LINK_PTR_QH; + } + else if (TD) + { + PrevTD->HwTD.NextElement = TD->PhysicalAddress & UHCI_TD_LINK_POINTER_MASK; + PrevTD->NextHcdTD = TD; + } + else + { + PrevTD->NextHcdTD = NULL; + PrevTD->HwTD.NextElement = UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + + UhciEndpoint->TailTD = PrevTD; + } + + *CompletedLength = UhciTransfer->TransferLen; +} + +VOID +NTAPI +UhciAbortTransfer(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN PVOID uhciTransfer, + IN PULONG CompletedLength) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + PUHCI_TRANSFER UhciTransfer = uhciTransfer; + ULONG TransferType; + + DPRINT("UhciAbortTransfer: ...\n"); + + InterlockedDecrement(&UhciEndpoint->EndpointLock); + + TransferType = UhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + InterlockedDecrement(&UhciExtension->ExtensionLock); + + UhciAbortIsoTransfer(UhciExtension, + UhciEndpoint, + UhciTransfer); + } + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + UhciAbortNonIsoTransfer(UhciExtension, + UhciEndpoint, + UhciTransfer, + CompletedLength); + } +} + +ULONG +NTAPI +UhciGetEndpointState(IN PVOID uhciExtension, + IN PVOID uhciEndpoint) +{ + DPRINT_IMPL("UhciGetEndpointState: UNIMPLEMENTED. FIXME\n"); + return 0; +} + +VOID +NTAPI +UhciInsertQH(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_HCD_QH StaticQH, + IN PUHCI_HCD_QH QH) +{ + PUHCI_HCD_QH NextHcdQH; + + DPRINT("UhciInsertQH: UhciExtension - %p, StaticQH - %p, QH - %p\n", UhciExtension, StaticQH, QH); + + QH->HwQH.NextQH = StaticQH->HwQH.NextQH; + NextHcdQH = StaticQH->NextHcdQH; + + QH->PrevHcdQH = StaticQH; + QH->NextHcdQH = NextHcdQH; + + if (NextHcdQH) + NextHcdQH->PrevHcdQH = QH; + else + UhciExtension->BulkTailQH = QH; + + StaticQH->HwQH.NextQH = QH->PhysicalAddress | UHCI_QH_HEAD_LINK_PTR_QH; + StaticQH->NextHcdQH = QH; + + QH->QhFlags |= UHCI_HCD_QH_FLAG_ACTIVE; +} + +VOID +NTAPI +UhciUnlinkQH(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_HCD_QH QH) +{ + PUHCI_HCD_QH NextHcdQH; + PUHCI_HCD_QH PrevHcdQH; + PUHCI_HCD_QH BulkQH; + + DPRINT("UhciUnlinkQH: ... \n"); + + NextHcdQH = QH->NextHcdQH; + PrevHcdQH = QH->PrevHcdQH; + + if (UhciExtension->BulkTailQH == QH) + UhciExtension->BulkTailQH = PrevHcdQH; + + PrevHcdQH->HwQH.NextQH = QH->HwQH.NextQH; + PrevHcdQH->NextHcdQH = NextHcdQH; + + if (NextHcdQH) + NextHcdQH->PrevHcdQH = PrevHcdQH; + + QH->PrevHcdQH = QH; + QH->NextHcdQH = QH; + + if (!(QH->UhciEndpoint->EndpointProperties.TransferType == + USBPORT_TRANSFER_TYPE_BULK)) + { + QH->QhFlags &= ~UHCI_HCD_QH_FLAG_ACTIVE; + return; + } + + if ((UhciExtension->BulkTailQH->HwQH.NextQH & UHCI_QH_HEAD_LINK_PTR_TERMINATE) + == UHCI_QH_HEAD_LINK_PTR_TERMINATE) + { + QH->QhFlags &= ~UHCI_HCD_QH_FLAG_ACTIVE; + return; + } + + BulkQH = UhciExtension->BulkQH; + + while (TRUE) + { + BulkQH = BulkQH->NextHcdQH; + + if (!BulkQH) + break; + + if (!(BulkQH->HwQH.NextElement & UHCI_QH_ELEMENT_LINK_PTR_TERMINATE)) + { + QH->QhFlags &= ~UHCI_HCD_QH_FLAG_ACTIVE; + return; + } + } + + UhciExtension->BulkTailQH->HwQH.NextQH |= UHCI_QH_HEAD_LINK_PTR_TERMINATE; + + QH->QhFlags &= ~UHCI_HCD_QH_FLAG_ACTIVE; +} + +VOID +NTAPI +UhciSetEndpointState(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN ULONG EndpointState) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + ULONG TransferType; + PUHCI_HCD_QH QH; + ULONG Idx; + + TransferType = UhciEndpoint->EndpointProperties.TransferType; + QH = UhciEndpoint->QH; + + DPRINT("UhciSetEndpointState: EndpointState - %x, TransferType - %x\n", + EndpointState, + TransferType); + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + return; + + if (TransferType != USBPORT_TRANSFER_TYPE_CONTROL && + TransferType != USBPORT_TRANSFER_TYPE_BULK && + TransferType != USBPORT_TRANSFER_TYPE_INTERRUPT) + { + DPRINT("UhciSetEndpointState: Unknown TransferType - %x\n", + TransferType); + } + + switch (EndpointState) + { + case USBPORT_ENDPOINT_PAUSED: + UhciUnlinkQH(UhciExtension, QH); + return; + + case USBPORT_ENDPOINT_ACTIVE: + switch (TransferType) + { + case USBPORT_TRANSFER_TYPE_CONTROL: + UhciInsertQH(UhciExtension, + UhciExtension->ControlQH, + UhciEndpoint->QH); + break; + + case USBPORT_TRANSFER_TYPE_BULK: + UhciInsertQH(UhciExtension, + UhciExtension->BulkQH, + UhciEndpoint->QH); + break; + + case USBPORT_TRANSFER_TYPE_INTERRUPT: + Idx = UhciEndpoint->EndpointProperties.Period + + UhciEndpoint->EndpointProperties.ScheduleOffset; + + UhciInsertQH(UhciExtension, + UhciExtension->IntQH[Idx - 1], + UhciEndpoint->QH); + break; + default: + ASSERT(FALSE); + break; + } + + break; + + case USBPORT_ENDPOINT_REMOVE: + QH->QhFlags |= UHCI_HCD_QH_FLAG_REMOVE; + UhciUnlinkQH(UhciExtension, QH); + break; + + default: + ASSERT(FALSE); + break; + } +} + +ULONG +NTAPI +UhciGetEndpointStatus(IN PVOID uhciExtension, + IN PVOID uhciEndpoint) +{ + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + ULONG EndpointStatus; + + DPRINT_UHCI("UhciGetEndpointStatus: ...\n"); + + if (UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + EndpointStatus = USBPORT_ENDPOINT_HALT; + else + EndpointStatus = USBPORT_ENDPOINT_RUN; + + return EndpointStatus; +} + +VOID +NTAPI +UhciSetEndpointStatus(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN ULONG EndpointStatus) +{ + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + ULONG PhysicalAddress; + + DPRINT("UhciSetEndpointStatus: uhciEndpoint - %p, EndpointStatus - %X\n", + uhciEndpoint, + EndpointStatus); + + if (EndpointStatus != USBPORT_ENDPOINT_RUN) + return; + + if (!(UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED)) + return; + + UhciEndpoint->Flags &= ~UHCI_ENDPOINT_FLAG_HALTED; + + if (UhciEndpoint->HeadTD == NULL) + UhciEndpoint->TailTD = NULL; + + if (UhciEndpoint->HeadTD) + { + PhysicalAddress = UhciEndpoint->HeadTD->PhysicalAddress; + PhysicalAddress &= ~UHCI_TD_LINK_PTR_TERMINATE; + UhciEndpoint->QH->HwQH.NextElement = PhysicalAddress; + UhciEndpoint->QH->HwQH.NextElement &= ~UHCI_QH_ELEMENT_LINK_PTR_QH; + } + else + { + UhciEndpoint->QH->HwQH.NextElement = UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } +} + +VOID +NTAPI +UhciPollIsoEndpoint(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint) +{ + DPRINT_IMPL("UhciPollIsoEndpoint: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciPollNonIsoEndpoint(IN PUHCI_EXTENSION UhciExtension, + IN PUHCI_ENDPOINT UhciEndpoint) +{ + PUHCI_HCD_QH QH; + PUHCI_HCD_TD NextTD; + PUHCI_HCD_TD TD; + ULONG NextTdPA; + ULONG PhysicalAddress; + SIZE_T TransferedLen; + PLIST_ENTRY ListTDs; + UCHAR TdStatus; + + DPRINT_UHCI("UhciPollNonIsoEndpoint: UhciExtension - %p, UhciEndpoint - %p\n", + UhciExtension, + UhciEndpoint); + + if (UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + { + DPRINT("UhciPollNonIsoEndpoint: Ep->Flags & UHCI_ENDPOINT_FLAG_HALTED \n"); + return; + } + + QH = UhciEndpoint->QH; + + NextTdPA = QH->HwQH.NextElement & UHCI_QH_ELEMENT_LINK_POINTER_MASK; + + if (NextTdPA) + { + NextTD = RegPacket.UsbPortGetMappedVirtualAddress(NextTdPA, + UhciExtension, + UhciEndpoint); + } + else + { + NextTD = NULL; + } + + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD - %p, NextTdPA - %p\n", + NextTD, + NextTdPA); + + for ( TD = UhciEndpoint->HeadTD; ; TD = TD->NextHcdTD ) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: TD - %p, TD->NextHcdTD - %p\n", + TD, + TD->NextHcdTD); + + if (TD != NextTD && TD != NULL) + { + TD->Flags |= UHCI_HCD_TD_FLAG_DONE; + InsertTailList(&UhciEndpoint->ListTDs, &TD->TdLink); + + if (TD->NextHcdTD && + TD->NextHcdTD->HwTD.ControlStatus.Status & UHCI_TD_STS_ACTIVE) + { + if (NextTdPA == 0) + break; + + if (NextTdPA != TD->NextHcdTD->PhysicalAddress) + { + DPRINT("UhciPollNonIsoEndpoint: TD->NextHcdTD->PhysicalAddress - %p\n", + TD->NextHcdTD->PhysicalAddress); + ASSERT(FALSE); + } + } + else + { + if (TD->NextHcdTD == NULL) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: TD->NextHcdTD == NULL\n"); + } + else + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: ControlStatus - %X\n", + TD->NextHcdTD->HwTD.ControlStatus.AsULONG); + } + } + + continue; + } + + UhciEndpoint->HeadTD = NextTD; + + if (NextTD == NULL) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD == NULL\n"); + + UhciEndpoint->HeadTD = NULL; + UhciEndpoint->TailTD = NULL; + + QH->HwQH.NextElement = UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + + goto ProcessListTDs; + } + + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD - %p, NextTdPA - %p\n", + NextTD, + NextTdPA); + + TdStatus = NextTD->HwTD.ControlStatus.Status; + + if (TdStatus & UHCI_TD_STS_ACTIVE) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: UHCI_TD_STS_ACTIVE \n"); + goto ProcessListTDs; + } + + if (NextTD->HwTD.Token.PIDCode == UHCI_TD_PID_IN && + TdStatus & UHCI_TD_STS_STALLED && + TdStatus & UHCI_TD_STS_TIMEOUT_CRC_ERROR && + !(TdStatus & UHCI_TD_STS_NAK_RECEIVED) && + !(TdStatus & UHCI_TD_STS_BABBLE_DETECTED) && + !(TdStatus & UHCI_TD_STS_BITSTUFF_ERROR)) + { + DPRINT("UhciPollNonIsoEndpoint: USBD_STATUS_DEV_NOT_RESPONDING\n"); + + UhciDumpHcdTD(NextTD); + + if (!(NextTD->Flags & UHCI_HCD_TD_FLAG_STALLED_SETUP)) + { + NextTD->HwTD.ControlStatus.ErrorCounter = 3; + + NextTD->HwTD.ControlStatus.Status &= ~(UHCI_TD_STS_STALLED | + UHCI_TD_STS_TIMEOUT_CRC_ERROR); + + NextTD->HwTD.ControlStatus.Status |= UHCI_TD_STS_ACTIVE; + + NextTD->Flags = NextTD->Flags | UHCI_HCD_TD_FLAG_STALLED_SETUP; + + goto ProcessListTDs; + } + } + + if (TdStatus & (UHCI_TD_STS_STALLED | + UHCI_TD_STS_DATA_BUFFER_ERROR | + UHCI_TD_STS_BABBLE_DETECTED | + UHCI_TD_STS_TIMEOUT_CRC_ERROR | + UHCI_TD_STS_BITSTUFF_ERROR)) + { + DPRINT("UhciPollNonIsoEndpoint: NextTD UHCI_TD_STS_ - %02X, PIDCode - %02X\n", + NextTD->HwTD.ControlStatus.Status, + NextTD->HwTD.Token.PIDCode); + + UhciDumpHcdTD(NextTD); + + UhciEndpoint->Flags |= UHCI_ENDPOINT_FLAG_HALTED; + NextTD->Flags |= UHCI_HCD_TD_FLAG_DONE; + + InsertTailList(&UhciEndpoint->ListTDs, &NextTD->TdLink); + + if (TD->UhciTransfer != NextTD->UhciTransfer) + ASSERT(TD->UhciTransfer == NextTD->UhciTransfer); + + while (TD && + TD->UhciTransfer->TransferParameters->TransferCounter == + NextTD->UhciTransfer->TransferParameters->TransferCounter) + { + DPRINT("UhciPollNonIsoEndpoint: Bad TD - %p\n", TD); + + if (!(TD->Flags & UHCI_HCD_TD_FLAG_DONE)) + { + TD->Flags |= UHCI_HCD_TD_FLAG_DONE; + TD->Flags |= UHCI_HCD_TD_FLAG_NOT_ACCESSED; + + InsertTailList(&UhciEndpoint->ListTDs, &TD->TdLink); + } + + TD = TD->NextHcdTD; + } + + if (UhciEndpoint->EndpointProperties.TransferType != + USBPORT_TRANSFER_TYPE_CONTROL) + { + UhciFixDataToggle(UhciExtension, + UhciEndpoint, + TD, + NextTD->HwTD.Token.DataToggle); + } + } + else + { + TransferedLen = NextTD->HwTD.ControlStatus.ActualLength; + + if (TransferedLen == UHCI_TD_LENGTH_NULL) + TransferedLen = 0; + else + TransferedLen += 1; + + if (NextTD->HwTD.Token.MaximumLength == UHCI_TD_LENGTH_NULL || + TransferedLen >= (NextTD->HwTD.Token.MaximumLength + 1)) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD - %p, TransferedLen - %X\n", + NextTD, + TransferedLen); + + if (NextTdPA == + (QH->HwQH.NextElement & UHCI_QH_ELEMENT_LINK_POINTER_MASK)) + { + NextTD->Flags |= UHCI_HCD_TD_FLAG_DONE; + InsertTailList(&UhciEndpoint->ListTDs, &NextTD->TdLink); + + UhciEndpoint->HeadTD = NextTD->NextHcdTD; + + QH->HwQH.NextElement = NextTD->HwTD.NextElement; + QH->HwQH.NextElement |= UHCI_QH_ELEMENT_LINK_PTR_TD; + + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD - %p, TD - %p\n", + NextTD, + TD); + } + + goto ProcessListTDs; + } + + DPRINT_UHCI("UhciPollNonIsoEndpoint: ShortPacket. ControlStatus - %X\n", + NextTD->HwTD.ControlStatus.AsULONG); + + NextTD->Flags |= UHCI_HCD_TD_FLAG_DONE; + InsertTailList(&UhciEndpoint->ListTDs, &NextTD->TdLink); + + while (TD && + TD->UhciTransfer->TransferParameters->TransferCounter == + NextTD->UhciTransfer->TransferParameters->TransferCounter) + { + if (TD->Flags & UHCI_HCD_TD_FLAG_CONTROLL && + NextTD->UhciTransfer->TransferParameters->TransferFlags & + USBD_SHORT_TRANSFER_OK) + { + break; + } + + if (!(TD->Flags & UHCI_HCD_TD_FLAG_DONE)) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: TD - %p\n", TD); + + TD->Flags |= (UHCI_HCD_TD_FLAG_DONE | + UHCI_HCD_TD_FLAG_NOT_ACCESSED); + + InsertTailList(&UhciEndpoint->ListTDs, &TD->TdLink); + } + + TD = TD->NextHcdTD; + } + + if (NextTD->NextHcdTD && + (UhciEndpoint->EndpointProperties.TransferType != + USBPORT_TRANSFER_TYPE_CONTROL)) + { + UhciFixDataToggle(UhciExtension, + UhciEndpoint, + TD, + NextTD->NextHcdTD->HwTD.Token.DataToggle); + } + + if (!(NextTD->UhciTransfer->TransferParameters->TransferFlags & + USBD_SHORT_TRANSFER_OK)) + { + UhciEndpoint->Flags |= UHCI_ENDPOINT_FLAG_HALTED; + } + } + + if (TD) + { + UhciEndpoint->HeadTD = TD; + } + else + { + UhciEndpoint->HeadTD = NULL; + UhciEndpoint->TailTD = NULL; + } + + if (TD == NULL || UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + { + PhysicalAddress = UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + else + { + PhysicalAddress = TD->PhysicalAddress; + PhysicalAddress &= ~UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + + DPRINT_UHCI("UhciPollNonIsoEndpoint: TD - %p\n", TD); + + QH->HwQH.NextElement = PhysicalAddress; + QH->HwQH.NextElement &= ~UHCI_QH_ELEMENT_LINK_PTR_QH; + + goto ProcessListTDs; + } + + NextTD = TD->NextHcdTD; + UhciEndpoint->HeadTD = NextTD; + + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD - %p\n", NextTD); + + if (NextTD == NULL) + UhciEndpoint->TailTD = NULL; + + if (NextTD == NULL || UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + { + PhysicalAddress = UHCI_ENDPOINT_FLAG_HALTED; + } + else + { + PhysicalAddress = NextTD->PhysicalAddress; + PhysicalAddress &= ~UHCI_QH_ELEMENT_LINK_PTR_TERMINATE; + } + + DPRINT_UHCI("UhciPollNonIsoEndpoint: NextTD - %p\n", NextTD); + + QH->HwQH.NextElement = PhysicalAddress; + QH->HwQH.NextElement &= ~UHCI_QH_ELEMENT_LINK_PTR_QH; + +ProcessListTDs: + + ListTDs = &UhciEndpoint->ListTDs; + + while (!IsListEmpty(ListTDs)) + { + TD = CONTAINING_RECORD(ListTDs->Flink, + UHCI_HCD_TD, + TdLink.Flink); + + RemoveHeadList(ListTDs); + + if ((TD->Flags & (UHCI_HCD_TD_FLAG_PROCESSED | UHCI_HCD_TD_FLAG_DONE)) == + (UHCI_HCD_TD_FLAG_PROCESSED | UHCI_HCD_TD_FLAG_DONE)) + { + UhciProcessDoneNonIsoTD(UhciExtension, TD); + } + } + + if (UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_CONTROL_OR_ISO && + UhciEndpoint->Flags & UHCI_ENDPOINT_FLAG_HALTED) + { + DPRINT_UHCI("UhciPollNonIsoEndpoint: Halted periodic EP - %p\n", + UhciEndpoint); + + UhciSetEndpointStatus(UhciExtension, + UhciEndpoint, + USBPORT_ENDPOINT_RUN); + } +} + +VOID +NTAPI +UhciPollEndpoint(IN PVOID uhciExtension, + IN PVOID uhciEndpoint) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_ENDPOINT UhciEndpoint = uhciEndpoint; + ULONG TransferType; + + DPRINT_UHCI("UhciPollEndpoint: ...\n"); + + TransferType = UhciEndpoint->EndpointProperties.TransferType; + + if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) + { + UhciPollIsoEndpoint(UhciExtension, UhciEndpoint); + return; + } + + if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL || + TransferType == USBPORT_TRANSFER_TYPE_BULK || + TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT) + { + UhciPollNonIsoEndpoint(UhciExtension, UhciEndpoint); + } +} + +VOID +NTAPI +UhciCheckController(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + + if (!UhciHardwarePresent(UhciExtension) || + UhciExtension->HcScheduleError >= UHCI_MAX_HC_SCHEDULE_ERRORS) + { + DPRINT1("UhciCheckController: INVALIDATE_CONTROLLER_SURPRISE_REMOVE !!!\n"); + + RegPacket.UsbPortInvalidateController(UhciExtension, + USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE); + } +} + +ULONG +NTAPI +UhciGet32BitFrameNumber(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + ULONG Uhci32BitFrame; + USHORT Fn; // FrameNumber + ULONG Hp; // FrameHighPart + + Fn = READ_PORT_USHORT(&UhciExtension->BaseRegister->FrameNumber); + Fn &= UHCI_FRNUM_FRAME_MASK; + Hp = UhciExtension->FrameHighPart; + + Uhci32BitFrame = Hp; + Uhci32BitFrame += ((USHORT)Hp ^ Fn) & UHCI_FRNUM_OVERFLOW_LIST; + Uhci32BitFrame |= Fn; + + DPRINT_UHCI("UhciGet32BitFrameNumber: Uhci32BitFrame - %lX\n", + Uhci32BitFrame); + + return Uhci32BitFrame; +} + +VOID +NTAPI +UhciInterruptNextSOF(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HC_RESOURCES UhciResources; + ULONG CurrentFrame; + PUHCI_HCD_TD SOF_HcdTDs; + ULONG ix; + ULONG NextFrame; + ULONG SofFrame; + ULONG Idx; + + DPRINT_UHCI("UhciInterruptNextSOF: ...\n"); + + CurrentFrame = UhciGet32BitFrameNumber(UhciExtension); + + SOF_HcdTDs = UhciExtension->SOF_HcdTDs; + NextFrame = CurrentFrame + 2; + + for (ix = 0; ix < UHCI_MAX_STATIC_SOF_TDS; ++ix) + { + SofFrame = SOF_HcdTDs->Frame; + + if (SofFrame == NextFrame) + break; + + if (SofFrame < CurrentFrame) + { + SOF_HcdTDs->Frame = NextFrame; + SOF_HcdTDs->Flags |= UHCI_HCD_TD_FLAG_GOOD_FRAME; + + /* Insert SOF_HcdTD (InterruptOnComplete = TRUE) in Frame List */ + UhciResources = UhciExtension->HcResourcesVA; + Idx = SOF_HcdTDs->Frame & UHCI_FRAME_LIST_INDEX_MASK; + + InterlockedExchangePointer((PVOID)&SOF_HcdTDs->HwTD.NextElement, + (PVOID)UhciResources->FrameList[Idx]); + + UhciResources->FrameList[Idx] = SOF_HcdTDs->PhysicalAddress; + break; + } + + /* Go to next SOF_HcdTD */ + SOF_HcdTDs += 1; + } + + for (ix = 0; ix < UHCI_MAX_STATIC_SOF_TDS; ++ix) + { + SOF_HcdTDs = &UhciExtension->SOF_HcdTDs[ix]; + + if (SOF_HcdTDs->Frame && + (SOF_HcdTDs->Frame < CurrentFrame || + (SOF_HcdTDs->Frame - CurrentFrame) > UHCI_FRAME_LIST_MAX_ENTRIES)) + { + SOF_HcdTDs->Frame = 0; + } + } +} + +VOID +NTAPI +UhciEnableInterrupts(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + UHCI_PCI_LEGSUP LegacySupport; + + DPRINT("UhciEnableInterrupts: UhciExtension - %p\n", UhciExtension); + + BaseRegister = UhciExtension->BaseRegister; + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + TRUE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); + + LegacySupport.UsbPIRQ = 1; + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + FALSE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); + + WRITE_PORT_USHORT(&BaseRegister->HcInterruptEnable.AsUSHORT, + UhciExtension->StatusMask.AsUSHORT); +} + +VOID +NTAPI +UhciDisableInterrupts(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + USB_CONTROLLER_FLAVOR HcFlavor; + UHCI_PCI_LEGSUP LegacySupport; + + DPRINT("UhciDisableInterrupts: UhciExtension - %p\n", UhciExtension); + + BaseRegister = UhciExtension->BaseRegister; + WRITE_PORT_USHORT(&BaseRegister->HcInterruptEnable.AsUSHORT, 0); + + HcFlavor = UhciExtension->HcFlavor; + DPRINT("UhciDisableInterrupts: FIXME HcFlavor - %lx\n", HcFlavor); + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + TRUE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); + + LegacySupport.UsbPIRQ = 0; + + RegPacket.UsbPortReadWriteConfigSpace(UhciExtension, + FALSE, + &LegacySupport.AsUSHORT, + PCI_LEGSUP, + sizeof(USHORT)); +} + +VOID +NTAPI +UhciPollController(IN PVOID uhciExtension) +{ + PUHCI_EXTENSION UhciExtension = uhciExtension; + PUHCI_HW_REGISTERS BaseRegister; + PUSHORT PortRegister; + UHCI_PORT_STATUS_CONTROL PortControl; + USHORT Port; + + DPRINT_UHCI("UhciPollController: UhciExtension - %p\n", UhciExtension); + + BaseRegister = UhciExtension->BaseRegister; + + if (!(UhciExtension->Flags & UHCI_EXTENSION_FLAG_SUSPENDED)) + { + UhciCleanupFrameList(UhciExtension, FALSE); + UhciUpdateCounter(UhciExtension); + RegPacket.UsbPortInvalidateRootHub(UhciExtension); + return; + } + + for (Port = 0; Port < UHCI_NUM_ROOT_HUB_PORTS; Port++) + { + PortRegister = (PUSHORT)&BaseRegister->PortControl[Port]; + PortControl.AsUSHORT = READ_PORT_USHORT(PortRegister); + + if (PortControl.ConnectStatusChange == 1) + RegPacket.UsbPortInvalidateRootHub(UhciExtension); + } +} + +VOID +NTAPI +UhciSetEndpointDataToggle(IN PVOID uhciExtension, + IN PVOID uhciEndpoint, + IN ULONG DataToggle) +{ + DPRINT_IMPL("UhciSetEndpointDataToggle: UNIMPLEMENTED. FIXME\n"); +} + +VOID +NTAPI +UhciResetController(IN PVOID uhciExtension) +{ + DPRINT_IMPL("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_IMPL("UhciStartSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +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_IMPL("UhciEndSendOnePacket: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +MPSTATUS +NTAPI +UhciPassThru(IN PVOID uhciExtension, + IN PVOID passThruParameters, + IN ULONG ParameterLength, + IN PVOID pParameters) +{ + DPRINT_IMPL("UhciPassThru: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +VOID +NTAPI +UhciFlushInterrupts(IN PVOID uhciExtension) +{ + DPRINT_IMPL("UhciFlushInterrupts: UNIMPLEMENTED. FIXME\n"); +} + +MPSTATUS +NTAPI +UhciUnload(IN PVOID uhciExtension) +{ + DPRINT_IMPL("UhciUnload: UNIMPLEMENTED. FIXME\n"); + return MP_STATUS_SUCCESS; +} + +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 | + USB_MINIPORT_FLAGS_NOT_LOCK_INT | + USB_MINIPORT_FLAGS_POLLING | + USB_MINIPORT_FLAGS_WAKE_SUPPORT; + + RegPacket.MiniPortBusBandwidth = TOTAL_USB11_BUS_BANDWIDTH; + + 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 = UhciRHDisableIrq; + RegPacket.RH_EnableIrq = UhciRHEnableIrq; + RegPacket.StartSendOnePacket = UhciStartSendOnePacket; + RegPacket.EndSendOnePacket = UhciEndSendOnePacket; + RegPacket.PassThru = UhciPassThru; + RegPacket.FlushInterrupts = UhciFlushInterrupts; + + DriverObject->DriverUnload = NULL; + + return USBPORT_RegisterUSBPortDriver(DriverObject, + USB10_MINIPORT_INTERFACE_VERSION, + &RegPacket); +} diff --git a/drivers/usb/usbuhci_new/usbuhci.h b/drivers/usb/usbuhci_new/usbuhci.h new file mode 100644 index 0000000..bba6c7c --- /dev/null +++ b/drivers/usb/usbuhci_new/usbuhci.h @@ -0,0 +1,297 @@ +#ifndef USBUHCI_H__ +#define USBUHCI_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "hardware.h" + +extern USBPORT_REGISTRATION_PACKET RegPacket; + +#define UHCI_MAX_HC_SCHEDULE_ERRORS 16 +#define UHCI_RH_STATUS_SUCCESS 1 + +#define UHCI_MAX_ISO_TRANSFER_SIZE 0x10000 +#define UHCI_MAX_BULK_TRANSFER_SIZE 0x1000 +//#define UHCI_MAX_BULK_TRANSFER_SIZE 0x10000 // Hack for testing w/o Split Transfers +#define UHCI_MAX_ISO_TD_COUNT 256 +#define UHCI_MAX_INTERRUPT_TD_COUNT 8 + +/* Host Controller Driver Transfer Descriptor (HCD TD) */ +#define UHCI_HCD_TD_FLAG_ALLOCATED 0x00000001 +#define UHCI_HCD_TD_FLAG_PROCESSED 0x00000002 +#define UHCI_HCD_TD_FLAG_DONE 0x00000008 +#define UHCI_HCD_TD_FLAG_NOT_ACCESSED 0x00000010 +#define UHCI_HCD_TD_FLAG_DATA_BUFFER 0x00000020 +#define UHCI_HCD_TD_FLAG_GOOD_FRAME 0x00000040 +#define UHCI_HCD_TD_FLAG_CONTROLL 0x00000400 +#define UHCI_HCD_TD_FLAG_STALLED_SETUP 0x00000800 + +typedef struct _UHCI_ENDPOINT *PUHCI_ENDPOINT; +typedef struct _UHCI_TRANSFER *PUHCI_TRANSFER; + +typedef struct _UHCI_HCD_TD { + /* Hardware */ + UHCI_TD HwTD; + /* Software */ + USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket; + ULONG PhysicalAddress; + ULONG Flags; + struct _UHCI_HCD_TD * NextHcdTD; + _ANONYMOUS_UNION union { + PUHCI_TRANSFER UhciTransfer; +#if !defined(_M_X64) + ULONG Frame; // for SOF_HcdTDs only +#else + struct { + ULONG Frame; + ULONG Pad2; + }; +#endif + } DUMMYUNIONNAME; + LIST_ENTRY TdLink; +#if !defined(_M_X64) + ULONG Padded[4]; +#else + ULONG Padded[15]; +#endif +} UHCI_HCD_TD, *PUHCI_HCD_TD; + +#if !defined(_M_X64) +C_ASSERT(sizeof(UHCI_HCD_TD) == 0x40); +#else +C_ASSERT(sizeof(UHCI_HCD_TD) == 0x80); +#endif + +/* Host Controller Driver Queue Header (HCD QH) */ +#define UHCI_HCD_QH_FLAG_ACTIVE 0x00000001 +#define UHCI_HCD_QH_FLAG_REMOVE 0x00000002 + +typedef struct _UHCI_HCD_QH { + /* Hardware */ + UHCI_QH HwQH; + /* Software */ + ULONG PhysicalAddress; + ULONG QhFlags; + struct _UHCI_HCD_QH * NextHcdQH; +#if !defined(_M_X64) + ULONG Pad1; +#endif + struct _UHCI_HCD_QH * PrevHcdQH; +#if !defined(_M_X64) + ULONG Pad2; +#endif + PUHCI_ENDPOINT UhciEndpoint; +#if !defined(_M_X64) + ULONG Pad3; +#endif + ULONG Padded[6]; +} UHCI_HCD_QH, *PUHCI_HCD_QH; + +C_ASSERT(sizeof(UHCI_HCD_QH) == 0x40); + +#define UHCI_ENDPOINT_FLAG_HALTED 1 +#define UHCI_ENDPOINT_FLAG_RESERVED 2 +#define UHCI_ENDPOINT_FLAG_CONTROL_OR_ISO 4 + +/* UHCI Endpoint follows USBPORT Endpoint */ +typedef struct _UHCI_ENDPOINT { + ULONG Flags; + LONG EndpointLock; + USBPORT_ENDPOINT_PROPERTIES EndpointProperties; + PUHCI_HCD_QH QH; + PUHCI_HCD_TD TailTD; + PUHCI_HCD_TD HeadTD; + PUHCI_HCD_TD FirstTD; + ULONG MaxTDs; + ULONG AllocatedTDs; + ULONG AllocTdCounter; + LIST_ENTRY ListTDs; + BOOL DataToggle; +} UHCI_ENDPOINT, *PUHCI_ENDPOINT; + +/* UHCI Transfer follows USBPORT Transfer */ +typedef struct _UHCI_TRANSFER { + PUSBPORT_TRANSFER_PARAMETERS TransferParameters; + PUHCI_ENDPOINT UhciEndpoint; + USBD_STATUS USBDStatus; + ULONG PendingTds; + SIZE_T TransferLen; +} UHCI_TRANSFER, *PUHCI_TRANSFER; + +#define UHCI_FRAME_LIST_POINTER_VALID (0 << 0) +#define UHCI_FRAME_LIST_POINTER_TERMINATE (1 << 0) +#define UHCI_FRAME_LIST_POINTER_TD (0 << 1) +#define UHCI_FRAME_LIST_POINTER_QH (1 << 1) + +#define UHCI_FRAME_LIST_INDEX_MASK 0x3FF +#define UHCI_MAX_STATIC_SOF_TDS 8 + +typedef struct _UHCI_HC_RESOURCES { + ULONG FrameList[UHCI_FRAME_LIST_MAX_ENTRIES]; // The 4-Kbyte Frame List Table is aligned on a 4-Kbyte boundary + UHCI_HCD_QH StaticIntHead[INTERRUPT_ENDPOINTs]; + UHCI_HCD_QH StaticControlHead; + UHCI_HCD_QH StaticBulkHead; + UHCI_HCD_TD StaticBulkTD; + UHCI_HCD_TD StaticTD; + UHCI_HCD_TD StaticSofTD[UHCI_MAX_STATIC_SOF_TDS]; +} UHCI_HC_RESOURCES, *PUHCI_HC_RESOURCES; + +#define UHCI_EXTENSION_FLAG_SUSPENDED 0x00000002 + +/* UHCI Extension follows USBPORT Extension */ +typedef struct _UHCI_EXTENSION { + PUHCI_HW_REGISTERS BaseRegister; + USB_CONTROLLER_FLAVOR HcFlavor; + PUHCI_HC_RESOURCES HcResourcesVA; + ULONG HcResourcesPA; + PUHCI_HCD_QH IntQH[INTERRUPT_ENDPOINTs]; + PUHCI_HCD_QH ControlQH; + PUHCI_HCD_QH BulkQH; + PUHCI_HCD_QH BulkTailQH; + PUHCI_HCD_TD StaticTD; + PUHCI_HCD_TD SOF_HcdTDs; // pointer to array StaticSofTD[UHCI_MAX_STATIC_SOF_TDS] + ULONG FrameNumber; + ULONG FrameHighPart; + ULONG Flags; + LONG LockFrameList; + ULONG ResetPortMask; + ULONG ResetChangePortMask; + ULONG SuspendChangePortMask; + ULONG HcScheduleError; + LONG ExtensionLock; + UHCI_USB_STATUS StatusMask; + UHCI_USB_STATUS HcStatus; + UCHAR SOF_Modify; + UCHAR Padded2[3]; +} UHCI_EXTENSION, *PUHCI_EXTENSION; + +/* 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 PUSB_PORT_STATUS_AND_CHANGE PortStatus); + +MPSTATUS +NTAPI +UhciRHGetHubStatus( + IN PVOID uhciExtension, + IN PUSB_HUB_STATUS_AND_CHANGE 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 */ +VOID +NTAPI +UhciDisableInterrupts( + IN PVOID uhciExtension); + +ULONG +NTAPI +UhciGet32BitFrameNumber( + IN PVOID uhciExtension); + +BOOLEAN +NTAPI +UhciHardwarePresent( + IN PUHCI_EXTENSION UhciExtension); + +#endif /* USBUHCI_H__ */ diff --git a/drivers/usb/usbuhci_new/usbuhci.rc b/drivers/usb/usbuhci_new/usbuhci.rc new file mode 100644 index 0000000..801d5be --- /dev/null +++ b/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/hal/halx86/acpi/halpnpdd.c b/hal/halx86/acpi/halpnpdd.c index cc30284..289cd87 100644 --- a/hal/halx86/acpi/halpnpdd.c +++ b/hal/halx86/acpi/halpnpdd.c @@ -100,7 +100,7 @@ HalpReportDetectedDevices(IN PDRIVER_OBJECT DriverObject, } /* This will synchronously load the ACPI driver (needed because we're critical for boot) */ - IoSynchronousInvalidateDeviceRelations(FdoExtension->PhysicalDeviceObject, BusRelations); + IoInvalidateDeviceRelations(FdoExtension->PhysicalDeviceObject, BusRelations); } NTSTATUS diff --git a/hal/halx86/legacy/halpnpdd.c b/hal/halx86/legacy/halpnpdd.c index 084ae86..5f84e03 100644 --- a/hal/halx86/legacy/halpnpdd.c +++ b/hal/halx86/legacy/halpnpdd.c @@ -91,7 +91,7 @@ HalpReportDetectedDevices(IN PDRIVER_OBJECT DriverObject, PdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; /* Invalidate device relations since we added a new device */ - IoSynchronousInvalidateDeviceRelations(FdoExtension->PhysicalDeviceObject, BusRelations); + IoInvalidateDeviceRelations(FdoExtension->PhysicalDeviceObject, BusRelations); } NTSTATUS diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h index f47768d..ad1de4e 100644 --- a/ntoskrnl/include/internal/io.h +++ b/ntoskrnl/include/internal/io.h @@ -1339,8 +1339,8 @@ extern ULONG IopNumTriageDumpDataBlocks; extern PVOID IopTriageDumpDataBlocks[64]; extern PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList; extern PDRIVER_OBJECT IopRootDriverObject; -extern KSPIN_LOCK IopDeviceActionLock; -extern LIST_ENTRY IopDeviceActionRequestList; +extern KEVENT PipEnumerationLock; +extern LIST_ENTRY IopPnpEnumerationRequestList; extern RESERVE_IRP_ALLOCATOR IopReserveIrpAllocator; // diff --git a/ntoskrnl/io/iomgr/iomgr.c b/ntoskrnl/io/iomgr/iomgr.c index 47defca..6852309 100644 --- a/ntoskrnl/io/iomgr/iomgr.c +++ b/ntoskrnl/io/iomgr/iomgr.c @@ -15,6 +15,7 @@ ULONG IopTraceLevel = 0; BOOLEAN PnpSystemInit = FALSE; +KEVENT PipEnumerationLock; VOID NTAPI @@ -464,6 +465,22 @@ IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock) return TRUE; } +static +BOOLEAN +NTAPI +IopWaitForBootDevicesStarted(VOID) +{ + NTSTATUS Status; + + Status = KeWaitForSingleObject(&PipEnumerationLock, + Executive, + KernelMode, + FALSE, + NULL); + + return NT_SUCCESS(Status); +} + BOOLEAN INIT_FUNCTION NTAPI @@ -552,19 +569,46 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock) /* Load boot start drivers */ IopInitializeBootDrivers(); + if (!IopWaitForBootDevicesStarted()) + { + DPRINT1("IopWaitForBootDevicesStarted failed!\n"); + return FALSE; + } /* Call back drivers that asked for */ IopReinitializeBootDrivers(); + if (!IopWaitForBootDevicesStarted()) + { + DPRINT1("IopWaitForBootDevicesStarted failed!\n"); + return FALSE; + } + /* Check if this was a ramdisk boot */ if (!_strnicmp(LoaderBlock->ArcBootDeviceName, "ramdisk(0)", 10)) { /* Initialize the ramdisk driver */ IopStartRamdisk(LoaderBlock); + if (!IopWaitForBootDevicesStarted()) + { + DPRINT1("IopWaitForBootDevicesStarted failed!\n"); + return FALSE; + } } - /* No one should need loader block any longer */ - IopLoaderBlock = NULL; +#ifndef NDEBUG + // FIXME: check if IopGroupIndex != 0 (IopInitializeBootDrivers()) + { + LARGE_INTEGER Interval; + Interval.QuadPart = -10000LL * 1000; // 1 sec. + KeDelayExecutionThread(KernelMode, FALSE, &Interval); + if (!IopWaitForBootDevicesStarted()) + { + DPRINT1("IopWaitForBootDevicesStarted failed!\n"); + return FALSE; + } + } +#endif /* Create ARC names for boot devices */ Status = IopCreateArcNames(LoaderBlock); @@ -584,6 +628,9 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock) /* Initialize PnP root relations */ IopEnumerateDevice(IopRootDeviceNode->PhysicalDeviceObject); + /* No one should need loader block any longer */ + IopLoaderBlock = NULL; + #ifndef _WINKD_ /* Read KDB Data */ KdbInit(); diff --git a/ntoskrnl/io/pnpmgr/pnpinit.c b/ntoskrnl/io/pnpmgr/pnpinit.c index 57c8447..b3805fa 100644 --- a/ntoskrnl/io/pnpmgr/pnpinit.c +++ b/ntoskrnl/io/pnpmgr/pnpinit.c @@ -23,6 +23,8 @@ typedef struct _IOPNP_DEVICE_EXTENSION PUNICODE_STRING PiInitGroupOrderTable; USHORT PiInitGroupOrderTableCount; INTERFACE_TYPE PnpDefaultInterfaceType; +KEVENT PipEnumerationLock; +LIST_ENTRY IopPnpEnumerationRequestList; /* FUNCTIONS ******************************************************************/ @@ -246,6 +248,21 @@ Quickie: return i; } +static +NTSTATUS +NTAPI +SetClassGuidValueKey(IN HANDLE ClassGuidHandle, + IN PUNICODE_STRING KeyName, + IN PUNICODE_STRING Key) +{ + return ZwSetValueKey(ClassGuidHandle, + KeyName, + 0, + REG_SZ, + Key->Buffer, + Key->Length + sizeof(UNICODE_NULL)); +} + NTSTATUS NTAPI PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode, @@ -261,6 +278,8 @@ PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode, RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class"); PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL; PWCHAR Buffer; + UNICODE_STRING ServiceName; + LONG DevType = -1; /* Open enumeration root key */ Status = IopOpenRegistryKeyEx(&EnumRootKey, @@ -287,6 +306,234 @@ PipCallDriverAddDevice(IN PDEVICE_NODE DeviceNode, return Status; } + RtlInitUnicodeString(&ServiceName, L"i8042prt"); + + if (ExpInTextModeSetup) + { + if (wcsstr(DeviceNode->InstancePath.Buffer, L"PNP0303")) + { + DevType = 1; // keyboard ps\2 + } + else if (wcsstr(DeviceNode->InstancePath.Buffer, L"PNP0F03")) + { + DevType = 2; // mouse ps\2 + } + else if (wcsstr(DeviceNode->ServiceName.Buffer, L"kbdhid")) + { + DevType = 3; // usb keyboard + } + else if (wcsstr(DeviceNode->ServiceName.Buffer, L"mouhid")) + { + DevType = 4; // usb mouse + } + } + + if (DevType > 0) + { + UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"ClassGUID"); + UNICODE_STRING Key; + ULONG Disposition = 0; + HANDLE ClassHandle=NULL; + HANDLE ClassGuidHandle=NULL; + + DPRINT1("PipCallDriverAddDevice: InstancePath -'%wZ'\n", &DeviceNode->InstancePath); + DPRINT1("PipCallDriverAddDevice: ServiceName -'%wZ'\n", &DeviceNode->ServiceName); + + /* Create subkey ClassGUID for Device Instance key */ + if (DevType == 1 || DevType == 3) + { + RtlInitUnicodeString(&ClassGuid, L"{4D36E96B-E325-11CE-BFC1-08002BE10318}\0"); + } + else if (DevType == 2 || DevType == 4) + { + RtlInitUnicodeString(&ClassGuid, L"{4D36E96F-E325-11CE-BFC1-08002BE10318}\0"); + } + + Status = ZwSetValueKey(SubKey, + &KeyName, + 0, + REG_SZ, + ClassGuid.Buffer, + ClassGuid.Length + sizeof(UNICODE_NULL)); + + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + /* Open the key */ + Status = IopOpenRegistryKeyEx(&ControlKey, + NULL, + &ControlClass, + KEY_READ); + + if (!NT_SUCCESS(Status)) + { + /* No class key */ + DPRINT1("PipCallDriverAddDevice: No key for '%wZ'\n", &ControlClass); + + /* Create class key */ + Status = IopCreateRegistryKeyEx(&ClassHandle, + NULL, + &ControlClass, + KEY_ALL_ACCESS, + REG_OPTION_NON_VOLATILE, + &Disposition); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + if (DevType == 1 || DevType == 3) + { + RtlInitUnicodeString(&ClassGuid, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96B-E325-11CE-BFC1-08002BE10318}"); + } + else if (DevType == 2 || DevType == 4) + { + RtlInitUnicodeString(&ClassGuid, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E96F-E325-11CE-BFC1-08002BE10318}"); + } + + Status = IopCreateRegistryKeyEx(&ClassGuidHandle, + NULL, + &ClassGuid, + KEY_ALL_ACCESS, + REG_OPTION_NON_VOLATILE, + &Disposition); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + if (DevType == 1 || DevType == 3) + { + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}",,0x00000000,"Keyboard" + RtlInitUnicodeString(&KeyName, L""); + RtlInitUnicodeString(&Key, L"Keyboard"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","Class",0x00000000,"Keyboard" + RtlInitUnicodeString(&KeyName, L"Class"); + RtlInitUnicodeString(&Key, L"Keyboard"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","Icon",0x00000000,"-3" + RtlInitUnicodeString(&KeyName, L"Icon"); + RtlInitUnicodeString(&Key, L"-3"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","Installer32",0x00000000,"SysSetup.Dll,KeyboardClassInstaller" + RtlInitUnicodeString(&KeyName, L"Installer32"); + RtlInitUnicodeString(&Key, L"SysSetup.Dll,KeyboardClassInstaller"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","NoInstallClass",0x00000000,"1" + RtlInitUnicodeString(&KeyName, L"NoInstallClass"); + RtlInitUnicodeString(&Key, L"1"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"kbdclass" + RtlInitUnicodeString(&KeyName, L"UpperFilters"); + RtlInitUnicodeString(&Key, L"kbdclass"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + } + else if (DevType == 2 || DevType == 4) + { + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}",,0x00000000,"Mouse" + RtlInitUnicodeString(&KeyName, L""); + RtlInitUnicodeString(&Key, L"Mouse"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","Class",0x00000000,"Mouse" + RtlInitUnicodeString(&KeyName, L"Class"); + RtlInitUnicodeString(&Key, L"Mouse"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","Icon",0x00000000,"-2" + RtlInitUnicodeString(&KeyName, L"Icon"); + RtlInitUnicodeString(&Key, L"-2"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","Installer32",0x00000000,"SysSetup.Dll,MouseClassInstaller" + RtlInitUnicodeString(&KeyName, L"Installer32"); + RtlInitUnicodeString(&Key, L"SysSetup.Dll,MouseClassInstaller"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","NoInstallClass",0x00000000,"1" + RtlInitUnicodeString(&KeyName, L"NoInstallClass"); + RtlInitUnicodeString(&Key, L"1"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + + //HKLM,"SYSTEM\CurrentControlSet\Control\Class\{4D36E96F-E325-11CE-BFC1-08002BE10318}","UpperFilters",0x00010000,"mouclass" + RtlInitUnicodeString(&KeyName, L"UpperFilters"); + RtlInitUnicodeString(&Key, L"mouclass"); + Status = SetClassGuidValueKey(ClassGuidHandle, &KeyName, &Key); + if (!NT_SUCCESS(Status)) + { + DPRINT("PipCallDriverAddDevice: Status -'%X'\n", Status); + goto Exit; + } + } + } + } + /* Get class GUID */ Status = IopGetRegistryValue(SubKey, REGSTR_VAL_CLASSGUID, @@ -399,8 +646,8 @@ IopInitializePlugPlayServices(VOID) /* Initialize locks and such */ KeInitializeSpinLock(&IopDeviceTreeLock); - KeInitializeSpinLock(&IopDeviceActionLock); - InitializeListHead(&IopDeviceActionRequestList); + KeInitializeEvent(&PipEnumerationLock, NotificationEvent, TRUE); + InitializeListHead(&IopPnpEnumerationRequestList); /* Get the default interface */ PnpDefaultInterfaceType = IopDetermineDefaultInterfaceType(); diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c index e4cb7db..0fc2139 100644 --- a/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -35,16 +35,37 @@ extern BOOLEAN PnpSystemInit; PDRIVER_OBJECT IopRootDriverObject; PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL; LIST_ENTRY IopDeviceActionRequestList; -WORK_QUEUE_ITEM IopDeviceActionWorkItem; -BOOLEAN IopDeviceActionInProgress; -KSPIN_LOCK IopDeviceActionLock; - -typedef struct _DEVICE_ACTION_DATA +WORK_QUEUE_ITEM PipDeviceEnumerationWorkItem; +BOOLEAN PipEnumerationInProgress; +KSPIN_LOCK IopPnPSpinLock; + +#define PIP_ENUM_TYPE_ADD_BOOT_DEVICES 0 +#define PIP_ENUM_TYPE_RESOURCES_ASSIGN 1 +#define PIP_ENUM_TYPE_GET_SET_DEVICE_STATUS 2 +#define PIP_ENUM_TYPE_CLEAR_PROBLEM 3 +#define PIP_ENUM_TYPE_INVALIDATE_RELATIONS_IN_LIST 4 +#define PIP_ENUM_TYPE_HALT_DEVICE 5 +#define PIP_ENUM_TYPE_BOOT_PROCESS 6 +#define PIP_ENUM_TYPE_INVALIDATE_RELATIONS 7 +#define PIP_ENUM_TYPE_INVALIDATE_BUS_RELATIONS 8 +#define PIP_ENUM_TYPE_INIT_PNP_SERVICES 9 +#define PIP_ENUM_TYPE_INVALIDATE_DEVICE_STATE 10 +#define PIP_ENUM_TYPE_RESET_DEVICE 11 +#define PIP_ENUM_TYPE_RESOURCE_CHANGE 12 +#define PIP_ENUM_TYPE_SYSTEM_HIVE_LIMIT_CHANGE 13 +#define PIP_ENUM_TYPE_SET_PROBLEM 14 +#define PIP_ENUM_TYPE_SHUTDOWN_PNP_DEVICES 15 +#define PIP_ENUM_TYPE_START_DEVICE 16 +#define PIP_ENUM_TYPE_START_SYSTEM_DEVICES 17 + +typedef struct _PIP_ENUM_REQUEST { - LIST_ENTRY RequestListEntry; + LIST_ENTRY RequestLink; PDEVICE_OBJECT DeviceObject; - DEVICE_RELATION_TYPE Type; -} DEVICE_ACTION_DATA, *PDEVICE_ACTION_DATA; + ULONG Type; + PKEVENT Event; + NTSTATUS * pStatus; +} PIP_ENUM_REQUEST, *PPIP_ENUM_REQUEST; /* FUNCTIONS *****************************************************************/ NTSTATUS @@ -96,6 +117,7 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; ULONG HidLength = 0, CidLength = 0, BufferLength; PWCHAR IdBuffer, OriginalIdBuffer; + extern PLOADER_PARAMETER_BLOCK IopLoaderBlock; /* Open the device instance key */ Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); @@ -192,167 +214,207 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) /* Free our temp buffer */ ExFreePool(PartialInfo); - InitializeObjectAttributes(&ObjectAttributes, - &CriticalDeviceKeyU, - OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, - NULL, - NULL); - Status = ZwOpenKey(&CriticalDeviceKey, - KEY_ENUMERATE_SUB_KEYS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) + if (ExpInTextModeSetup && (IopLoaderBlock != NULL)) { - /* The critical device database doesn't exist because - * we're probably in 1st stage setup, but it's ok */ - ExFreePool(OriginalIdBuffer); - ZwClose(InstanceKey); - return; - } + PPNP_HARDWARE_ID IdDatabase; + NTSTATUS status; - while (*IdBuffer) - { - USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index; + while (*IdBuffer) + { + USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1; - IopFixupDeviceId(IdBuffer); + IdDatabase = IopLoaderBlock->SetupLdrBlock->HardwareIdDatabase; - /* Look through all subkeys for a match */ - for (Index = 0; TRUE; Index++) - { - ULONG NeededLength; - PKEY_BASIC_INFORMATION BasicInfo; - - Status = ZwEnumerateKey(CriticalDeviceKey, - Index, - KeyBasicInformation, - NULL, - 0, - &NeededLength); - if (Status == STATUS_NO_MORE_ENTRIES) - break; - else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) + do { - UNICODE_STRING ChildIdNameU, RegKeyNameU; + ANSI_STRING Id, ChildIdNameA; + UNICODE_STRING ChildIdNameU; - BasicInfo = ExAllocatePool(PagedPool, NeededLength); - if (!BasicInfo) - { - /* No memory */ - ExFreePool(OriginalIdBuffer); - ZwClose(CriticalDeviceKey); - ZwClose(InstanceKey); - return; - } + RtlInitAnsiString(&Id, IdDatabase->Id); + RtlInitUnicodeString(&ChildIdNameU, IdBuffer); - Status = ZwEnumerateKey(CriticalDeviceKey, - Index, - KeyBasicInformation, - BasicInfo, - NeededLength, - &NeededLength); - if (Status != STATUS_SUCCESS) + status = RtlUnicodeStringToAnsiString(&ChildIdNameA, + &ChildIdNameU, + TRUE); + + if (!NT_SUCCESS(status)) { - /* This shouldn't happen */ - ExFreePool(BasicInfo); + DPRINT("IopInstallCriticalDevice: Failed convert ChildIdNameU - %wZ\n", + &ChildIdNameU); continue; } - ChildIdNameU.Buffer = IdBuffer; - ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR); - RegKeyNameU.Buffer = BasicInfo->Name; - RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength; - - if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE)) + if (RtlEqualString(&Id, &ChildIdNameA, TRUE)) { - HANDLE ChildKeyHandle; + ANSI_STRING DriverNameA; + UNICODE_STRING DriverNameU; - InitializeObjectAttributes(&ObjectAttributes, - &ChildIdNameU, - OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, - CriticalDeviceKey, - NULL); + DPRINT("IopInstallCriticalDevice: txtsetup.sif IDs == HID (or CID)\n"); - Status = ZwOpenKey(&ChildKeyHandle, - KEY_QUERY_VALUE, - &ObjectAttributes); - if (Status != STATUS_SUCCESS) - { - ExFreePool(BasicInfo); - continue; - } + /* Write it to the ENUM key */ + RtlInitAnsiString(&DriverNameA, IdDatabase->DriverName); - /* Check if there's already a driver installed */ - Status = ZwQueryValueKey(InstanceKey, - &ClassGuidU, - KeyValuePartialInformation, - NULL, - 0, - &NeededLength); - if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) + status = RtlAnsiStringToUnicodeString(&DriverNameU, + &DriverNameA, + TRUE); + + if (!NT_SUCCESS(status)) { - ExFreePool(BasicInfo); + DPRINT1("IopInstallCriticalDevice: Failed convert DriverName %s\n", + IdDatabase->DriverName); continue; } - Status = ZwQueryValueKey(ChildKeyHandle, - &ClassGuidU, - KeyValuePartialInformation, - NULL, - 0, - &NeededLength); - if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) + Status = ZwSetValueKey(InstanceKey, + &ServiceU, + 0, + REG_SZ, + DriverNameU.Buffer, + DriverNameU.Length + sizeof(UNICODE_NULL)); + + if (!NT_SUCCESS(Status)) { - ExFreePool(BasicInfo); + DPRINT1("IopInstallCriticalDevice: ZwSetValueKey() failed (Status %lx)\n", + Status); continue; } - PartialInfo = ExAllocatePool(PagedPool, NeededLength); - if (!PartialInfo) + DPRINT("Installed service '%s' for device '%wZ'\n", + DriverNameA.Buffer, + &ChildIdNameU); + + RtlFreeUnicodeString(&DriverNameU); + ExFreePool(OriginalIdBuffer); + ZwClose(InstanceKey); + + /* That's it */ + return; + } + + /* Next Id from IdDatabase->Id (txtsetup.sif)*/ + IdDatabase = IdDatabase->Next; + + } while (IdDatabase->Next); + + /* Next HardwareId or CompatibleId from IdBuffer (registry) */ + IdBuffer += StringLength; + } + } + else + { + InitializeObjectAttributes(&ObjectAttributes, + &CriticalDeviceKeyU, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenKey(&CriticalDeviceKey, + KEY_ENUMERATE_SUB_KEYS, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* The critical device database doesn't exist because + * we're probably in 1st stage setup, but it's ok */ + ExFreePool(OriginalIdBuffer); + ZwClose(InstanceKey); + return; + } + + while (*IdBuffer) + { + USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index; + + IopFixupDeviceId(IdBuffer); + + /* Look through all subkeys for a match */ + for (Index = 0; TRUE; Index++) + { + ULONG NeededLength; + PKEY_BASIC_INFORMATION BasicInfo; + + Status = ZwEnumerateKey(CriticalDeviceKey, + Index, + KeyBasicInformation, + NULL, + 0, + &NeededLength); + if (Status == STATUS_NO_MORE_ENTRIES) + break; + else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) + { + UNICODE_STRING ChildIdNameU, RegKeyNameU; + + BasicInfo = ExAllocatePool(PagedPool, NeededLength); + if (!BasicInfo) { + /* No memory */ ExFreePool(OriginalIdBuffer); - ExFreePool(BasicInfo); - ZwClose(InstanceKey); - ZwClose(ChildKeyHandle); ZwClose(CriticalDeviceKey); + ZwClose(InstanceKey); return; } - /* Read ClassGUID entry in the CDDB */ - Status = ZwQueryValueKey(ChildKeyHandle, - &ClassGuidU, - KeyValuePartialInformation, - PartialInfo, - NeededLength, - &NeededLength); + Status = ZwEnumerateKey(CriticalDeviceKey, + Index, + KeyBasicInformation, + BasicInfo, + NeededLength, + &NeededLength); if (Status != STATUS_SUCCESS) { + /* This shouldn't happen */ ExFreePool(BasicInfo); continue; } - /* Write it to the ENUM key */ - Status = ZwSetValueKey(InstanceKey, - &ClassGuidU, - 0, - REG_SZ, - PartialInfo->Data, - PartialInfo->DataLength); - if (Status != STATUS_SUCCESS) - { - ExFreePool(BasicInfo); - ExFreePool(PartialInfo); - ZwClose(ChildKeyHandle); - continue; - } + ChildIdNameU.Buffer = IdBuffer; + ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR); + RegKeyNameU.Buffer = BasicInfo->Name; + RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength; - Status = ZwQueryValueKey(ChildKeyHandle, - &ServiceU, - KeyValuePartialInformation, - NULL, - 0, - &NeededLength); - if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) + if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE)) { - ExFreePool(PartialInfo); + HANDLE ChildKeyHandle; + + InitializeObjectAttributes(&ObjectAttributes, + &ChildIdNameU, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + CriticalDeviceKey, + NULL); + + Status = ZwOpenKey(&ChildKeyHandle, + KEY_QUERY_VALUE, + &ObjectAttributes); + if (Status != STATUS_SUCCESS) + { + ExFreePool(BasicInfo); + continue; + } + + /* Check if there's already a driver installed */ + Status = ZwQueryValueKey(InstanceKey, + &ClassGuidU, + KeyValuePartialInformation, + NULL, + 0, + &NeededLength); + if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) + { + ExFreePool(BasicInfo); + continue; + } + + Status = ZwQueryValueKey(ChildKeyHandle, + &ClassGuidU, + KeyValuePartialInformation, + NULL, + 0, + &NeededLength); + if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) + { + ExFreePool(BasicInfo); + continue; + } + PartialInfo = ExAllocatePool(PagedPool, NeededLength); if (!PartialInfo) { @@ -364,9 +426,9 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) return; } - /* Read the service entry from the CDDB */ + /* Read ClassGUID entry in the CDDB */ Status = ZwQueryValueKey(ChildKeyHandle, - &ServiceU, + &ClassGuidU, KeyValuePartialInformation, PartialInfo, NeededLength, @@ -374,14 +436,12 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) if (Status != STATUS_SUCCESS) { ExFreePool(BasicInfo); - ExFreePool(PartialInfo); - ZwClose(ChildKeyHandle); continue; } /* Write it to the ENUM key */ Status = ZwSetValueKey(InstanceKey, - &ServiceU, + &ClassGuidU, 0, REG_SZ, PartialInfo->Data, @@ -394,40 +454,91 @@ IopInstallCriticalDevice(PDEVICE_NODE DeviceNode) continue; } - DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU); - } - else - { - DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU); + Status = ZwQueryValueKey(ChildKeyHandle, + &ServiceU, + KeyValuePartialInformation, + NULL, + 0, + &NeededLength); + if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL) + { + ExFreePool(PartialInfo); + PartialInfo = ExAllocatePool(PagedPool, NeededLength); + if (!PartialInfo) + { + ExFreePool(OriginalIdBuffer); + ExFreePool(BasicInfo); + ZwClose(InstanceKey); + ZwClose(ChildKeyHandle); + ZwClose(CriticalDeviceKey); + return; + } + + /* Read the service entry from the CDDB */ + Status = ZwQueryValueKey(ChildKeyHandle, + &ServiceU, + KeyValuePartialInformation, + PartialInfo, + NeededLength, + &NeededLength); + if (Status != STATUS_SUCCESS) + { + ExFreePool(BasicInfo); + ExFreePool(PartialInfo); + ZwClose(ChildKeyHandle); + continue; + } + + /* Write it to the ENUM key */ + Status = ZwSetValueKey(InstanceKey, + &ServiceU, + 0, + REG_SZ, + PartialInfo->Data, + PartialInfo->DataLength); + if (Status != STATUS_SUCCESS) + { + ExFreePool(BasicInfo); + ExFreePool(PartialInfo); + ZwClose(ChildKeyHandle); + continue; + } + + DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU); + } + else + { + DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU); + } + + ExFreePool(OriginalIdBuffer); + ExFreePool(PartialInfo); + ExFreePool(BasicInfo); + ZwClose(InstanceKey); + ZwClose(ChildKeyHandle); + ZwClose(CriticalDeviceKey); + + /* That's it */ + return; } - ExFreePool(OriginalIdBuffer); - ExFreePool(PartialInfo); ExFreePool(BasicInfo); - ZwClose(InstanceKey); - ZwClose(ChildKeyHandle); - ZwClose(CriticalDeviceKey); - - /* That's it */ - return; } - - ExFreePool(BasicInfo); - } - else - { - /* Umm, not sure what happened here */ - continue; + else + { + /* Umm, not sure what happened here */ + continue; + } } - } - /* Advance to the next ID */ - IdBuffer += StringLength; + /* Advance to the next ID */ + IdBuffer += StringLength; + } + ZwClose(CriticalDeviceKey); } ExFreePool(OriginalIdBuffer); ZwClose(InstanceKey); - ZwClose(CriticalDeviceKey); } NTSTATUS @@ -745,7 +856,8 @@ IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode) (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)) { /* Enumerate us */ - IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations); + IoInvalidateDeviceRelations(DeviceObject, BusRelations); + Status = STATUS_SUCCESS; } else @@ -906,34 +1018,184 @@ IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, return Status; } -static VOID NTAPI -IopDeviceActionWorker( - _In_ PVOID Context) +PipEnumerationWorker(IN PVOID Context) { - PLIST_ENTRY ListEntry; - PDEVICE_ACTION_DATA Data; + PDEVICE_OBJECT DeviceObject; + PDEVICE_NODE DeviceNode; + PPIP_ENUM_REQUEST Request; + PLIST_ENTRY Entry; + BOOLEAN IsDereferenceObject; KIRQL OldIrql; + NTSTATUS Status; + + //FIXME: DeviceNodeLockTree(TRUE); + + KeAcquireSpinLock(&IopPnPSpinLock, &OldIrql); + + while (!IsListEmpty(&IopPnpEnumerationRequestList)) + { + Status = STATUS_SUCCESS; + IsDereferenceObject = TRUE; + + Entry = RemoveHeadList(&IopPnpEnumerationRequestList); + ASSERT(Entry); // ? Need ? + + Request = CONTAINING_RECORD(Entry, + PIP_ENUM_REQUEST, + RequestLink); + + KeReleaseSpinLock(&IopPnPSpinLock, OldIrql); + + InitializeListHead(Entry); + + //FIXME: Check ShuttingDown\n"); + + DeviceObject = Request->DeviceObject; + ASSERT(DeviceObject); + + DeviceNode = IopGetDeviceNode(DeviceObject); + ASSERT(DeviceNode); + + if (DeviceNode->State == DeviceNodeDeleted) + { + Status = STATUS_UNSUCCESSFUL; + } + else + { + DPRINT("PipEnumerationWorker: DeviceObject - %p, Request->Type - %X\n", + DeviceObject, + Request->Type); + + switch (Request->Type) + { + case PIP_ENUM_TYPE_INVALIDATE_RELATIONS: + case PIP_ENUM_TYPE_INVALIDATE_BUS_RELATIONS: + case PIP_ENUM_TYPE_INIT_PNP_SERVICES: // NOT_IMPLEMENTED FIXME + case PIP_ENUM_TYPE_SYSTEM_HIVE_LIMIT_CHANGE: // NOT_IMPLEMENTED FIXME + Status = IopEnumerateDevice(Request->DeviceObject); + IsDereferenceObject = FALSE; + break; + + // NOT_IMPLEMENTED FIXME + case PIP_ENUM_TYPE_ADD_BOOT_DEVICES: + case PIP_ENUM_TYPE_RESOURCES_ASSIGN: + case PIP_ENUM_TYPE_GET_SET_DEVICE_STATUS: + case PIP_ENUM_TYPE_INVALIDATE_RELATIONS_IN_LIST: + case PIP_ENUM_TYPE_CLEAR_PROBLEM: + case PIP_ENUM_TYPE_HALT_DEVICE: + case PIP_ENUM_TYPE_BOOT_PROCESS: + case PIP_ENUM_TYPE_INVALIDATE_DEVICE_STATE: + case PIP_ENUM_TYPE_RESET_DEVICE: + case PIP_ENUM_TYPE_START_DEVICE: + case PIP_ENUM_TYPE_RESOURCE_CHANGE: + case PIP_ENUM_TYPE_SET_PROBLEM: + case PIP_ENUM_TYPE_SHUTDOWN_PNP_DEVICES: + case PIP_ENUM_TYPE_START_SYSTEM_DEVICES: + default: + ASSERT(FALSE); + break; + } + } + + if (Request->pStatus) + *Request->pStatus = Status; + + if (Request->Event) + KeSetEvent(Request->Event, IO_NO_INCREMENT, FALSE); + + if (IsDereferenceObject) + ObDereferenceObject(Request->DeviceObject); + + ExFreePoolWithTag(Request, TAG_IO); + + KeAcquireSpinLock(&IopPnPSpinLock, &OldIrql); + } + + PipEnumerationInProgress = FALSE; + KeSetEvent(&PipEnumerationLock, IO_NO_INCREMENT, FALSE); // KeWaitForSingleObject() in IoInitSystem() + KeReleaseSpinLock(&IopPnPSpinLock, OldIrql); + + //FIXME: DeviceNodeUnlockTree(TRUE); +} + +NTSTATUS +NTAPI +PipRequestEnumerationAction(IN PDEVICE_OBJECT DeviceObject, + IN ULONG RequestType, + IN PKEVENT Event, + IN NTSTATUS * pStatus) +{ + PPIP_ENUM_REQUEST Request; + PDEVICE_OBJECT RequestDeviceObject; + KIRQL OldIrql; + + DPRINT("PipRequestEnumerationAction: DeviceObject - %p, RequestType - %X\n", + DeviceObject, + RequestType); + + //FIXME: check ShuttingDown + + Request = ExAllocatePoolWithTag(NonPagedPool, + sizeof(PIP_ENUM_REQUEST), + TAG_IO); + + if (!Request) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (!DeviceObject) + RequestDeviceObject = IopRootDeviceNode->PhysicalDeviceObject; + else + RequestDeviceObject = DeviceObject; + + ObReferenceObject(RequestDeviceObject); - KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); - while (!IsListEmpty(&IopDeviceActionRequestList)) + Request->DeviceObject = RequestDeviceObject; + Request->Type = RequestType; + Request->Event = Event; + Request->pStatus = pStatus; + + InitializeListHead(&Request->RequestLink); // ? Need ? + + KeAcquireSpinLock(&IopPnPSpinLock, &OldIrql); + + InsertTailList(&IopPnpEnumerationRequestList, &Request->RequestLink); + + if (RequestType == PIP_ENUM_TYPE_ADD_BOOT_DEVICES || + RequestType == PIP_ENUM_TYPE_BOOT_PROCESS || + RequestType == PIP_ENUM_TYPE_INIT_PNP_SERVICES) { - ListEntry = RemoveHeadList(&IopDeviceActionRequestList); - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); - Data = CONTAINING_RECORD(ListEntry, - DEVICE_ACTION_DATA, - RequestListEntry); + ASSERT(!PipEnumerationInProgress); + + PipEnumerationInProgress = TRUE; + KeClearEvent(&PipEnumerationLock); + KeReleaseSpinLock(&IopPnPSpinLock, OldIrql); - IoSynchronousInvalidateDeviceRelations(Data->DeviceObject, - Data->Type); + PipEnumerationWorker(NULL); - ObDereferenceObject(Data->DeviceObject); - ExFreePoolWithTag(Data, TAG_IO); - KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); + return STATUS_SUCCESS; } - IopDeviceActionInProgress = FALSE; - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); + + if (PipEnumerationInProgress) // FIXME: (!PnPBootDriversLoaded || PipEnumerationInProgress) + { + KeReleaseSpinLock(&IopPnPSpinLock, OldIrql); + return STATUS_SUCCESS; + } + + PipEnumerationInProgress = TRUE; + KeClearEvent(&PipEnumerationLock); + KeReleaseSpinLock(&IopPnPSpinLock, OldIrql); + + ExInitializeWorkItem(&PipDeviceEnumerationWorkItem, + PipEnumerationWorker, + NULL); + + ExQueueWorkItem(&PipDeviceEnumerationWorkItem, DelayedWorkQueue); + + return STATUS_SUCCESS; } NTSTATUS @@ -4888,38 +5150,44 @@ cleanup: */ VOID NTAPI -IoInvalidateDeviceRelations( - IN PDEVICE_OBJECT DeviceObject, - IN DEVICE_RELATION_TYPE Type) +IoInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject, + IN DEVICE_RELATION_TYPE Type) { - PDEVICE_ACTION_DATA Data; - KIRQL OldIrql; - - Data = ExAllocatePoolWithTag(NonPagedPool, - sizeof(DEVICE_ACTION_DATA), - TAG_IO); - if (!Data) - return; - - ObReferenceObject(DeviceObject); - Data->DeviceObject = DeviceObject; - Data->Type = Type; + PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); - KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); - InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry); - if (IopDeviceActionInProgress) + if (!DeviceObject || !DeviceNode || + DeviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE) { - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); - return; + KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, + 0x2, + (ULONG_PTR)DeviceObject, + 0x0, + 0x0); } - IopDeviceActionInProgress = TRUE; - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); + switch (Type) + { + case BusRelations: + PipRequestEnumerationAction(DeviceObject, + PIP_ENUM_TYPE_INVALIDATE_BUS_RELATIONS, + NULL, + NULL); + break; - ExInitializeWorkItem(&IopDeviceActionWorkItem, - IopDeviceActionWorker, - NULL); - ExQueueWorkItem(&IopDeviceActionWorkItem, - DelayedWorkQueue); + case PowerRelations: + DPRINT("IoInvalidateDeviceRelations: PowerRelations NOT_IMPLEMENTED FIXME!\n"); + //ASSERT(FALSE);//PoInvalidateDevicePowerRelations(DeviceObject); + break; + + case SingleBusRelations: + PipRequestEnumerationAction(DeviceObject, + PIP_ENUM_TYPE_INVALIDATE_RELATIONS, + NULL, + NULL); + break; + + default: + break; + } } /* @@ -4927,27 +5195,70 @@ IoInvalidateDeviceRelations( */ NTSTATUS NTAPI -IoSynchronousInvalidateDeviceRelations( - IN PDEVICE_OBJECT DeviceObject, - IN DEVICE_RELATION_TYPE Type) +IoSynchronousInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject, + IN DEVICE_RELATION_TYPE Type) { + PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); + NTSTATUS Status = STATUS_SUCCESS; + KEVENT Event; + PAGED_CODE(); + if (!DeviceObject || !DeviceNode || + DeviceNode->Flags & DNF_LEGACY_RESOURCE_DEVICENODE) + { + KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, + 0x2, + (ULONG_PTR)DeviceObject, + 0x0, + 0x0); + } + switch (Type) { case BusRelations: - /* Enumerate the device */ - return IopEnumerateDevice(DeviceObject); + { + + if (PnpSystemInit && DeviceNode->State == DeviceNodeStarted) + { + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + Status = PipRequestEnumerationAction(DeviceObject, + PIP_ENUM_TYPE_INVALIDATE_BUS_RELATIONS, + &Event, + NULL); + + if (NT_SUCCESS(Status)) + { + Status = KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + } + } + else + { + Status = STATUS_UNSUCCESSFUL; + } + + break; + } + + case EjectionRelations: + Status = STATUS_NOT_SUPPORTED; + break; + case PowerRelations: - /* Not handled yet */ - return STATUS_NOT_IMPLEMENTED; - case TargetDeviceRelation: - /* Nothing to do */ - return STATUS_SUCCESS; + DPRINT("IoSynchronousInvalidateDeviceRelations: PowerRelations NOT_IMPLEMENTED FIXME!\n"); + //ASSERT(FALSE);//PoInvalidateDevicePowerRelations(DeviceObject); + break; + default: - /* Ejection relations are not supported */ - return STATUS_NOT_SUPPORTED; + break; } + + return Status; } /* diff --git a/sdk/lib/drivers/hidparser/api.c b/sdk/lib/drivers/hidparser/api.c index d4eb327..2085fe0 100644 --- a/sdk/lib/drivers/hidparser/api.c +++ b/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/sdk/lib/drivers/hidparser/hidparser.c b/sdk/lib/drivers/hidparser/hidparser.c index 957f47c..8daa927 100644 --- a/sdk/lib/drivers/hidparser/hidparser.c +++ b/sdk/lib/drivers/hidparser/hidparser.c @@ -57,6 +57,7 @@ HidParser_GetCollectionDescription( ULONG CollectionCount; ULONG Index; PVOID ParserContext; + BOOLEAN UsesReportId = 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)) + { + UsesReportId = TRUE; + } + + if (UsesReportId) + { + 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); diff --git a/sdk/lib/drivers/hidparser/parser.h b/sdk/lib/drivers/hidparser/parser.h index 1a8f0ce..5656b39 100644 --- a/sdk/lib/drivers/hidparser/parser.h +++ b/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); -- 2.7.4