[USBEHCI]

- Pass memory manager to USBQueue object
- Fix bug in memory manager which did not check if an allocation equals page size
- Implement interrupt queue head array with frequencys of 1ms up to 32ms
- Store queue heads in the sync schedule array
- WIP

svn path=/branches/usb-bringup/; revision=51826
This commit is contained in:
Johannes Anderwald
2011-05-20 14:47:15 +00:00
parent ff208f7adb
commit 9e2ca3d539
4 changed files with 173 additions and 12 deletions
+1 -1
View File
@@ -437,7 +437,7 @@ CUSBHardwareDevice::PnpStart(
//
// Initialize the UsbQueue now that we have an AdapterObject.
//
Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, NULL);
Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to Initialize the UsbQueue\n");
+2 -1
View File
@@ -525,7 +525,8 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown)
// Description: initializes the object
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware,
PDMA_ADAPTER AdapterObject,
IN PDMA_ADAPTER AdapterObject,
IN PDMAMEMORYMANAGER MemManager,
IN OPTIONAL PKSPIN_LOCK Lock) = 0;
//-----------------------------------------------------------------------------------------
+20 -1
View File
@@ -131,11 +131,12 @@ CDMAMemoryManager::Allocate(
{
ULONG Length, BlockCount, FreeIndex, StartPage, EndPage;
KIRQL OldLevel;
ULONG BlocksPerPage;
//
// sanity checks
//
ASSERT(Size < PAGE_SIZE);
ASSERT(Size <= PAGE_SIZE);
//ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
@@ -158,6 +159,11 @@ CDMAMemoryManager::Allocate(
//
KeAcquireSpinLock(m_Lock, &OldLevel);
//
// helper variable
//
BlocksPerPage = PAGE_SIZE / m_BlockSize;
//
// start search
//
@@ -202,6 +208,19 @@ CDMAMemoryManager::Allocate(
//
break;
}
else if ((BlockCount == BlocksPerPage) && (FreeIndex % BlocksPerPage == 0))
{
//
// the request equals PAGE_SIZE and is aligned at page boundary
// reserve block
//
RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
//
// reserve block
//
break;
}
else
{
//
+150 -9
View File
@@ -33,7 +33,7 @@ public:
return m_Ref;
}
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock);
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, IN OPTIONAL PKSPIN_LOCK Lock);
virtual ULONG GetPendingRequestCount();
virtual NTSTATUS AddUSBRequest(PURB Urb);
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request);
@@ -47,13 +47,18 @@ public:
virtual ~CUSBQueue(){}
protected:
LONG m_Ref;
KSPIN_LOCK m_Lock;
PDMA_ADAPTER m_Adapter;
PQUEUE_HEAD AsyncListQueueHead;
LIST_ENTRY m_CompletedRequestAsyncList;
LIST_ENTRY m_PendingRequestAsyncList;
LONG m_Ref; // reference count
KSPIN_LOCK m_Lock; // list lock
PDMA_ADAPTER m_Adapter; // dma adapter
PUSBHARDWAREDEVICE m_Hardware; // stores hardware object
PQUEUE_HEAD AsyncListQueueHead; // async queue head
LIST_ENTRY m_CompletedRequestAsyncList; // completed async request list
LIST_ENTRY m_PendingRequestAsyncList; // pending async request list
ULONG m_MaxPeriodicListEntries; // max perdiodic list entries
ULONG m_MaxPollingInterval; // max polling interval
PHYSICAL_ADDRESS m_SyncFrameListAddr; // physical address of sync frame list
PULONG m_SyncFrameList; // virtual address of sync frame list
PQUEUE_HEAD * m_SyncFrameListQueueHeads; // stores the frame list of queue head
// queue head manipulation functions
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
@@ -69,6 +74,9 @@ protected:
// called when the completion queue is cleaned up
VOID QueueHeadCleanup(PQUEUE_HEAD QueueHead);
// intializes the sync schedule
NTSTATUS InitializeSyncSchedule(IN PUSBHARDWAREDEVICE Hardware, IN PDMAMEMORYMANAGER MemManager);
};
//=================================================================================================
@@ -93,7 +101,8 @@ CUSBQueue::QueryInterface(
NTSTATUS
CUSBQueue::Initialize(
IN PUSBHARDWAREDEVICE Hardware,
PDMA_ADAPTER AdapterObject,
IN PDMA_ADAPTER AdapterObject,
IN PDMAMEMORYMANAGER MemManager,
IN OPTIONAL PKSPIN_LOCK Lock)
{
NTSTATUS Status = STATUS_SUCCESS;
@@ -127,9 +136,141 @@ CUSBQueue::Initialize(
//
InitializeListHead(&m_PendingRequestAsyncList);
//
// now initialize sync schedule
//
Status = InitializeSyncSchedule(Hardware, MemManager);
return Status;
}
NTSTATUS
CUSBQueue::InitializeSyncSchedule(
IN PUSBHARDWAREDEVICE Hardware,
IN PDMAMEMORYMANAGER MemManager)
{
PHYSICAL_ADDRESS QueueHeadPhysAddr;
NTSTATUS Status;
ULONG Index;
PQUEUE_HEAD QueueHead;
//
// FIXME: check if smaller list sizes are supported
//
m_MaxPeriodicListEntries = 1024;
//
// use polling scheme of 32ms
//
m_MaxPollingInterval = 32;
//
// allocate dummy frame list array
//
m_SyncFrameListQueueHeads = (PQUEUE_HEAD*)ExAllocatePool(NonPagedPool, m_MaxPollingInterval * sizeof(PQUEUE_HEAD));
if (!m_SyncFrameListQueueHeads)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// first allocate a page to hold the queue array
//
Status = MemManager->Allocate(m_MaxPeriodicListEntries * sizeof(PVOID), (PVOID*)&m_SyncFrameList, &m_SyncFrameListAddr);
if (!NT_SUCCESS(Status))
{
//
// failed to allocate sync frame list array
//
DPRINT1("Failed to allocate sync frame list\n");
ExFreePool(m_SyncFrameListQueueHeads);
ASSERT(FALSE);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now allocate queue head descriptors for the polling interval
//
for(Index = 0; Index < m_MaxPeriodicListEntries; Index++)
{
//
// check if is inside our polling interrupt frequency window
//
if (Index < m_MaxPollingInterval)
{
//
// allocate queue head
//
Status = MemManager->Allocate(sizeof(QUEUE_HEAD), (PVOID*)&QueueHead, &QueueHeadPhysAddr);
//
// initialize queue head
//
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 QEDT
//
QueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
//
// FIXME: check if High Speed Device
//
QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
QueueHead->Token.DWord = 0;
QueueHead->Token.Bits.InterruptOnComplete = FALSE;
QueueHead->PhysicalAddr = QueueHeadPhysAddr.LowPart;
//
// store in queue head array
//
m_SyncFrameListQueueHeads[Index] = QueueHead;
}
else
{
//
// get cached entry
//
QueueHead = m_SyncFrameListQueueHeads[m_MaxPeriodicListEntries % m_MaxPollingInterval];
}
//
// store entry
//
m_SyncFrameList[Index] = (QueueHead->PhysicalAddr | 0x2);
}
//
// now set the sync base
//
Hardware->SetPeriodicListRegister(m_SyncFrameListAddr.LowPart);
//
// sync frame list initialized
//
return STATUS_SUCCESS;
}
ULONG
CUSBQueue::GetPendingRequestCount()
{