/* * PROJECT: ReactOS USB Port Driver * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: USBPort main driver functions * COPYRIGHT: Copyright 2017 Vadim Galyant */ #include "usbport.h" #define NDEBUG #include #define NDEBUG_USBPORT_CORE #define NDEBUG_USBPORT_INTERRUPT #define NDEBUG_USBPORT_TIMER #include "usbdebug.h" LIST_ENTRY USBPORT_MiniPortDrivers = {NULL, NULL}; LIST_ENTRY USBPORT_USB1FdoList = {NULL, NULL}; LIST_ENTRY USBPORT_USB2FdoList = {NULL, NULL}; KSPIN_LOCK USBPORT_SpinLock; BOOLEAN USBPORT_Initialized = FALSE; PDEVICE_OBJECT NTAPI USBPORT_FindUSB2Controller(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_DEVICE_EXTENSION USB2FdoExtension; KIRQL OldIrql; PLIST_ENTRY USB2FdoEntry; PDEVICE_OBJECT USB2FdoDevice = NULL; DPRINT("USBPORT_FindUSB2Controller: FdoDevice - %p\n", FdoDevice); FdoExtension = FdoDevice->DeviceExtension; KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); USB2FdoEntry = USBPORT_USB2FdoList.Flink; while (USB2FdoEntry && USB2FdoEntry != &USBPORT_USB2FdoList) { USB2FdoExtension = CONTAINING_RECORD(USB2FdoEntry, USBPORT_DEVICE_EXTENSION, ControllerLink); if (USB2FdoExtension->BusNumber == FdoExtension->BusNumber && USB2FdoExtension->PciDeviceNumber == FdoExtension->PciDeviceNumber) { USB2FdoDevice = USB2FdoExtension->CommonExtension.SelfDevice; break; } USB2FdoEntry = USB2FdoEntry->Flink; } KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); return USB2FdoDevice; } VOID NTAPI USBPORT_AddUSB1Fdo(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_AddUSB1Fdo: FdoDevice - %p\n", FdoDevice); FdoExtension = FdoDevice->DeviceExtension; FdoExtension->Flags |= USBPORT_FLAG_REGISTERED_FDO; ExInterlockedInsertTailList(&USBPORT_USB1FdoList, &FdoExtension->ControllerLink, &USBPORT_SpinLock); } VOID NTAPI USBPORT_AddUSB2Fdo(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_AddUSB2Fdo: FdoDevice - %p\n", FdoDevice); FdoExtension = FdoDevice->DeviceExtension; FdoExtension->Flags |= USBPORT_FLAG_REGISTERED_FDO; ExInterlockedInsertTailList(&USBPORT_USB2FdoList, &FdoExtension->ControllerLink, &USBPORT_SpinLock); } VOID NTAPI USBPORT_RemoveUSBxFdo(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; KIRQL OldIrql; DPRINT("USBPORT_RemoveUSBxFdo: FdoDevice - %p\n", FdoDevice); FdoExtension = FdoDevice->DeviceExtension; KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); RemoveEntryList(&FdoExtension->ControllerLink); KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); FdoExtension->Flags &= ~USBPORT_FLAG_REGISTERED_FDO; FdoExtension->ControllerLink.Flink = NULL; FdoExtension->ControllerLink.Blink = NULL; } BOOLEAN NTAPI USBPORT_IsCompanionFdoExtension(IN PDEVICE_OBJECT USB2FdoDevice, IN PUSBPORT_DEVICE_EXTENSION USB1FdoExtension) { PUSBPORT_DEVICE_EXTENSION USB2FdoExtension; DPRINT("USBPORT_IsCompanionFdoExtension: USB2Fdo - %p, USB1FdoExtension - %p\n", USB2FdoDevice, USB1FdoExtension); USB2FdoExtension = USB2FdoDevice->DeviceExtension; return USB2FdoExtension->BusNumber == USB1FdoExtension->BusNumber && USB2FdoExtension->PciDeviceNumber == USB1FdoExtension->PciDeviceNumber; } PDEVICE_RELATIONS NTAPI USBPORT_FindCompanionControllers(IN PDEVICE_OBJECT USB2FdoDevice, IN BOOLEAN IsObRefer, IN BOOLEAN IsFDOsReturned) { PLIST_ENTRY USB1FdoList; PUSBPORT_DEVICE_EXTENSION USB1FdoExtension; ULONG NumControllers = 0; PDEVICE_OBJECT * Entry; PDEVICE_RELATIONS ControllersList = NULL; KIRQL OldIrql; DPRINT("USBPORT_FindCompanionControllers: USB2Fdo - %p, IsObRefer - %x, IsFDOs - %x\n", USB2FdoDevice, IsObRefer, IsFDOsReturned); KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); USB1FdoList = USBPORT_USB1FdoList.Flink; while (USB1FdoList && USB1FdoList != &USBPORT_USB1FdoList) { USB1FdoExtension = CONTAINING_RECORD(USB1FdoList, USBPORT_DEVICE_EXTENSION, ControllerLink); if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC && USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension)) { ++NumControllers; } USB1FdoList = USB1FdoExtension->ControllerLink.Flink; } DPRINT("USBPORT_FindCompanionControllers: NumControllers - %x\n", NumControllers); if (!NumControllers) { goto Exit; } ControllersList = ExAllocatePoolWithTag(NonPagedPool, NumControllers * sizeof(DEVICE_RELATIONS), USB_PORT_TAG); if (!ControllersList) { goto Exit; } RtlZeroMemory(ControllersList, NumControllers * sizeof(DEVICE_RELATIONS)); ControllersList->Count = NumControllers; USB1FdoList = USBPORT_USB1FdoList.Flink; Entry = &ControllersList->Objects[0]; while (USB1FdoList && USB1FdoList != &USBPORT_USB1FdoList) { USB1FdoExtension = CONTAINING_RECORD(USB1FdoList, USBPORT_DEVICE_EXTENSION, ControllerLink); if (USB1FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC && USBPORT_IsCompanionFdoExtension(USB2FdoDevice, USB1FdoExtension)) { *Entry = USB1FdoExtension->CommonExtension.LowerPdoDevice; if (IsObRefer) { ObReferenceObject(USB1FdoExtension->CommonExtension.LowerPdoDevice); } if (IsFDOsReturned) { *Entry = USB1FdoExtension->CommonExtension.SelfDevice; } ++Entry; } USB1FdoList = USB1FdoExtension->ControllerLink.Flink; } Exit: KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); return ControllersList; } MPSTATUS NTAPI USBPORT_NtStatusToMpStatus(NTSTATUS NtStatus) { DPRINT("USBPORT_NtStatusToMpStatus: NtStatus - %x\n", NtStatus); if (NtStatus == STATUS_SUCCESS) { return MP_STATUS_SUCCESS; } else { return MP_STATUS_UNSUCCESSFUL; } } NTSTATUS NTAPI USBPORT_SetRegistryKeyValue(IN PDEVICE_OBJECT DeviceObject, IN BOOL UseDriverKey, IN ULONG Type, IN PCWSTR ValueNameString, IN PVOID Data, IN ULONG DataSize) { UNICODE_STRING ValueName; HANDLE KeyHandle; NTSTATUS Status; DPRINT("USBPORT_SetRegistryKeyValue: ValueNameString - %S\n", ValueNameString); if (UseDriverKey) { Status = IoOpenDeviceRegistryKey(DeviceObject, PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_ALL, &KeyHandle); } else { Status = IoOpenDeviceRegistryKey(DeviceObject, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &KeyHandle); } if (NT_SUCCESS(Status)) { RtlInitUnicodeString(&ValueName, ValueNameString); Status = ZwSetValueKey(KeyHandle, &ValueName, 0, Type, Data, DataSize); ZwClose(KeyHandle); } return Status; } NTSTATUS NTAPI USBPORT_GetRegistryKeyValueFullInfo(IN PDEVICE_OBJECT FdoDevice, IN PDEVICE_OBJECT PdoDevice, IN BOOL UseDriverKey, IN PCWSTR SourceString, IN ULONG LengthStr, IN PVOID Buffer, IN ULONG BufferLength) { NTSTATUS Status; PKEY_VALUE_FULL_INFORMATION KeyValue; UNICODE_STRING ValueName; HANDLE KeyHandle; ULONG LengthKey; DPRINT("USBPORT_GetRegistryKeyValue: UseDriverKey - %x, SourceString - %S, LengthStr - %x, Buffer - %p, BufferLength - %x\n", UseDriverKey, SourceString, LengthStr, Buffer, BufferLength); if (UseDriverKey) { Status = IoOpenDeviceRegistryKey(PdoDevice, PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_ALL, &KeyHandle); } else { Status = IoOpenDeviceRegistryKey(PdoDevice, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &KeyHandle); } if (NT_SUCCESS(Status)) { RtlInitUnicodeString(&ValueName, SourceString); LengthKey = sizeof(KEY_VALUE_FULL_INFORMATION) + LengthStr + BufferLength; KeyValue = ExAllocatePoolWithTag(PagedPool, LengthKey, USB_PORT_TAG); if (KeyValue) { RtlZeroMemory(KeyValue, LengthKey); Status = ZwQueryValueKey(KeyHandle, &ValueName, KeyValueFullInformation, KeyValue, LengthKey, &LengthKey); if (NT_SUCCESS(Status)) { RtlCopyMemory(Buffer, (PUCHAR)KeyValue + KeyValue->DataOffset, BufferLength); } ExFreePoolWithTag(KeyValue, USB_PORT_TAG); } ZwClose(KeyHandle); } return Status; } MPSTATUS NTAPI USBPORT_GetMiniportRegistryKeyValue(IN PVOID MiniPortExtension, IN BOOL UseDriverKey, IN PCWSTR SourceString, IN SIZE_T LengthStr, IN PVOID Buffer, IN SIZE_T BufferLength) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT FdoDevice; NTSTATUS Status; DPRINT("USBPORT_GetMiniportRegistryKeyValue: MiniPortExtension - %p, UseDriverKey - %x, SourceString - %S, LengthStr - %x, Buffer - %p, BufferLength - %x\n", MiniPortExtension, UseDriverKey, SourceString, LengthStr, Buffer, BufferLength); FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension - sizeof(USBPORT_DEVICE_EXTENSION)); FdoDevice = FdoExtension->CommonExtension.SelfDevice; Status = USBPORT_GetRegistryKeyValueFullInfo(FdoDevice, FdoExtension->CommonExtension.LowerPdoDevice, UseDriverKey, SourceString, LengthStr, Buffer, BufferLength); return USBPORT_NtStatusToMpStatus(Status); } NTSTATUS NTAPI USBPORT_GetSetConfigSpaceData(IN PDEVICE_OBJECT FdoDevice, IN BOOLEAN IsReadData, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length) { PUSBPORT_DEVICE_EXTENSION FdoExtension; ULONG BytesReadWrite; DPRINT("USBPORT_GetSetConfigSpaceData ...\n"); FdoExtension = FdoDevice->DeviceExtension; BytesReadWrite = Length; if (IsReadData) { RtlZeroMemory(Buffer, Length); BytesReadWrite = (*FdoExtension->BusInterface.GetBusData) (FdoExtension->BusInterface.Context, PCI_WHICHSPACE_CONFIG, Buffer, Offset, Length); } else { BytesReadWrite = (*FdoExtension->BusInterface.SetBusData) (FdoExtension->BusInterface.Context, PCI_WHICHSPACE_CONFIG, Buffer, Offset, Length); } if (BytesReadWrite == Length) { return STATUS_SUCCESS; } return STATUS_UNSUCCESSFUL; } MPSTATUS NTAPI USBPORT_ReadWriteConfigSpace(IN PVOID MiniPortExtension, IN BOOLEAN IsReadData, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length) { NTSTATUS Status; PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT FdoDevice; DPRINT("USBPORT_ReadWriteConfigSpace: ...\n"); //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION)); FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension - sizeof(USBPORT_DEVICE_EXTENSION)); FdoDevice = FdoExtension->CommonExtension.SelfDevice; Status = USBPORT_GetSetConfigSpaceData(FdoDevice, IsReadData, Buffer, Offset, Length); return USBPORT_NtStatusToMpStatus(Status); } NTSTATUS NTAPI USBPORT_USBDStatusToNtStatus(IN PURB Urb, IN USBD_STATUS USBDStatus) { NTSTATUS Status; if (USBD_ERROR(USBDStatus)) { DPRINT1("USBPORT_USBDStatusToNtStatus: Urb - %p, USBDStatus - %x\n", Urb, USBDStatus); } if (Urb) Urb->UrbHeader.Status = USBDStatus; switch (USBDStatus) { case USBD_STATUS_SUCCESS: Status = STATUS_SUCCESS; break; case USBD_STATUS_INSUFFICIENT_RESOURCES: Status = STATUS_INSUFFICIENT_RESOURCES; break; case USBD_STATUS_DEVICE_GONE: Status = STATUS_DEVICE_NOT_CONNECTED; break; case USBD_STATUS_CANCELED: Status = STATUS_CANCELLED; break; case USBD_STATUS_NOT_SUPPORTED: Status = STATUS_NOT_SUPPORTED; break; case USBD_STATUS_INVALID_URB_FUNCTION: case USBD_STATUS_INVALID_PARAMETER: case USBD_STATUS_INVALID_PIPE_HANDLE: case USBD_STATUS_BAD_START_FRAME: Status = STATUS_INVALID_PARAMETER; break; default: if (USBD_ERROR(USBDStatus)) Status = STATUS_UNSUCCESSFUL; else Status = STATUS_SUCCESS; break; } return Status; } NTSTATUS NTAPI USBPORT_Wait(IN PVOID MiniPortExtension, IN ULONG Milliseconds) { LARGE_INTEGER Interval = {{0, 0}}; DPRINT("USBPORT_Wait: Milliseconds - %x\n", Milliseconds); Interval.QuadPart -= 10000 * Milliseconds + (KeQueryTimeIncrement() - 1); return KeDelayExecutionThread(KernelMode, FALSE, &Interval); } VOID NTAPI USBPORT_MiniportInterrupts(IN PDEVICE_OBJECT FdoDevice, IN BOOLEAN IsEnable) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; BOOLEAN IsLock; KIRQL OldIrql; DPRINT_INT("USBPORT_MiniportInterrupts: IsEnable - %p\n", IsEnable); FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; IsLock = (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_NOT_LOCK_INT) == 0; if (IsLock) KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); if (IsEnable) { FdoExtension->Flags |= USBPORT_FLAG_INTERRUPT_ENABLED; Packet->EnableInterrupts(FdoExtension->MiniPortExt); } else { Packet->DisableInterrupts(FdoExtension->MiniPortExt); FdoExtension->Flags &= ~USBPORT_FLAG_INTERRUPT_ENABLED; } if (IsLock) KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); } VOID NTAPI USBPORT_SoftInterruptDpc(IN PRKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT_INT("USBPORT_SoftInterruptDpc: ...\n"); FdoDevice = DeferredContext; FdoExtension = FdoDevice->DeviceExtension; if (!KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, (PVOID)1)) { InterlockedDecrement(&FdoExtension->IsrDpcCounter); } } VOID NTAPI USBPORT_SoftInterrupt(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; LARGE_INTEGER DueTime = {{0, 0}}; DPRINT_INT("USBPORT_SoftInterrupt: ...\n"); FdoExtension = FdoDevice->DeviceExtension; KeInitializeTimer(&FdoExtension->TimerSoftInterrupt); KeInitializeDpc(&FdoExtension->SoftInterruptDpc, USBPORT_SoftInterruptDpc, FdoDevice); DueTime.QuadPart -= 10000 + (KeQueryTimeIncrement() - 1); KeSetTimer(&FdoExtension->TimerSoftInterrupt, DueTime, &FdoExtension->SoftInterruptDpc); } VOID NTAPI USBPORT_InvalidateControllerHandler(IN PDEVICE_OBJECT FdoDevice, IN ULONG Type) { PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT_CORE("USBPORT_InvalidateControllerHandler: Invalidate Type - %x\n", Type); FdoExtension = FdoDevice->DeviceExtension; switch (Type) { case USBPORT_INVALIDATE_CONTROLLER_RESET: DPRINT1("USBPORT_InvalidateControllerHandler: INVALIDATE_CONTROLLER_RESET UNIMPLEMENTED. FIXME.\n"); break; case USBPORT_INVALIDATE_CONTROLLER_SURPRISE_REMOVE: DPRINT1("USBPORT_InvalidateControllerHandler: INVALIDATE_CONTROLLER_SURPRISE_REMOVE UNIMPLEMENTED. FIXME.\n"); break; case USBPORT_INVALIDATE_CONTROLLER_SOFT_INTERRUPT: if (InterlockedIncrement(&FdoExtension->IsrDpcCounter)) { InterlockedDecrement(&FdoExtension->IsrDpcCounter); } else { USBPORT_SoftInterrupt(FdoDevice); } break; } } ULONG NTAPI USBPORT_InvalidateController(IN PVOID MiniPortExtension, IN ULONG Type) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT FdoDevice; DPRINT("USBPORT_InvalidateController: Invalidate Type - %x\n", Type); //FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION)); FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension - sizeof(USBPORT_DEVICE_EXTENSION)); FdoDevice = FdoExtension->CommonExtension.SelfDevice; USBPORT_InvalidateControllerHandler(FdoDevice, Type); return 0; } ULONG NTAPI USBPORT_NotifyDoubleBuffer(IN PVOID MiniPortExtension, IN PVOID MiniPortTransfer, IN PVOID Buffer, IN SIZE_T Length) { DPRINT1("USBPORT_NotifyDoubleBuffer: UNIMPLEMENTED. FIXME.\n"); return 0; } VOID NTAPI USBPORT_WorkerRequestDpc(IN PRKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT("USBPORT_WorkerRequestDpc: ...\n"); FdoDevice = DeferredContext; FdoExtension = FdoDevice->DeviceExtension; if (!InterlockedIncrement(&FdoExtension->IsrDpcHandlerCounter)) { USBPORT_DpcHandler(FdoDevice); } InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter); } VOID NTAPI USBPORT_DoneTransfer(IN PUSBPORT_TRANSFER Transfer) { PUSBPORT_ENDPOINT Endpoint; PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; PURB Urb; PIRP Irp; KIRQL CancelIrql; KIRQL OldIrql; DPRINT_CORE("USBPORT_DoneTransfer: Transfer - %p\n", Transfer); Endpoint = Transfer->Endpoint; FdoDevice = Endpoint->FdoDevice; FdoExtension = FdoDevice->DeviceExtension; Urb = Transfer->Urb; Irp = Transfer->Irp; KeAcquireSpinLock(&FdoExtension->FlushTransferSpinLock, &OldIrql); if (Irp) { IoAcquireCancelSpinLock(&CancelIrql); IoSetCancelRoutine(Irp, NULL); IoReleaseCancelSpinLock(CancelIrql); USBPORT_RemoveActiveTransferIrp(FdoDevice, Irp); } KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql); USBPORT_USBDStatusToNtStatus(Transfer->Urb, Transfer->USBDStatus); USBPORT_CompleteTransfer(Urb, Urb->UrbHeader.Status); DPRINT_CORE("USBPORT_DoneTransfer: exit\n"); } VOID NTAPI USBPORT_FlushDoneTransfers(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PLIST_ENTRY DoneTransferList; PUSBPORT_TRANSFER Transfer; PUSBPORT_ENDPOINT Endpoint; ULONG TransferCount; KIRQL OldIrql; BOOLEAN IsHasTransfers; DPRINT_CORE("USBPORT_FlushDoneTransfers: ...\n"); FdoExtension = FdoDevice->DeviceExtension; DoneTransferList = &FdoExtension->DoneTransferList; while (TRUE) { KeAcquireSpinLock(&FdoExtension->DoneTransferSpinLock, &OldIrql); if (IsListEmpty(DoneTransferList)) break; Transfer = CONTAINING_RECORD(DoneTransferList->Flink, USBPORT_TRANSFER, TransferLink); RemoveHeadList(DoneTransferList); KeReleaseSpinLock(&FdoExtension->DoneTransferSpinLock, OldIrql); if (Transfer) { Endpoint = Transfer->Endpoint; if ((Transfer->Flags & TRANSFER_FLAG_SPLITED)) { USBPORT_DoneSplitTransfer(Transfer); } else { USBPORT_DoneTransfer(Transfer); } IsHasTransfers = USBPORT_EndpointHasQueuedTransfers(FdoDevice, Endpoint, &TransferCount); if (IsHasTransfers && !TransferCount) { USBPORT_InvalidateEndpointHandler(FdoDevice, Endpoint, INVALIDATE_ENDPOINT_WORKER_DPC); } } } KeReleaseSpinLock(&FdoExtension->DoneTransferSpinLock, OldIrql); } VOID NTAPI USBPORT_TransferFlushDpc(IN PRKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PDEVICE_OBJECT FdoDevice; DPRINT_CORE("USBPORT_TransferFlushDpc: ...\n"); FdoDevice = DeferredContext; USBPORT_FlushDoneTransfers(FdoDevice); } BOOLEAN NTAPI USBPORT_QueueDoneTransfer(IN PUSBPORT_TRANSFER Transfer, IN USBD_STATUS USBDStatus) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; DPRINT_CORE("USBPORT_QueueDoneTransfer: Transfer - %p, USBDStatus - %p\n", Transfer, USBDStatus); FdoDevice = Transfer->Endpoint->FdoDevice; FdoExtension = FdoDevice->DeviceExtension; RemoveEntryList(&Transfer->TransferLink); Transfer->USBDStatus = USBDStatus; ExInterlockedInsertTailList(&FdoExtension->DoneTransferList, &Transfer->TransferLink, &FdoExtension->DoneTransferSpinLock); return KeInsertQueueDpc(&FdoExtension->TransferFlushDpc, NULL, NULL); } VOID NTAPI USBPORT_DpcHandler(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_ENDPOINT Endpoint; PLIST_ENTRY Entry; LIST_ENTRY List; LONG LockCounter; DPRINT_CORE("USBPORT_DpcHandler: ...\n"); FdoExtension = FdoDevice->DeviceExtension; InitializeListHead(&List); KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); Entry = FdoExtension->EndpointList.Flink; while (Entry && Entry != &FdoExtension->EndpointList) { Endpoint = CONTAINING_RECORD(Entry, USBPORT_ENDPOINT, EndpointLink); LockCounter = InterlockedIncrement(&Endpoint->LockCounter); if (USBPORT_GetEndpointState(Endpoint) != USBPORT_ENDPOINT_ACTIVE || LockCounter || Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0) { InterlockedDecrement(&Endpoint->LockCounter); } else { InsertTailList(&List, &Endpoint->DispatchLink); if (Endpoint->WorkerLink.Flink && Endpoint->WorkerLink.Blink) { RemoveEntryList(&Endpoint->WorkerLink); Endpoint->WorkerLink.Flink = NULL; Endpoint->WorkerLink.Blink = NULL; } } Entry = Endpoint->EndpointLink.Flink; } KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); while (!IsListEmpty(&List)) { Endpoint = CONTAINING_RECORD(List.Flink, USBPORT_ENDPOINT, DispatchLink); RemoveEntryList(List.Flink); Endpoint->DispatchLink.Flink = NULL; Endpoint->DispatchLink.Blink = NULL; USBPORT_EndpointWorker(Endpoint, TRUE); USBPORT_FlushPendingTransfers(Endpoint); } KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); if (!IsListEmpty(&FdoExtension->WorkerList)) { USBPORT_SignalWorkerThread(FdoDevice); } KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); USBPORT_FlushDoneTransfers(FdoDevice); } VOID NTAPI USBPORT_IsrDpcHandler(IN PDEVICE_OBJECT FdoDevice, IN BOOLEAN IsDpcHandler) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; PUSBPORT_ENDPOINT Endpoint; PLIST_ENTRY List; ULONG FrameNumber; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); DPRINT_CORE("USBPORT_IsrDpcHandler: IsDpcHandler - %x\n", IsDpcHandler); FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; if (InterlockedIncrement(&FdoExtension->IsrDpcHandlerCounter)) { KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL); InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter); return; } for (List = ExInterlockedRemoveHeadList(&FdoExtension->EpStateChangeList, &FdoExtension->EpStateChangeSpinLock); List != NULL; List = ExInterlockedRemoveHeadList(&FdoExtension->EpStateChangeList, &FdoExtension->EpStateChangeSpinLock)) { Endpoint = CONTAINING_RECORD(List, USBPORT_ENDPOINT, StateChangeLink); DPRINT_CORE("USBPORT_IsrDpcHandler: Endpoint - %p\n", Endpoint); KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock); KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); FrameNumber = Packet->Get32BitFrameNumber(FdoExtension->MiniPortExt); KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); if (FrameNumber <= Endpoint->FrameNumber && !(Endpoint->Flags & ENDPOINT_FLAG_NUKE)) { KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); ExInterlockedInsertHeadList(&FdoExtension->EpStateChangeList, &Endpoint->StateChangeLink, &FdoExtension->EpStateChangeSpinLock); KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportSpinLock); Packet->InterruptNextSOF(FdoExtension->MiniPortExt); KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportSpinLock); break; } KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock); KeAcquireSpinLockAtDpcLevel(&Endpoint->StateChangeSpinLock); Endpoint->StateLast = Endpoint->StateNext; KeReleaseSpinLockFromDpcLevel(&Endpoint->StateChangeSpinLock); DPRINT_CORE("USBPORT_IsrDpcHandler: Endpoint->StateLast - %x\n", Endpoint->StateLast); if (IsDpcHandler) { USBPORT_InvalidateEndpointHandler(FdoDevice, Endpoint, INVALIDATE_ENDPOINT_ONLY); } else { USBPORT_InvalidateEndpointHandler(FdoDevice, Endpoint, INVALIDATE_ENDPOINT_WORKER_THREAD); } } if (IsDpcHandler) { USBPORT_DpcHandler(FdoDevice); } InterlockedDecrement(&FdoExtension->IsrDpcHandlerCounter); } VOID NTAPI USBPORT_IsrDpc(IN PRKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; BOOLEAN InterruptEnable; DPRINT_INT("USBPORT_IsrDpc: DeferredContext - %p, SystemArgument2 - %p\n", DeferredContext, SystemArgument2); FdoDevice = DeferredContext; FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; if (SystemArgument2) { InterlockedDecrement(&FdoExtension->IsrDpcCounter); } KeAcquireSpinLockAtDpcLevel(&FdoExtension->MiniportInterruptsSpinLock); InterruptEnable = (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED) == USBPORT_FLAG_INTERRUPT_ENABLED; Packet->InterruptDpc(FdoExtension->MiniPortExt, InterruptEnable); KeReleaseSpinLockFromDpcLevel(&FdoExtension->MiniportInterruptsSpinLock); if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND && FdoExtension->TimerFlags & USBPORT_TMFLAG_WAKE) { USBPORT_CompletePdoWaitWake(FdoDevice); } else { USBPORT_IsrDpcHandler(FdoDevice, TRUE); } DPRINT_INT("USBPORT_IsrDpc: exit\n"); } BOOLEAN NTAPI USBPORT_InterruptService(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; BOOLEAN Result = FALSE; FdoDevice = ServiceContext; FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; DPRINT_INT("USBPORT_InterruptService: FdoExtension[%p]->Flags - %08X\n", FdoExtension, FdoExtension->Flags); if (FdoExtension->Flags & USBPORT_FLAG_INTERRUPT_ENABLED && FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) { Result = Packet->InterruptService(FdoExtension->MiniPortExt); if (Result) { KeInsertQueueDpc(&FdoExtension->IsrDpc, NULL, NULL); } } DPRINT_INT("USBPORT_InterruptService: return - %x\n", Result); return Result; } VOID NTAPI USBPORT_SignalWorkerThread(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; KIRQL OldIrql; DPRINT_CORE("USBPORT_SignalWorkerThread ...\n"); FdoExtension = FdoDevice->DeviceExtension; KeAcquireSpinLock(&FdoExtension->WorkerThreadEventSpinLock, &OldIrql); KeSetEvent(&FdoExtension->WorkerThreadEvent, EVENT_INCREMENT, FALSE); KeReleaseSpinLock(&FdoExtension->WorkerThreadEventSpinLock, OldIrql); } VOID NTAPI USBPORT_WorkerThreadHandler(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; PLIST_ENTRY workerList; KIRQL OldIrql; PUSBPORT_ENDPOINT Endpoint; LIST_ENTRY list; BOOLEAN Result; DPRINT_CORE("USBPORT_WorkerThreadHandler: ...\n"); FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) { Packet->CheckController(FdoExtension->MiniPortExt); } KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); InitializeListHead(&list); USBPORT_FlushAllEndpoints(FdoDevice); while (TRUE) { KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); workerList = &FdoExtension->WorkerList; if (IsListEmpty(workerList)) break; Endpoint = CONTAINING_RECORD(workerList->Flink, USBPORT_ENDPOINT, WorkerLink); DPRINT_CORE("USBPORT_WorkerThreadHandler: Endpoint - %p\n", Endpoint); RemoveHeadList(workerList); Endpoint->WorkerLink.Blink = NULL; Endpoint->WorkerLink.Flink = NULL; KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); Result = USBPORT_EndpointWorker(Endpoint, FALSE); KeAcquireSpinLockAtDpcLevel(&FdoExtension->EndpointListSpinLock); if (Result) { if (Endpoint->FlushAbortLink.Flink == NULL || Endpoint->FlushAbortLink.Blink == NULL) { InsertTailList(&list, &Endpoint->FlushAbortLink); } } while (!IsListEmpty(&list)) { Endpoint = CONTAINING_RECORD(list.Flink, USBPORT_ENDPOINT, FlushAbortLink); RemoveHeadList(&list); Endpoint->FlushAbortLink.Flink = NULL; Endpoint->FlushAbortLink.Blink = NULL; if (Endpoint->WorkerLink.Flink == NULL || Endpoint->WorkerLink.Blink == NULL) { InsertTailList(&FdoExtension->WorkerList, &Endpoint->WorkerLink); USBPORT_SignalWorkerThread(FdoDevice); } } KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); KeLowerIrql(OldIrql); } KeReleaseSpinLockFromDpcLevel(&FdoExtension->EndpointListSpinLock); KeLowerIrql(OldIrql); USBPORT_FlushClosedEndpointList(FdoDevice); } VOID NTAPI USBPORT_DoRootHubCallback(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT PdoDevice; PUSBPORT_RHDEVICE_EXTENSION PdoExtension; PRH_INIT_CALLBACK RootHubInitCallback; PVOID RootHubInitContext; FdoExtension = FdoDevice->DeviceExtension; DPRINT("USBPORT_DoRootHubCallback: FdoDevice - %p\n", FdoDevice); PdoDevice = FdoExtension->RootHubPdo; if (PdoDevice) { PdoExtension = PdoDevice->DeviceExtension; RootHubInitContext = PdoExtension->RootHubInitContext; RootHubInitCallback = PdoExtension->RootHubInitCallback; PdoExtension->RootHubInitCallback = NULL; PdoExtension->RootHubInitContext = NULL; if (RootHubInitCallback) { RootHubInitCallback(RootHubInitContext); } } DPRINT("USBPORT_DoRootHubCallback: exit\n"); } VOID NTAPI USBPORT_SynchronizeRootHubCallback(IN PDEVICE_OBJECT FdoDevice, IN PDEVICE_OBJECT Usb2FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; PUSBPORT_DEVICE_EXTENSION Usb2FdoExtension; PDEVICE_RELATIONS CompanionControllersList; PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension; PDEVICE_OBJECT * Entry; ULONG ix; DPRINT("USBPORT_SynchronizeRootHubCallback: FdoDevice - %p, Usb2FdoDevice - %p\n", FdoDevice, Usb2FdoDevice); FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; if (Usb2FdoDevice == NULL && !(Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)) { /* Not Companion USB11 Controller */ USBPORT_DoRootHubCallback(FdoDevice); FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1); DPRINT("USBPORT_SynchronizeRootHubCallback: exit\n"); return; } /* USB2 or Companion USB11 */ DPRINT("USBPORT_SynchronizeRootHubCallback: FdoExtension->Flags - %p\n", FdoExtension->Flags); if (!(FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC)) { KeWaitForSingleObject(&FdoExtension->ControllerSemaphore, Executive, KernelMode, FALSE, NULL); FdoExtension->Flags |= USBPORT_FLAG_PWR_AND_CHIRP_LOCK; if (!(FdoExtension->Flags & (USBPORT_FLAG_HC_SUSPEND | USBPORT_FLAG_POWER_AND_CHIRP_OK))) { USBPORT_RootHubPowerAndChirpAllCcPorts(FdoDevice); FdoExtension->Flags |= USBPORT_FLAG_POWER_AND_CHIRP_OK; } FdoExtension->Flags &= ~USBPORT_FLAG_PWR_AND_CHIRP_LOCK; KeReleaseSemaphore(&FdoExtension->ControllerSemaphore, LOW_REALTIME_PRIORITY, 1, FALSE); CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice, FALSE, TRUE); if (CompanionControllersList) { Entry = &CompanionControllersList->Objects[0]; for (ix = 0; ix < CompanionControllersList->Count; ++ix) { CompanionFdoExtension = ((*Entry)->DeviceExtension); InterlockedCompareExchange(&CompanionFdoExtension->RHInitCallBackLock, 0, 1); ++Entry; } ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG); } USBPORT_DoRootHubCallback(FdoDevice); FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 0, 1); } else { Usb2FdoExtension = Usb2FdoDevice->DeviceExtension; USBPORT_Wait(FdoDevice, 50); while (FdoExtension->RHInitCallBackLock) { USBPORT_Wait(FdoDevice, 10); Usb2FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK; USBPORT_SignalWorkerThread(Usb2FdoDevice); } USBPORT_DoRootHubCallback(FdoDevice); FdoExtension->Flags &= ~USBPORT_FLAG_RH_INIT_CALLBACK; } DPRINT("USBPORT_SynchronizeRootHubCallback: exit\n"); } VOID NTAPI USBPORT_WorkerThread(IN PVOID StartContext) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; LARGE_INTEGER OldTime; LARGE_INTEGER NewTime; KIRQL OldIrql; DPRINT_CORE("USBPORT_WorkerThread ...\n"); FdoDevice = StartContext; FdoExtension = FdoDevice->DeviceExtension; FdoExtension->WorkerThread = KeGetCurrentThread(); do { KeQuerySystemTime(&OldTime); KeWaitForSingleObject(&FdoExtension->WorkerThreadEvent, Suspended, KernelMode, FALSE, NULL); if (FdoExtension->Flags & USBPORT_FLAG_WORKER_THREAD_EXIT) { break; } KeQuerySystemTime(&NewTime); KeAcquireSpinLock(&FdoExtension->WorkerThreadEventSpinLock, &OldIrql); KeClearEvent(&FdoExtension->WorkerThreadEvent); KeReleaseSpinLock(&FdoExtension->WorkerThreadEventSpinLock, OldIrql); DPRINT_CORE("USBPORT_WorkerThread: run\n"); if (FdoExtension->MiniPortFlags & USBPORT_MPFLAG_INTERRUPTS_ENABLED) { USBPORT_DoSetPowerD0(FdoDevice); if (FdoExtension->Flags & USBPORT_FLAG_RH_INIT_CALLBACK) { PDEVICE_OBJECT USB2FdoDevice = NULL; USB2FdoDevice = USBPORT_FindUSB2Controller(FdoDevice); USBPORT_SynchronizeRootHubCallback(FdoDevice, USB2FdoDevice); } } USBPORT_WorkerThreadHandler(FdoDevice); } while (!(FdoExtension->Flags & USBPORT_FLAG_WORKER_THREAD_ON)); PsTerminateSystemThread(0); } NTSTATUS NTAPI USBPORT_CreateWorkerThread(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; NTSTATUS Status; DPRINT("USBPORT_CreateWorkerThread ...\n"); FdoExtension = FdoDevice->DeviceExtension; FdoExtension->Flags &= ~USBPORT_FLAG_WORKER_THREAD_ON; KeInitializeEvent(&FdoExtension->WorkerThreadEvent, NotificationEvent, FALSE); Status = PsCreateSystemThread(&FdoExtension->WorkerThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, USBPORT_WorkerThread, (PVOID)FdoDevice); return Status; } VOID NTAPI USBPORT_StopWorkerThread(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; NTSTATUS Status; DPRINT("USBPORT_StopWorkerThread ...\n"); FdoExtension = FdoDevice->DeviceExtension; FdoExtension->Flags |= USBPORT_FLAG_WORKER_THREAD_EXIT; USBPORT_SignalWorkerThread(FdoDevice); Status = ZwWaitForSingleObject(FdoExtension->WorkerThreadHandle, FALSE, NULL); NT_ASSERT(Status == STATUS_SUCCESS); } VOID NTAPI USBPORT_SynchronizeControllersStart(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT PdoDevice; PUSBPORT_RHDEVICE_EXTENSION PdoExtension; PDEVICE_OBJECT USB2FdoDevice = NULL; PUSBPORT_DEVICE_EXTENSION USB2FdoExtension; BOOLEAN IsOn; DPRINT_TIMER("USBPORT_SynchronizeControllersStart: FdoDevice - %p\n", FdoDevice); FdoExtension = FdoDevice->DeviceExtension; PdoDevice = FdoExtension->RootHubPdo; if (!PdoDevice) { return; } PdoExtension = PdoDevice->DeviceExtension; if (PdoExtension->RootHubInitCallback == NULL || FdoExtension->Flags & USBPORT_FLAG_RH_INIT_CALLBACK) { return; } DPRINT_TIMER("USBPORT_SynchronizeControllersStart: Flags - %p\n", FdoExtension->Flags); if (FdoExtension->Flags & USBPORT_FLAG_COMPANION_HC) { IsOn = FALSE; USB2FdoDevice = USBPORT_FindUSB2Controller(FdoDevice); DPRINT_TIMER("USBPORT_SynchronizeControllersStart: USB2FdoDevice - %p\n", USB2FdoDevice); if (USB2FdoDevice) { USB2FdoExtension = USB2FdoDevice->DeviceExtension; if (USB2FdoExtension->CommonExtension.PnpStateFlags & USBPORT_PNP_STATE_STARTED) { IsOn = TRUE; } } if (!(FdoExtension->Flags & USBPORT_FLAG_NO_HACTION)) { goto Start; } USB2FdoDevice = NULL; } IsOn = TRUE; Start: if (IsOn && !InterlockedCompareExchange(&FdoExtension->RHInitCallBackLock, 1, 0)) { FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK; USBPORT_SignalWorkerThread(FdoDevice); if (USB2FdoDevice) { USB2FdoExtension = USB2FdoDevice->DeviceExtension; USB2FdoExtension->Flags |= USBPORT_FLAG_RH_INIT_CALLBACK; USBPORT_SignalWorkerThread(USB2FdoDevice); } } DPRINT_TIMER("USBPORT_SynchronizeControllersStart: exit\n"); } VOID NTAPI USBPORT_TimerDpc(IN PRKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_REGISTRATION_PACKET Packet; LARGE_INTEGER DueTime = {{0, 0}}; ULONG TimerFlags; PTIMER_WORK_QUEUE_ITEM IdleQueueItem; KIRQL OldIrql; KIRQL TimerOldIrql; DPRINT_TIMER("USBPORT_TimerDpc: Dpc - %p, DeferredContext - %p\n", Dpc, DeferredContext); FdoDevice = DeferredContext; FdoExtension = FdoDevice->DeviceExtension; Packet = &FdoExtension->MiniPortInterface->Packet; KeAcquireSpinLock(&FdoExtension->TimerFlagsSpinLock, &TimerOldIrql); TimerFlags = FdoExtension->TimerFlags; DPRINT_TIMER("USBPORT_TimerDpc: Flags - %p, TimerFlags - %p\n", FdoExtension->Flags, TimerFlags); if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND && FdoExtension->Flags & USBPORT_FLAG_HC_WAKE_SUPPORT && !(TimerFlags & USBPORT_TMFLAG_HC_RESUME)) { KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); Packet->PollController(FdoExtension->MiniPortExt); KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); } USBPORT_SynchronizeControllersStart(FdoDevice); if (TimerFlags & USBPORT_TMFLAG_HC_SUSPENDED) { USBPORT_BadRequestFlush(FdoDevice); goto Exit; } KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND)) { Packet->CheckController(FdoExtension->MiniPortExt); } KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); if (FdoExtension->Flags & USBPORT_FLAG_HC_POLLING) { KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql); Packet->PollController(FdoExtension->MiniPortExt); KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql); } USBPORT_IsrDpcHandler(FdoDevice, FALSE); DPRINT_TIMER("USBPORT_TimerDpc: USBPORT_TimeoutAllEndpoints UNIMPLEMENTED.\n"); //USBPORT_TimeoutAllEndpoints(FdoDevice); DPRINT_TIMER("USBPORT_TimerDpc: USBPORT_CheckIdleEndpoints UNIMPLEMENTED.\n"); //USBPORT_CheckIdleEndpoints(FdoDevice); USBPORT_BadRequestFlush(FdoDevice); if (FdoExtension->IdleLockCounter > -1 && !(TimerFlags & USBPORT_TMFLAG_IDLE_QUEUEITEM_ON)) { IdleQueueItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(TIMER_WORK_QUEUE_ITEM), USB_PORT_TAG); DPRINT("USBPORT_TimerDpc: IdleLockCounter - %x, IdleQueueItem - %p\n", FdoExtension->IdleLockCounter, IdleQueueItem); if (IdleQueueItem) { RtlZeroMemory(IdleQueueItem, sizeof(TIMER_WORK_QUEUE_ITEM)); IdleQueueItem->WqItem.List.Flink = NULL; IdleQueueItem->WqItem.WorkerRoutine = USBPORT_DoIdleNotificationCallback; IdleQueueItem->WqItem.Parameter = IdleQueueItem; IdleQueueItem->FdoDevice = FdoDevice; IdleQueueItem->Context = 0; FdoExtension->TimerFlags |= USBPORT_TMFLAG_IDLE_QUEUEITEM_ON; ExQueueWorkItem(&IdleQueueItem->WqItem, CriticalWorkQueue); } } Exit: KeReleaseSpinLock(&FdoExtension->TimerFlagsSpinLock, TimerOldIrql); if (TimerFlags & USBPORT_TMFLAG_TIMER_QUEUED) { DueTime.QuadPart -= FdoExtension->TimerValue * 10000 + (KeQueryTimeIncrement() - 1); KeSetTimer(&FdoExtension->TimerObject, DueTime, &FdoExtension->TimerDpc); } DPRINT_TIMER("USBPORT_TimerDpc: exit\n"); } BOOLEAN NTAPI USBPORT_StartTimer(IN PDEVICE_OBJECT FdoDevice, IN ULONG Time) { PUSBPORT_DEVICE_EXTENSION FdoExtension; LARGE_INTEGER DueTime = {{0, 0}}; ULONG TimeIncrement; BOOLEAN Result; DPRINT_TIMER("USBPORT_StartTimer: FdoDevice - %p, Time - %x\n", FdoDevice, Time); FdoExtension = FdoDevice->DeviceExtension; TimeIncrement = KeQueryTimeIncrement(); FdoExtension->TimerFlags |= USBPORT_TMFLAG_TIMER_QUEUED; FdoExtension->TimerValue = Time; KeInitializeTimer(&FdoExtension->TimerObject); KeInitializeDpc(&FdoExtension->TimerDpc, USBPORT_TimerDpc, FdoDevice); DueTime.QuadPart -= 10000 * Time + (TimeIncrement - 1); Result = KeSetTimer(&FdoExtension->TimerObject, DueTime, &FdoExtension->TimerDpc); return Result; } PUSBPORT_COMMON_BUFFER_HEADER NTAPI USBPORT_AllocateCommonBuffer(IN PDEVICE_OBJECT FdoDevice, IN SIZE_T BufferLength) { PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer = NULL; PUSBPORT_DEVICE_EXTENSION FdoExtension; PDMA_ADAPTER DmaAdapter; PDMA_OPERATIONS DmaOperations; SIZE_T HeaderSize; ULONG Length = 0; ULONG LengthPadded; PHYSICAL_ADDRESS LogicalAddress; ULONG_PTR BaseVA; ULONG_PTR StartBufferVA; ULONG StartBufferPA; DPRINT("USBPORT_AllocateCommonBuffer: FdoDevice - %p, BufferLength - %p\n", FdoDevice, BufferLength); if (BufferLength == 0) goto Exit; FdoExtension = FdoDevice->DeviceExtension; DmaAdapter = FdoExtension->DmaAdapter; DmaOperations = DmaAdapter->DmaOperations; HeaderSize = sizeof(USBPORT_COMMON_BUFFER_HEADER); Length = ROUND_TO_PAGES(BufferLength + HeaderSize); LengthPadded = Length - (BufferLength + HeaderSize); BaseVA = (ULONG_PTR)DmaOperations->AllocateCommonBuffer(DmaAdapter, Length, &LogicalAddress, TRUE); if (!BaseVA) goto Exit; StartBufferVA = BaseVA & ~(PAGE_SIZE - 1); StartBufferPA = LogicalAddress.LowPart & ~(PAGE_SIZE - 1); HeaderBuffer = (PUSBPORT_COMMON_BUFFER_HEADER)(StartBufferVA + BufferLength + LengthPadded); HeaderBuffer->Length = Length; HeaderBuffer->BaseVA = BaseVA; HeaderBuffer->LogicalAddress = LogicalAddress; HeaderBuffer->BufferLength = BufferLength + LengthPadded; HeaderBuffer->VirtualAddress = StartBufferVA; HeaderBuffer->PhysicalAddress = StartBufferPA; RtlZeroMemory((PVOID)StartBufferVA, BufferLength + LengthPadded); Exit: return HeaderBuffer; } VOID NTAPI USBPORT_FreeCommonBuffer(IN PDEVICE_OBJECT FdoDevice, IN PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDMA_ADAPTER DmaAdapter; PDMA_OPERATIONS DmaOperations; DPRINT("USBPORT_FreeCommonBuffer: ...\n"); FdoExtension = FdoDevice->DeviceExtension; DmaAdapter = FdoExtension->DmaAdapter; DmaOperations = DmaAdapter->DmaOperations; DmaOperations->FreeCommonBuffer(FdoExtension->DmaAdapter, HeaderBuffer->Length, HeaderBuffer->LogicalAddress, (PVOID)HeaderBuffer->VirtualAddress, TRUE); } PUSBPORT_MINIPORT_INTERFACE NTAPI USBPORT_FindMiniPort(IN PDRIVER_OBJECT DriverObject) { KIRQL OldIrql; PLIST_ENTRY List; PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; BOOLEAN IsFound = FALSE; DPRINT("USBPORT_FindMiniPort: ...\n"); KeAcquireSpinLock(&USBPORT_SpinLock, &OldIrql); for (List = USBPORT_MiniPortDrivers.Flink; List != &USBPORT_MiniPortDrivers; List = List->Flink) { MiniPortInterface = CONTAINING_RECORD(List, USBPORT_MINIPORT_INTERFACE, DriverLink); if (MiniPortInterface->DriverObject == DriverObject) { DPRINT("USBPORT_FindMiniPort: find MiniPortInterface - %p\n", MiniPortInterface); IsFound = TRUE; break; } } KeReleaseSpinLock(&USBPORT_SpinLock, OldIrql); if (IsFound) return MiniPortInterface; else return NULL; } NTSTATUS NTAPI USBPORT_AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) { NTSTATUS Status; PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; ULONG DeviceNumber = 0; WCHAR CharDeviceName[64]; UNICODE_STRING DeviceName; PDEVICE_OBJECT DeviceObject; PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_COMMON_DEVICE_EXTENSION FdoCommonExtension; PDEVICE_OBJECT LowerDevice; ULONG Length; DPRINT("USBPORT_AddDevice: DriverObject - %p, PhysicalDeviceObject - %p\n", DriverObject, PhysicalDeviceObject); MiniPortInterface = USBPORT_FindMiniPort(DriverObject); if (!MiniPortInterface) { DPRINT("USBPORT_AddDevice: USBPORT_FindMiniPort not found MiniPortInterface\n"); return STATUS_UNSUCCESSFUL; } while (TRUE) { /* Construct device name */ RtlStringCbPrintfW(CharDeviceName, sizeof(CharDeviceName), L"\\Device\\USBFDO-%d", DeviceNumber); RtlInitUnicodeString(&DeviceName, CharDeviceName); ASSERT(MiniPortInterface->Packet.MiniPortExtensionSize <= MAXULONG - sizeof(USBPORT_DEVICE_EXTENSION) - sizeof(USB2_HC_EXTENSION)); Length = (ULONG)(sizeof(USBPORT_DEVICE_EXTENSION) + MiniPortInterface->Packet.MiniPortExtensionSize + sizeof(USB2_HC_EXTENSION)); /* Create device */ Status = IoCreateDevice(DriverObject, Length, &DeviceName, FILE_DEVICE_CONTROLLER, 0, FALSE, &DeviceObject); /* Check for success */ if (NT_SUCCESS(Status)) break; /* Is there a device object with that same name */ if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION)) { /* Try the next name */ DeviceNumber++; continue; } /* Bail out on other errors */ if (!NT_SUCCESS(Status)) { DPRINT1("USBPORT_AddDevice: failed to create %wZ, Status %x\n", &DeviceName, Status); return Status; } } DPRINT("USBPORT_AddDevice: created device %p <%wZ>, Status %x\n", DeviceObject, &DeviceName, Status); FdoExtension = DeviceObject->DeviceExtension; FdoCommonExtension = &FdoExtension->CommonExtension; RtlZeroMemory(FdoExtension, sizeof(USBPORT_DEVICE_EXTENSION)); FdoCommonExtension->SelfDevice = DeviceObject; FdoCommonExtension->LowerPdoDevice = PhysicalDeviceObject; FdoCommonExtension->IsPDO = FALSE; LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); FdoCommonExtension->LowerDevice = LowerDevice; FdoCommonExtension->DevicePowerState = PowerDeviceD3; FdoExtension->MiniPortExt = (PVOID)((ULONG_PTR)FdoExtension + sizeof(USBPORT_DEVICE_EXTENSION)); if (MiniPortInterface->Packet.MiniPortFlags & USB_MINIPORT_FLAGS_USB2) { FdoExtension->Usb2Extension = (PUSB2_HC_EXTENSION)((ULONG_PTR)FdoExtension->MiniPortExt + MiniPortInterface->Packet.MiniPortExtensionSize); DPRINT("USBPORT_AddDevice: Usb2Extension - %p\n", FdoExtension->Usb2Extension); USB2_InitController(FdoExtension->Usb2Extension); } else { FdoExtension->Usb2Extension = NULL; } FdoExtension->MiniPortInterface = MiniPortInterface; FdoExtension->FdoNameNumber = DeviceNumber; KeInitializeSemaphore(&FdoExtension->DeviceSemaphore, 1, 1); KeInitializeSemaphore(&FdoExtension->ControllerSemaphore, 1, 1); InitializeListHead(&FdoExtension->EndpointList); InitializeListHead(&FdoExtension->DoneTransferList); InitializeListHead(&FdoExtension->WorkerList); InitializeListHead(&FdoExtension->EpStateChangeList); InitializeListHead(&FdoExtension->MapTransferList); InitializeListHead(&FdoExtension->DeviceHandleList); InitializeListHead(&FdoExtension->IdleIrpList); InitializeListHead(&FdoExtension->BadRequestList); InitializeListHead(&FdoExtension->EndpointClosedList); DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; return Status; } VOID NTAPI USBPORT_Unload(IN PDRIVER_OBJECT DriverObject) { PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; DPRINT1("USBPORT_Unload: FIXME!\n"); MiniPortInterface = USBPORT_FindMiniPort(DriverObject); if (!MiniPortInterface) { DPRINT("USBPORT_Unload: CRITICAL ERROR!!! Not found MiniPortInterface\n"); KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0); } DPRINT1("USBPORT_Unload: UNIMPLEMENTED. FIXME.\n"); //MiniPortInterface->DriverUnload(DriverObject); // Call MiniPort _HCI_Unload } VOID NTAPI USBPORT_MiniportCompleteTransfer(IN PVOID MiniPortExtension, IN PVOID MiniPortEndpoint, IN PVOID TransferParameters, IN USBD_STATUS USBDStatus, IN ULONG TransferLength) { PUSBPORT_TRANSFER Transfer; PUSBPORT_TRANSFER ParentTransfer; PUSBPORT_TRANSFER SplitTransfer; PLIST_ENTRY SplitHead; PLIST_ENTRY Entry; KIRQL OldIrql; DPRINT_CORE("USBPORT_MiniportCompleteTransfer: USBDStatus - %x, TransferLength - %x\n", USBDStatus, TransferLength); Transfer = CONTAINING_RECORD(TransferParameters, USBPORT_TRANSFER, TransferParameters); Transfer->Flags |= TRANSFER_FLAG_COMPLETED; Transfer->CompletedTransferLen = TransferLength; if (((Transfer->Flags & TRANSFER_FLAG_SPLITED) == 0) || TransferLength >= Transfer->TransferParameters.TransferBufferLength) { goto Exit; } ParentTransfer = Transfer->ParentTransfer; KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql); if (IsListEmpty(&ParentTransfer->SplitTransfersList)) { goto Exit; } SplitHead = &ParentTransfer->SplitTransfersList; Entry = SplitHead->Flink; while (Entry && !IsListEmpty(SplitHead)) { SplitTransfer = CONTAINING_RECORD(Entry, USBPORT_TRANSFER, SplitLink); if (!(SplitTransfer->Flags & TRANSFER_FLAG_SUBMITED)) { DPRINT1("USBPORT_MiniportCompleteTransfer: SplitTransfer->Flags - %X\n", SplitTransfer->Flags); //Add TRANSFER_FLAG_xxx } Entry = Entry->Flink; } KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql); Exit: USBPORT_QueueDoneTransfer(Transfer, USBDStatus); } VOID NTAPI USBPORT_AsyncTimerDpc(IN PRKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; PUSBPORT_ASYNC_CALLBACK_DATA AsyncCallbackData; DPRINT("USBPORT_AsyncTimerDpc: ...\n"); AsyncCallbackData = DeferredContext; FdoDevice = AsyncCallbackData->FdoDevice; FdoExtension = FdoDevice->DeviceExtension; (*AsyncCallbackData->CallbackFunction)(FdoExtension->MiniPortExt, &AsyncCallbackData->CallbackContext); ExFreePoolWithTag(AsyncCallbackData, USB_PORT_TAG); } ULONG NTAPI USBPORT_RequestAsyncCallback(IN PVOID MiniPortExtension, IN ULONG TimerValue, IN PVOID Buffer, IN SIZE_T Length, IN ASYNC_TIMER_CALLBACK * Callback) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT FdoDevice; PUSBPORT_ASYNC_CALLBACK_DATA AsyncCallbackData; LARGE_INTEGER DueTime = {{0, 0}}; DPRINT("USBPORT_RequestAsyncCallback: ...\n"); FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension - sizeof(USBPORT_DEVICE_EXTENSION)); FdoDevice = FdoExtension->CommonExtension.SelfDevice; AsyncCallbackData = ExAllocatePoolWithTag(NonPagedPool, sizeof(USBPORT_ASYNC_CALLBACK_DATA) + Length, USB_PORT_TAG); if (!AsyncCallbackData) { DPRINT1("USBPORT_RequestAsyncCallback: Not allocated AsyncCallbackData!\n"); return 0; } RtlZeroMemory(AsyncCallbackData, sizeof(USBPORT_ASYNC_CALLBACK_DATA) + Length); if (Length) { RtlCopyMemory(&AsyncCallbackData->CallbackContext, Buffer, Length); } AsyncCallbackData->FdoDevice = FdoDevice; AsyncCallbackData->CallbackFunction = Callback; KeInitializeTimer(&AsyncCallbackData->AsyncTimer); KeInitializeDpc(&AsyncCallbackData->AsyncTimerDpc, USBPORT_AsyncTimerDpc, AsyncCallbackData); DueTime.QuadPart -= (KeQueryTimeIncrement() - 1) + 10000 * TimerValue; KeSetTimer(&AsyncCallbackData->AsyncTimer, DueTime, &AsyncCallbackData->AsyncTimerDpc); return 0; } PVOID NTAPI USBPORT_GetMappedVirtualAddress(IN ULONG PhysicalAddress, IN PVOID MiniPortExtension, IN PVOID MiniPortEndpoint) { PUSBPORT_COMMON_BUFFER_HEADER HeaderBuffer; PUSBPORT_ENDPOINT Endpoint; ULONG Offset; ULONG_PTR VirtualAddress; DPRINT_CORE("USBPORT_GetMappedVirtualAddress ...\n"); Endpoint = (PUSBPORT_ENDPOINT)((ULONG_PTR)MiniPortEndpoint - sizeof(USBPORT_ENDPOINT)); if (!Endpoint) { ASSERT(FALSE); } HeaderBuffer = Endpoint->HeaderBuffer; Offset = PhysicalAddress - HeaderBuffer->PhysicalAddress; VirtualAddress = HeaderBuffer->VirtualAddress + Offset; return (PVOID)VirtualAddress; } ULONG NTAPI USBPORT_InvalidateEndpoint(IN PVOID MiniPortExtension, IN PVOID MiniPortEndpoint) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDEVICE_OBJECT FdoDevice; PUSBPORT_ENDPOINT Endpoint; DPRINT_CORE("USBPORT_InvalidateEndpoint: ...\n"); FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension - sizeof(USBPORT_DEVICE_EXTENSION)); FdoDevice = FdoExtension->CommonExtension.SelfDevice; if (!MiniPortEndpoint) { USBPORT_InvalidateEndpointHandler(FdoDevice, NULL, INVALIDATE_ENDPOINT_ONLY); return 0; } Endpoint = (PUSBPORT_ENDPOINT)((ULONG_PTR)MiniPortEndpoint - sizeof(USBPORT_ENDPOINT)); USBPORT_InvalidateEndpointHandler(FdoDevice, Endpoint, INVALIDATE_ENDPOINT_ONLY); return 0; } VOID NTAPI USBPORT_CompleteTransfer(IN PURB Urb, IN USBD_STATUS TransferStatus) { struct _URB_CONTROL_TRANSFER *UrbTransfer; PUSBPORT_TRANSFER Transfer; NTSTATUS Status; PIRP Irp; KIRQL OldIrql; PRKEVENT Event; BOOLEAN WriteToDevice; BOOLEAN IsFlushSuccess; PMDL Mdl; ULONG_PTR CurrentVa; SIZE_T TransferLength; PUSBPORT_ENDPOINT Endpoint; PDEVICE_OBJECT FdoDevice; PUSBPORT_DEVICE_EXTENSION FdoExtension; PDMA_OPERATIONS DmaOperations; DPRINT("USBPORT_CompleteTransfer: Urb - %p, TransferStatus - %X\n", Urb, TransferStatus); UrbTransfer = &Urb->UrbControlTransfer; Transfer = UrbTransfer->hca.Reserved8[0]; Transfer->USBDStatus = TransferStatus; Status = USBPORT_USBDStatusToNtStatus(Urb, TransferStatus); UrbTransfer->TransferBufferLength = Transfer->CompletedTransferLen; if (Transfer->Flags & TRANSFER_FLAG_DMA_MAPPED) { Endpoint = Transfer->Endpoint; FdoDevice = Endpoint->FdoDevice; FdoExtension = FdoDevice->DeviceExtension; DmaOperations = FdoExtension->DmaAdapter->DmaOperations; WriteToDevice = Transfer->Direction == USBPORT_DMA_DIRECTION_TO_DEVICE; Mdl = UrbTransfer->TransferBufferMDL; CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); TransferLength = UrbTransfer->TransferBufferLength; IsFlushSuccess = DmaOperations->FlushAdapterBuffers(FdoExtension->DmaAdapter, Mdl, Transfer->MapRegisterBase, (PVOID)CurrentVa, TransferLength, WriteToDevice); if (!IsFlushSuccess) { DPRINT("USBPORT_CompleteTransfer: no FlushAdapterBuffers !!!\n"); ASSERT(FALSE); } KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); DmaOperations->FreeMapRegisters(FdoExtension->DmaAdapter, Transfer->MapRegisterBase, Transfer->NumberOfMapRegisters); KeLowerIrql(OldIrql); } if (Urb->UrbHeader.UsbdFlags & USBD_FLAG_ALLOCATED_MDL) { IoFreeMdl(Transfer->TransferBufferMDL); Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_MDL; } Urb->UrbControlTransfer.hca.Reserved8[0] = NULL; Urb->UrbHeader.UsbdFlags |= ~USBD_FLAG_ALLOCATED_TRANSFER; Irp = Transfer->Irp; if (Irp) { if (!NT_SUCCESS(Status)) { //DbgBreakPoint(); DPRINT1("USBPORT_CompleteTransfer: Irp - %p complete with Status - %lx\n", Irp, Status); USBPORT_DumpingURB(Urb); } Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); IoCompleteRequest(Irp, IO_NO_INCREMENT); KeLowerIrql(OldIrql); } Event = Transfer->Event; if (Event) { KeSetEvent(Event, EVENT_INCREMENT, FALSE); } ExFreePoolWithTag(Transfer, USB_PORT_TAG); DPRINT_CORE("USBPORT_CompleteTransfer: exit\n"); } IO_ALLOCATION_ACTION NTAPI USBPORT_MapTransfer(IN PDEVICE_OBJECT FdoDevice, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PDMA_ADAPTER DmaAdapter; PUSBPORT_TRANSFER Transfer; PURB Urb; PUSBPORT_ENDPOINT Endpoint; PMDL Mdl; ULONG_PTR CurrentVa; PUSBPORT_SCATTER_GATHER_LIST sgList; SIZE_T CurrentLength; ULONG ix; BOOLEAN WriteToDevice; PHYSICAL_ADDRESS PhAddr = {{0, 0}}; PHYSICAL_ADDRESS PhAddress = {{0, 0}}; ULONG TransferLength; SIZE_T SgCurrentLength; SIZE_T ElementLength; PUSBPORT_DEVICE_HANDLE DeviceHandle; PDMA_OPERATIONS DmaOperations; USBD_STATUS USBDStatus; LIST_ENTRY List; PUSBPORT_TRANSFER transfer; DPRINT_CORE("USBPORT_MapTransfer: ...\n"); FdoExtension = FdoDevice->DeviceExtension; DmaAdapter = FdoExtension->DmaAdapter; DmaOperations = DmaAdapter->DmaOperations; Transfer = Context; Urb = Transfer->Urb; Endpoint = Transfer->Endpoint; TransferLength = Transfer->TransferParameters.TransferBufferLength; Mdl = Urb->UrbControlTransfer.TransferBufferMDL; CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); sgList = &Transfer->SgList; sgList->Flags = 0; sgList->CurrentVa = CurrentVa; sgList->MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority); Transfer->MapRegisterBase = MapRegisterBase; ix = 0; CurrentLength = 0; do { WriteToDevice = Transfer->Direction == USBPORT_DMA_DIRECTION_TO_DEVICE; ASSERT(Transfer->Direction != 0); PhAddress = DmaOperations->MapTransfer(DmaAdapter, Mdl, MapRegisterBase, (PVOID)CurrentVa, &TransferLength, WriteToDevice); DPRINT_CORE("USBPORT_MapTransfer: PhAddress.LowPart - %p, PhAddress.HighPart - %x, TransferLength - %x\n", PhAddress.LowPart, PhAddress.HighPart, TransferLength); PhAddress.HighPart = 0; SgCurrentLength = TransferLength; do { ElementLength = PAGE_SIZE - (PhAddress.LowPart & (PAGE_SIZE - 1)); if (ElementLength > SgCurrentLength) ElementLength = SgCurrentLength; DPRINT_CORE("USBPORT_MapTransfer: PhAddress.LowPart - %p, HighPart - %x, ElementLength - %x\n", PhAddress.LowPart, PhAddress.HighPart, ElementLength); sgList->SgElement[ix].SgPhysicalAddress = PhAddress; sgList->SgElement[ix].SgTransferLength = ElementLength; sgList->SgElement[ix].SgOffset = CurrentLength + (TransferLength - SgCurrentLength); PhAddress.LowPart += ElementLength; SgCurrentLength -= ElementLength; ++ix; } while (SgCurrentLength); if (PhAddr.QuadPart == PhAddress.QuadPart) { DPRINT1("USBPORT_MapTransfer: PhAddr == PhAddress\n"); ASSERT(FALSE); } PhAddr = PhAddress; CurrentLength += TransferLength; CurrentVa += TransferLength; TransferLength = Transfer->TransferParameters.TransferBufferLength - CurrentLength; } while (CurrentLength != Transfer->TransferParameters.TransferBufferLength); sgList->SgElementCount = ix; if (Endpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed) { Transfer->Flags |= TRANSFER_FLAG_HIGH_SPEED; } Transfer->Flags |= TRANSFER_FLAG_DMA_MAPPED; if ((Transfer->Flags & TRANSFER_FLAG_ISO) == 0) { KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); USBPORT_SplitTransfer(FdoDevice, Endpoint, Transfer, &List); while (!IsListEmpty(&List)) { transfer = CONTAINING_RECORD(List.Flink, USBPORT_TRANSFER, TransferLink); RemoveHeadList(&List); InsertTailList(&Endpoint->TransferList, &transfer->TransferLink); } KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); } else { USBDStatus = USBPORT_InitializeIsoTransfer(FdoDevice, &Urb->UrbIsochronousTransfer, Transfer); if (USBDStatus != USBD_STATUS_SUCCESS) { KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql); USBPORT_QueueDoneTransfer(Transfer, USBDStatus); KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql); } } DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle; InterlockedDecrement(&DeviceHandle->DeviceHandleLock); if (USBPORT_EndpointWorker(Endpoint, 0)) { USBPORT_InvalidateEndpointHandler(FdoDevice, Endpoint, INVALIDATE_ENDPOINT_WORKER_THREAD); } return DeallocateObjectKeepRegisters; } VOID NTAPI USBPORT_FlushMapTransfers(IN PDEVICE_OBJECT FdoDevice) { PUSBPORT_DEVICE_EXTENSION FdoExtension; PLIST_ENTRY MapTransferList; PUSBPORT_TRANSFER Transfer; ULONG NumMapRegisters; PMDL Mdl; SIZE_T TransferBufferLength; ULONG_PTR VirtualAddr; KIRQL OldIrql; NTSTATUS Status; PDMA_OPERATIONS DmaOperations; DPRINT_CORE("USBPORT_FlushMapTransfers: ...\n"); FdoExtension = FdoDevice->DeviceExtension; DmaOperations = FdoExtension->DmaAdapter->DmaOperations; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); while (TRUE) { MapTransferList = &FdoExtension->MapTransferList; if (IsListEmpty(&FdoExtension->MapTransferList)) { KeLowerIrql(OldIrql); return; } Transfer = CONTAINING_RECORD(MapTransferList->Flink, USBPORT_TRANSFER, TransferLink); RemoveHeadList(MapTransferList); Mdl = Transfer->Urb->UrbControlTransfer.TransferBufferMDL; TransferBufferLength = Transfer->TransferParameters.TransferBufferLength; VirtualAddr = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); NumMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr, TransferBufferLength); Transfer->NumberOfMapRegisters = NumMapRegisters; Status = DmaOperations->AllocateAdapterChannel(FdoExtension->DmaAdapter, FdoDevice, NumMapRegisters, USBPORT_MapTransfer, Transfer); if (!NT_SUCCESS(Status)) ASSERT(FALSE); } KeLowerIrql(OldIrql); } USBD_STATUS NTAPI USBPORT_AllocateTransfer(IN PDEVICE_OBJECT FdoDevice, IN PURB Urb, IN PUSBPORT_DEVICE_HANDLE DeviceHandle, IN PIRP Irp, IN PRKEVENT Event) { PUSBPORT_DEVICE_EXTENSION FdoExtension; SIZE_T TransferLength; PMDL Mdl; ULONG_PTR VirtualAddr; ULONG PagesNeed = 0; SIZE_T PortTransferLength; SIZE_T FullTransferLength; PUSBPORT_TRANSFER Transfer; PUSBPORT_PIPE_HANDLE PipeHandle; USBD_STATUS USBDStatus; SIZE_T IsoBlockLen = 0; DPRINT_CORE("USBPORT_AllocateTransfer: FdoDevice - %p, Urb - %p, DeviceHandle - %p, Irp - %p, Event - %p\n", FdoDevice, Urb, DeviceHandle, Irp, Event); FdoExtension = FdoDevice->DeviceExtension; TransferLength = Urb->UrbControlTransfer.TransferBufferLength; PipeHandle = Urb->UrbControlTransfer.PipeHandle; if (TransferLength) { Mdl = Urb->UrbControlTransfer.TransferBufferMDL; VirtualAddr = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); PagesNeed = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr, TransferLength); if (PagesNeed > 0) { PagesNeed--; } } if (Urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER) { DPRINT1("USBPORT_AllocateTransfer: ISOCH_TRANSFER UNIMPLEMENTED. FIXME\n"); //IsoBlockLen = sizeof(USBPORT_ISO_BLOCK) + // Urb->UrbIsochronousTransfer.NumberOfPackets * // sizeof(USBPORT_ISO_BLOCK_PACKET); } PortTransferLength = sizeof(USBPORT_TRANSFER) + PagesNeed * sizeof(USBPORT_SCATTER_GATHER_ELEMENT) + IsoBlockLen; FullTransferLength = PortTransferLength + FdoExtension->MiniPortInterface->Packet.MiniPortTransferSize; Transfer = ExAllocatePoolWithTag(NonPagedPool, FullTransferLength, USB_PORT_TAG); if (!Transfer) { DPRINT1("USBPORT_AllocateTransfer: Transfer not allocated!\n"); return USBD_STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(Transfer, FullTransferLength); Transfer->Irp = Irp; Transfer->Urb = Urb; Transfer->Endpoint = PipeHandle->Endpoint; Transfer->Event = Event; Transfer->PortTransferLength = PortTransferLength; Transfer->FullTransferLength = FullTransferLength; Transfer->IsoBlockPtr = NULL; Transfer->Period = 0; Transfer->ParentTransfer = Transfer; if (IsoBlockLen) { Transfer->IsoBlockPtr = (PVOID)((ULONG_PTR)Transfer + PortTransferLength - IsoBlockLen); Transfer->Period = PipeHandle->Endpoint->EndpointProperties.Period; Transfer->Flags |= TRANSFER_FLAG_ISO; } Transfer->MiniportTransfer = (PVOID)((ULONG_PTR)Transfer + PortTransferLength); KeInitializeSpinLock(&Transfer->TransferSpinLock); Urb->UrbControlTransfer.hca.Reserved8[0] = Transfer; Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_TRANSFER; USBDStatus = USBD_STATUS_SUCCESS; DPRINT_CORE("USBPORT_AllocateTransfer: return USBDStatus - %x\n", USBDStatus); return USBDStatus; } NTSTATUS NTAPI USBPORT_Dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PUSBPORT_COMMON_DEVICE_EXTENSION DeviceExtension; PIO_STACK_LOCATION IoStack; NTSTATUS Status = STATUS_SUCCESS; DeviceExtension = DeviceObject->DeviceExtension; IoStack = IoGetCurrentIrpStackLocation(Irp); if (DeviceExtension->PnpStateFlags & USBPORT_PNP_STATE_FAILED) { DPRINT1("USBPORT_Dispatch: USBPORT_PNP_STATE_FAILED\n"); DbgBreakPoint(); } switch (IoStack->MajorFunction) { case IRP_MJ_DEVICE_CONTROL: if (DeviceExtension->IsPDO) { DPRINT("USBPORT_Dispatch: PDO IRP_MJ_DEVICE_CONTROL. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_PdoDeviceControl(DeviceObject, Irp); } else { DPRINT("USBPORT_Dispatch: FDO IRP_MJ_DEVICE_CONTROL. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_FdoDeviceControl(DeviceObject, Irp); } break; case IRP_MJ_INTERNAL_DEVICE_CONTROL: if (DeviceExtension->IsPDO) { DPRINT("USBPORT_Dispatch: PDO IRP_MJ_INTERNAL_DEVICE_CONTROL. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_PdoInternalDeviceControl(DeviceObject, Irp); } else { DPRINT("USBPORT_Dispatch: FDO IRP_MJ_INTERNAL_DEVICE_CONTROL. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_FdoInternalDeviceControl(DeviceObject, Irp); } break; case IRP_MJ_POWER: if (DeviceExtension->IsPDO) { DPRINT("USBPORT_Dispatch: PDO IRP_MJ_POWER. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_PdoPower(DeviceObject, Irp); } else { DPRINT("USBPORT_Dispatch: FDO IRP_MJ_POWER. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_FdoPower(DeviceObject, Irp); } break; case IRP_MJ_SYSTEM_CONTROL: if (DeviceExtension->IsPDO) { DPRINT("USBPORT_Dispatch: PDO IRP_MJ_SYSTEM_CONTROL. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { DPRINT("USBPORT_Dispatch: FDO IRP_MJ_SYSTEM_CONTROL. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(DeviceExtension->LowerDevice, Irp); } break; case IRP_MJ_PNP: if (DeviceExtension->IsPDO) { DPRINT("USBPORT_Dispatch: PDO IRP_MJ_PNP. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_PdoPnP(DeviceObject, Irp); } else { DPRINT("USBPORT_Dispatch: FDO IRP_MJ_PNP. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); Status = USBPORT_FdoPnP(DeviceObject, Irp); } break; case IRP_MJ_CREATE: case IRP_MJ_CLOSE: DPRINT("USBPORT_Dispatch: IRP_MJ_CREATE | IRP_MJ_CLOSE\n"); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); break; default: if (DeviceExtension->IsPDO) { DPRINT("USBPORT_Dispatch: PDO unhandled IRP_MJ_???. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); } else { DPRINT("USBPORT_Dispatch: FDO unhandled IRP_MJ_???. Major - %d, Minor - %d\n", IoStack->MajorFunction, IoStack->MinorFunction); } Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); break; } DPRINT("USBPORT_Dispatch: Status - %x\n", Status); return Status; } ULONG NTAPI USBPORT_GetHciMn(VOID) { return USBPORT_HCI_MN; } NTSTATUS NTAPI USBPORT_RegisterUSBPortDriver(IN PDRIVER_OBJECT DriverObject, IN ULONG Version, IN PUSBPORT_REGISTRATION_PACKET RegPacket) { PUSBPORT_MINIPORT_INTERFACE MiniPortInterface; DPRINT("USBPORT_RegisterUSBPortDriver: DriverObject - %p, Version - %p, RegPacket - %p\n", DriverObject, Version, RegPacket); DPRINT("USBPORT_RegisterUSBPortDriver: sizeof(USBPORT_MINIPORT_INTERFACE) - %x\n", sizeof(USBPORT_MINIPORT_INTERFACE)); DPRINT("USBPORT_RegisterUSBPortDriver: sizeof(USBPORT_DEVICE_EXTENSION) - %x\n", sizeof(USBPORT_DEVICE_EXTENSION)); if (Version < USB10_MINIPORT_INTERFACE_VERSION) { return STATUS_UNSUCCESSFUL; } if (!USBPORT_Initialized) { InitializeListHead(&USBPORT_MiniPortDrivers); InitializeListHead(&USBPORT_USB1FdoList); InitializeListHead(&USBPORT_USB2FdoList); KeInitializeSpinLock(&USBPORT_SpinLock); USBPORT_Initialized = TRUE; } MiniPortInterface = ExAllocatePoolWithTag(NonPagedPool, sizeof(USBPORT_MINIPORT_INTERFACE), USB_PORT_TAG); if (!MiniPortInterface) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(MiniPortInterface, sizeof(USBPORT_MINIPORT_INTERFACE)); MiniPortInterface->DriverObject = DriverObject; MiniPortInterface->DriverUnload = DriverObject->DriverUnload; MiniPortInterface->Version = Version; ExInterlockedInsertTailList(&USBPORT_MiniPortDrivers, &MiniPortInterface->DriverLink, &USBPORT_SpinLock); DriverObject->DriverExtension->AddDevice = USBPORT_AddDevice; DriverObject->DriverUnload = USBPORT_Unload; DriverObject->MajorFunction[IRP_MJ_CREATE] = USBPORT_Dispatch; DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBPORT_Dispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBPORT_Dispatch; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBPORT_Dispatch; DriverObject->MajorFunction[IRP_MJ_PNP] = USBPORT_Dispatch; DriverObject->MajorFunction[IRP_MJ_POWER] = USBPORT_Dispatch; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = USBPORT_Dispatch; RegPacket->UsbPortDbgPrint = USBPORT_DbgPrint; RegPacket->UsbPortTestDebugBreak = USBPORT_TestDebugBreak; RegPacket->UsbPortAssertFailure = USBPORT_AssertFailure; RegPacket->UsbPortGetMiniportRegistryKeyValue = USBPORT_GetMiniportRegistryKeyValue; RegPacket->UsbPortInvalidateRootHub = USBPORT_InvalidateRootHub; RegPacket->UsbPortInvalidateEndpoint = USBPORT_InvalidateEndpoint; RegPacket->UsbPortCompleteTransfer = USBPORT_MiniportCompleteTransfer; RegPacket->UsbPortCompleteIsoTransfer = USBPORT_CompleteIsoTransfer; RegPacket->UsbPortLogEntry = USBPORT_LogEntry; RegPacket->UsbPortGetMappedVirtualAddress = USBPORT_GetMappedVirtualAddress; RegPacket->UsbPortRequestAsyncCallback = USBPORT_RequestAsyncCallback; RegPacket->UsbPortReadWriteConfigSpace = USBPORT_ReadWriteConfigSpace; RegPacket->UsbPortWait = USBPORT_Wait; RegPacket->UsbPortInvalidateController = USBPORT_InvalidateController; RegPacket->UsbPortBugCheck = USBPORT_BugCheck; RegPacket->UsbPortNotifyDoubleBuffer = USBPORT_NotifyDoubleBuffer; RtlCopyMemory(&MiniPortInterface->Packet, RegPacket, sizeof(USBPORT_REGISTRATION_PACKET)); return STATUS_SUCCESS; } NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { return STATUS_SUCCESS; }