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_qu…
==============================================================================
--- 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)