Author: janderwald Date: Fri Mar 2 18:26:08 2012 New Revision: 55960
URL: http://svn.reactos.org/svn/reactos?rev=55960&view=rev Log: [USBEHCI] - Check if allocation of queue heads failed - Implement removing of completed queue head
Modified: trunk/reactos/drivers/usb/usbehci/usb_queue.cpp
Modified: trunk/reactos/drivers/usb/usbehci/usb_queue.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbehci/usb_que... ============================================================================== --- trunk/reactos/drivers/usb/usbehci/usb_queue.cpp [iso-8859-1] (original) +++ trunk/reactos/drivers/usb/usbehci/usb_queue.cpp [iso-8859-1] Fri Mar 2 18:26:08 2012 @@ -71,6 +71,9 @@ // called for each completed queue head VOID QueueHeadCompletion(PQUEUE_HEAD QueueHead, NTSTATUS Status);
+ // called for each completed queue head + VOID QueueHeadInterruptCompletion(PQUEUE_HEAD QueueHead, NTSTATUS Status); + // called when the completion queue is cleaned up VOID QueueHeadCleanup(PQUEUE_HEAD QueueHead);
@@ -80,10 +83,15 @@ // links interrupt queue head VOID LinkInterruptQueueHead(PQUEUE_HEAD QueueHead);
+ // interval index + UCHAR GetIntervalIndex(UCHAR Interval); + + // interrupt queue heads PQUEUE_HEAD m_InterruptQueueHeads[EHCI_INTERRUPT_ENTRIES_COUNT];
- + // contains the periodic queue heads + LIST_ENTRY m_PeriodicQueueHeads; };
//================================================================================================= @@ -151,6 +159,11 @@ InitializeListHead(&m_PendingRequestAsyncList);
// + // initialize periodic queue heads + // + InitializeListHead(&m_PeriodicQueueHeads); + + // // now initialize sync schedule // Status = InitializeSyncSchedule(m_Hardware, MemManager); @@ -198,6 +211,14 @@ // allocate queue head // Status = MemManager->Allocate(sizeof(QUEUE_HEAD), (PVOID*)&QueueHead, &QueueHeadPhysAddr); + if (!NT_SUCCESS(Status)) + { + // + // failed to create queue head + // + DPRINT1("Failed to create queue head\n"); + return Status; + }
// // initialize queue head @@ -347,46 +368,11 @@ return Status; }
-VOID -CUSBQueue::LinkInterruptQueueHead( - PQUEUE_HEAD QueueHead) -{ - PEHCIREQUEST Request; - UCHAR Interval, IntervalIndex; - USB_DEVICE_SPEED DeviceSpeed; - PQUEUE_HEAD InterruptQueueHead; - - // get internal req - Request = PEHCIREQUEST(QueueHead->Request); - ASSERT(Request); - - // get interval - Interval = Request->GetInterval(); - - // get device speed - DeviceSpeed = Request->GetSpeed(); - if (DeviceSpeed == UsbHighSpeed) - { - // interrupt queue head can be scheduled on each possible micro frame - QueueHead->EndPointCapabilities.InterruptScheduleMask = 0xFF; - } - else - { - // As we do not yet support FSTNs to correctly reference low/full - // speed interrupt transfers, we simply put them into the 1 interval - // queue. This way we ensure that we reach them on every micro frame - // and can do the corresponding start/complete split transactions. - // ToDo: use FSTNs to correctly link non high speed interrupt transfers - Interval = 1; - - // For now we also force start splits to be in micro frame 0 and - // complete splits to be in micro frame 2, 3 and 4. - QueueHead->EndPointCapabilities.InterruptScheduleMask = 0x01; - QueueHead->EndPointCapabilities.SplitCompletionMask = 0x1C; - } - - // sanitize interrupt interval - Interval = max(1, Interval); +UCHAR +CUSBQueue::GetIntervalIndex( + UCHAR Interval) +{ + UCHAR IntervalIndex;
if (Interval == 1) IntervalIndex = 1; @@ -409,6 +395,54 @@ else IntervalIndex = 10;
+ return IntervalIndex; +} + +VOID +CUSBQueue::LinkInterruptQueueHead( + PQUEUE_HEAD QueueHead) +{ + PEHCIREQUEST Request; + UCHAR Interval, IntervalIndex; + USB_DEVICE_SPEED DeviceSpeed; + PQUEUE_HEAD InterruptQueueHead; + + // get internal req + Request = PEHCIREQUEST(QueueHead->Request); + ASSERT(Request); + + // get interval + Interval = Request->GetInterval(); + + // get device speed + DeviceSpeed = Request->GetSpeed(); + if (DeviceSpeed == UsbHighSpeed) + { + // interrupt queue head can be scheduled on each possible micro frame + QueueHead->EndPointCapabilities.InterruptScheduleMask = 0xFF; + } + else + { + // As we do not yet support FSTNs to correctly reference low/full + // speed interrupt transfers, we simply put them into the 1 interval + // queue. This way we ensure that we reach them on every micro frame + // and can do the corresponding start/complete split transactions. + // ToDo: use FSTNs to correctly link non high speed interrupt transfers + Interval = 1; + + // For now we also force start splits to be in micro frame 0 and + // complete splits to be in micro frame 2, 3 and 4. + QueueHead->EndPointCapabilities.InterruptScheduleMask = 0x01; + QueueHead->EndPointCapabilities.SplitCompletionMask = 0x1C; + } + + // sanitize interrupt interval + Interval = max(1, Interval); + + // get interval index + IntervalIndex = GetIntervalIndex(Interval); + + // get interrupt queue head InterruptQueueHead = m_InterruptQueueHeads[IntervalIndex];
@@ -418,6 +452,9 @@
InterruptQueueHead->HorizontalLinkPointer = QueueHead->PhysicalAddr | QH_TYPE_QH; InterruptQueueHead->NextQueueHead = QueueHead; + + // store in periodic list + InsertTailList(&m_PeriodicQueueHeads, &QueueHead->LinkedQueueHeads); }
// @@ -595,6 +632,67 @@ }
VOID +CUSBQueue::QueueHeadInterruptCompletion( + PQUEUE_HEAD QueueHead, + NTSTATUS Status) +{ + PEHCIREQUEST Request; + UCHAR Interval, IntervalIndex; + PQUEUE_HEAD InterruptQueueHead, LastQueueHead = NULL; + + + // + // sanity check + // + PC_ASSERT(QueueHead->Request); + + // + // get IUSBRequest interface + // + Request = (PEHCIREQUEST)QueueHead->Request; + + // get interval + Interval = Request->GetInterval(); + + // sanitize interval + Interval = max(1, Interval); + + // get interval index + IntervalIndex = GetIntervalIndex(Interval); + + // get interrupt queue head from index + InterruptQueueHead = m_InterruptQueueHeads[IntervalIndex]; + + while(InterruptQueueHead != NULL) + { + if (InterruptQueueHead == QueueHead) + break; + + // move to next queue head + LastQueueHead = InterruptQueueHead; + InterruptQueueHead = (PQUEUE_HEAD)InterruptQueueHead->NextQueueHead; + } + + if (InterruptQueueHead != QueueHead) + { + // queue head not in list + ASSERT(FALSE); + return; + } + + // now unlink queue head + LastQueueHead->HorizontalLinkPointer = QueueHead->HorizontalLinkPointer; + LastQueueHead->NextQueueHead = QueueHead->NextQueueHead; + + DPRINT1("Periodic QueueHead %p Addr $x unlinked\n", QueueHead, QueueHead->PhysicalAddr); + + // insert into completed list + InsertTailList(&m_CompletedRequestAsyncList, &QueueHead->LinkedQueueHeads); +} + + + +VOID CUSBQueue::QueueHeadCompletion( PQUEUE_HEAD CurrentQH, NTSTATUS Status) @@ -619,15 +717,6 @@
VOID CUSBQueue::ProcessPeriodicSchedule( - IN NTSTATUS Status, - OUT PULONG ShouldRingDoorBell) -{ - - -} - -VOID -CUSBQueue::ProcessAsyncList( IN NTSTATUS Status, OUT PULONG ShouldRingDoorBell) { @@ -646,6 +735,82 @@ // walk async list // ASSERT(AsyncListQueueHead); + Entry = m_PeriodicQueueHeads.Flink; + + while(Entry != &m_PeriodicQueueHeads) + { + // + // get queue head structure + // + QueueHead = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads); + ASSERT(QueueHead); + + // + // sanity check + // + PC_ASSERT(QueueHead->Request); + + // + // get IUSBRequest interface + // + Request = (PEHCIREQUEST)QueueHead->Request; + + // + // move to next entry + // + Entry = Entry->Flink; + + // + // check if queue head is complete + // + IsQueueHeadComplete = Request->IsQueueHeadComplete(QueueHead); + + DPRINT("Request %p QueueHead %p Complete %d\n", Request, QueueHead, IsQueueHeadComplete); + + // + // check if queue head is complete + // + if (IsQueueHeadComplete) + { + // + // current queue head is complete + // + QueueHeadInterruptCompletion(QueueHead, Status); + + // + // ring door bell is going to be necessary + // + *ShouldRingDoorBell = TRUE; + } + } + + // + // release lock + // + KeReleaseSpinLock(m_Lock, OldLevel); + +} + +VOID +CUSBQueue::ProcessAsyncList( + IN NTSTATUS Status, + OUT PULONG ShouldRingDoorBell) +{ + KIRQL OldLevel; + PLIST_ENTRY Entry; + PQUEUE_HEAD QueueHead; + PEHCIREQUEST Request; + BOOLEAN IsQueueHeadComplete; + + // + // lock completed async list + // + KeAcquireSpinLock(m_Lock, &OldLevel); + + // + // walk async list + // + ASSERT(AsyncListQueueHead); Entry = AsyncListQueueHead->LinkedQueueHeads.Flink;
while(Entry != &AsyncListQueueHead->LinkedQueueHeads)