From 9067f34e6f3856434978647466a68c7f12561da2 Mon Sep 17 00:00:00 2001 From: Michael Martin Date: Mon, 18 Apr 2011 00:06:37 +0000 Subject: [PATCH] [USBEHCI_NEW] - Use LIST_ENTRY in QueueHeads and Descriptors vice Next and Previous Pointers. - Add functions to interface for setting AsyncListRegister and PeriodicListRegister. - USBHardwareDevice: Initialize USBQueue when handling PNPStart. - USBQueue: Allocate Common Buffer and use it to Create and Initialize DmaMemoryManager object. - USBQueue: Implement CreateQueueHead and CreateDescriptor. svn path=/branches/usb-bringup/; revision=51388 --- drivers/usb/usbehci_new/hardware.cpp | 44 +++++--- drivers/usb/usbehci_new/hardware.h | 6 +- drivers/usb/usbehci_new/interfaces.h | 21 +++- drivers/usb/usbehci_new/usb_queue.cpp | 151 +++++++++++++++++++++++++- 4 files changed, 196 insertions(+), 26 deletions(-) diff --git a/drivers/usb/usbehci_new/hardware.cpp b/drivers/usb/usbehci_new/hardware.cpp index a3a8e9b7686..1b3fe8cf4df 100644 --- a/drivers/usb/usbehci_new/hardware.cpp +++ b/drivers/usb/usbehci_new/hardware.cpp @@ -60,7 +60,7 @@ public: NTSTATUS ResetController(); NTSTATUS ResetPort(ULONG PortIndex); - VOID SetAsyncListAddressRegister(ULONG PhysicalAddress); + VOID SetAsyncListRegister(ULONG PhysicalAddress); VOID SetPeriodicListRegister(ULONG PhysicalAddress); KIRQL AcquireDeviceLock(void); @@ -132,12 +132,16 @@ CUSBHardwareDevice::Initialize( DPRINT1("CUSBHardwareDevice::Initialize\n"); + // + // Create the UsbQueue class that will handle the Asynchronous and Periodic Schedules + // Status = CreateUSBQueue(&m_UsbQueue); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to create UsbQueue!\n"); return Status; } + // // store device objects // @@ -332,9 +336,27 @@ CUSBHardwareDevice::PnpStart( return STATUS_INSUFFICIENT_RESOURCES; } + // + // Stop the controller before modifying schedules + // + Status = StopController(); + if (!NT_SUCCESS(Status)) + return Status; + + // + // Initialize the UsbQueue now that we have an AdapterObject. + // + Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to Initialize the UsbQueue\n"); + return Status; + } + // // Start the controller // + DPRINT1("Starting Controller\n"); return StartController(); } @@ -369,7 +391,7 @@ CUSBHardwareDevice::GetDeviceDetails( *NumberOfPorts = m_Capabilities.HCSParams.PortCount; //FIXME: What to returned here? if (Speed) - *Speed = 0; + *Speed = 0x200; return STATUS_SUCCESS; } @@ -477,6 +499,7 @@ CUSBHardwareDevice::StartController(void) // Set port routing to EHCI controller // EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1); + DPRINT1("EHCI Started!\n"); return STATUS_SUCCESS; } @@ -489,6 +512,7 @@ CUSBHardwareDevice::StopController(void) // // Disable Interrupts and stop execution + // EHCI_WRITE_REGISTER_ULONG (EHCI_USBINTR, 0); GetCommandRegister(&UsbCmd); @@ -565,25 +589,11 @@ CUSBHardwareDevice::ResetPort( return STATUS_SUCCESS; } -//----------------------------------------------------------------------------------------- -// -// SetAsyncListAddressRegister -// -// Description: this functions sets the register to a address that is the physical address of a QueueHead. -// This is the location at which the controller will start executing the Asynchronous Schedule. -// -VOID CUSBHardwareDevice::SetAsyncListAddressRegister(ULONG PhysicalAddress) +VOID CUSBHardwareDevice::SetAsyncListRegister(ULONG PhysicalAddress) { EHCI_WRITE_REGISTER_ULONG(EHCI_ASYNCLISTBASE, PhysicalAddress); } -//----------------------------------------------------------------------------------------- -// -// SetPeriodicListRegister -// -// Description: this functions sets the register to a address that is the physical address of a ???. -// This is the location at which the controller will start executing the Periodic Schedule. -// VOID CUSBHardwareDevice::SetPeriodicListRegister(ULONG PhysicalAddress) { EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, PhysicalAddress); diff --git a/drivers/usb/usbehci_new/hardware.h b/drivers/usb/usbehci_new/hardware.h index bdc6a9a2448..d2b83feea48 100644 --- a/drivers/usb/usbehci_new/hardware.h +++ b/drivers/usb/usbehci_new/hardware.h @@ -125,8 +125,7 @@ typedef struct _QUEUE_TRANSFER_DESCRIPTOR //Software ULONG PhysicalAddr; - struct _QUEUE_TRANSFER_DESCRIPTOR *PreviousDescriptor; - struct _QUEUE_TRANSFER_DESCRIPTOR *NextDescriptor; + LIST_ENTRY LinkedDescriptors; } QUEUE_TRANSFER_DESCRIPTOR, *PQUEUE_TRANSFER_DESCRIPTOR; // @@ -190,8 +189,7 @@ typedef struct _QUEUE_HEAD //Software ULONG PhysicalAddr; - struct _QUEUE_HEAD *PreviousQueueHead; - struct _QUEUE_HEAD *NextQueueHead; + LIST_ENTRY LinkedQueueHeads; PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor; PIRP IrpToComplete; PMDL MdlToFree; diff --git a/drivers/usb/usbehci_new/interfaces.h b/drivers/usb/usbehci_new/interfaces.h index fec8f10e2d1..743dabcc108 100644 --- a/drivers/usb/usbehci_new/interfaces.h +++ b/drivers/usb/usbehci_new/interfaces.h @@ -209,6 +209,25 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown) // virtual NTSTATUS ResetPort(ULONG PortNumber) = 0; + +//----------------------------------------------------------------------------------------- +// +// SetAsyncListRegister +// +// Description: this functions sets the register to a address that is the physical address of a QueueHead. +// This is the location at which the controller will start executing the Asynchronous Schedule. +// +// FIXME: This is only available for USB 2.0 + virtual VOID SetAsyncListRegister(ULONG PhysicalAddress) = 0; + +//----------------------------------------------------------------------------------------- +// +// SetPeriodicListRegister +// +// Description: this functions sets the register to a address that is the physical address of a ???. +// This is the location at which the controller will start executing the Periodic Schedule. +// + virtual VOID SetPeriodicListRegister(ULONG PhysicalAddress) = 0; //----------------------------------------------------------------------------------------- // @@ -374,7 +393,7 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown) // Description: initializes the object virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, - PADAPTER_OBJECT AdapterObject, + PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock) = 0; //----------------------------------------------------------------------------------------- diff --git a/drivers/usb/usbehci_new/usb_queue.cpp b/drivers/usb/usbehci_new/usb_queue.cpp index cff76ef9b23..3bacede2462 100644 --- a/drivers/usb/usbehci_new/usb_queue.cpp +++ b/drivers/usb/usbehci_new/usb_queue.cpp @@ -33,7 +33,7 @@ public: return m_Ref; } - NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PADAPTER_OBJECT AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock); + NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock); ULONG GetPendingRequestCount(); NTSTATUS AddUSBRequest(PURB Urb); NTSTATUS AddUSBRequest(IUSBRequest * Request); @@ -46,10 +46,16 @@ public: protected: LONG m_Ref; + KSPIN_LOCK m_Lock; PDMA_ADAPTER m_Adapter; - PQUEUE_HEAD ExecutingList; - PQUEUE_HEAD PendingList; + PVOID VirtualBase; + PHYSICAL_ADDRESS PhysicalAddress; + PLIST_ENTRY ExecutingList; + PLIST_ENTRY PendingList; IDMAMemoryManager *m_MemoryManager; + + PQUEUE_HEAD CreateQueueHead(); + PQUEUE_TRANSFER_DESCRIPTOR CreateDescriptor(UCHAR PIDCode, ULONG TotalBytesToTransfer); }; //================================================================================================= @@ -74,14 +80,33 @@ CUSBQueue::QueryInterface( NTSTATUS CUSBQueue::Initialize( IN PUSBHARDWAREDEVICE Hardware, - PADAPTER_OBJECT AdapterObject, + PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock) { NTSTATUS Status; + PQUEUE_HEAD HeadQueueHead; + + DPRINT1("CUSBQueue::Initialize()\n"); ASSERT(Hardware); ASSERT(AdapterObject); + // + // Create Common Buffer + // + VirtualBase = AdapterObject->DmaOperations->AllocateCommonBuffer(AdapterObject, + PAGE_SIZE * 4, + &PhysicalAddress, + FALSE); + if (!VirtualBase) + { + DPRINT1("Failed to allocate a common buffer\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Create DMAMemoryManager for use with QueueHeads and Transfer Descriptors. + // Status = CreateDMAMemoryManager(&m_MemoryManager); if (!NT_SUCCESS(Status)) { @@ -89,6 +114,50 @@ CUSBQueue::Initialize( return Status; } + // + // initialize device lock + // + KeInitializeSpinLock(&m_Lock); + + // + // Initialize the DMAMemoryManager + // + Status = m_MemoryManager->Initialize(Hardware, &m_Lock, PAGE_SIZE * 4, VirtualBase, PhysicalAddress, 32); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to initialize the DMAMemoryManager\n"); + return Status; + } + + // + // Create a dead QueueHead for use in Async Register + // + HeadQueueHead = CreateQueueHead(); + HeadQueueHead->HorizontalLinkPointer = HeadQueueHead->PhysicalAddr | QH_TYPE_QH; + HeadQueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE; + HeadQueueHead->Token.Bits.InterruptOnComplete = FALSE; + HeadQueueHead->EndPointCharacteristics.HeadOfReclamation = TRUE; + HeadQueueHead->Token.Bits.Halted = TRUE; + + Hardware->SetAsyncListRegister(HeadQueueHead->PhysicalAddr); + + // + // Set ExecutingList and create PendingList + // + ExecutingList = &HeadQueueHead->LinkedQueueHeads; + PendingList = (PLIST_ENTRY) ExAllocatePool(NonPagedPool, sizeof(LIST_ENTRY)); + if (!PendingList) + { + DPRINT1("Pool allocation failed\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Initialize ListHeads + // + InitializeListHead(ExecutingList); + InitializeListHead(PendingList); + return STATUS_SUCCESS; } @@ -130,6 +199,80 @@ CUSBQueue::CreateUSBRequest( return STATUS_NOT_IMPLEMENTED; } +PQUEUE_HEAD +CUSBQueue::CreateQueueHead() +{ + PQUEUE_HEAD QueueHead; + PHYSICAL_ADDRESS PhysicalAddress; + NTSTATUS Status; + // + // Create the QueueHead from Common Buffer + // + Status = m_MemoryManager->Allocate(sizeof(QUEUE_HEAD), + (PVOID*)&QueueHead, + &PhysicalAddress); + if (!NT_SUCCESS(Status)) + return NULL; + + // + // Initialize default values + // + + QueueHead->PhysicalAddr = PhysicalAddress.LowPart; + QueueHead->HorizontalLinkPointer = TERMINATE_POINTER; + QueueHead->AlternateNextPointer = TERMINATE_POINTER; + QueueHead->NextPointer = TERMINATE_POINTER; + + // 1 for non high speed, 0 for high speed device + QueueHead->EndPointCharacteristics.ControlEndPointFlag = 0; + QueueHead->EndPointCharacteristics.HeadOfReclamation = FALSE; + QueueHead->EndPointCharacteristics.MaximumPacketLength = 64; + + // Set NakCountReload to max value possible + QueueHead->EndPointCharacteristics.NakCountReload = 0xF; + + // Get the Initial Data Toggle from the Queue Element Desriptor + QueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE; + + QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED; + + QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03; + + // Interrupt when QueueHead is processed + QueueHead->Token.Bits.InterruptOnComplete = FALSE; + + return QueueHead; +} + +PQUEUE_TRANSFER_DESCRIPTOR +CUSBQueue::CreateDescriptor( + UCHAR PIDCode, + ULONG TotalBytesToTransfer) +{ + PQUEUE_TRANSFER_DESCRIPTOR Descriptor; + PHYSICAL_ADDRESS PhysicalAddress; + NTSTATUS Status; + + // + // Create the Descriptor from Common Buffer + // + Status = m_MemoryManager->Allocate(sizeof(QUEUE_TRANSFER_DESCRIPTOR), + (PVOID*)&Descriptor, + &PhysicalAddress); + if (!NT_SUCCESS(Status)) + return NULL; + + Descriptor->NextPointer = TERMINATE_POINTER; + Descriptor->AlternateNextPointer = TERMINATE_POINTER; + Descriptor->Token.Bits.DataToggle = TRUE; + Descriptor->Token.Bits.ErrorCounter = 0x03; + Descriptor->Token.Bits.Active = TRUE; + Descriptor->Token.Bits.PIDCode = PIDCode; + Descriptor->Token.Bits.TotalBytesToTransfer = TotalBytesToTransfer; + Descriptor->PhysicalAddr = PhysicalAddress.LowPart; + return Descriptor; +} + NTSTATUS CreateUSBQueue( PUSBQUEUE *OutUsbQueue)