[ros-diffs] [janderwald] 55960: [USBEHCI] - Check if allocation of queue heads failed - Implement removing of completed queue head

janderwald at svn.reactos.org janderwald at svn.reactos.org
Fri Mar 2 18:26:08 UTC 2012


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_queue.cpp?rev=55960&r1=55959&r2=55960&view=diff
==============================================================================
--- 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)




More information about the Ros-diffs mailing list