[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
This commit is contained in:
Michael Martin 2011-04-18 00:06:37 +00:00
parent a2b99febfa
commit 9067f34e6f
4 changed files with 196 additions and 26 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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;
//-----------------------------------------------------------------------------------------

View file

@ -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)