2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/usb_queue.cpp
5 * PURPOSE: USB EHCI device driver.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 class CUSBQueue
: public IUSBQueue
17 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
19 STDMETHODIMP_(ULONG
) AddRef()
21 InterlockedIncrement(&m_Ref
);
24 STDMETHODIMP_(ULONG
) Release()
26 InterlockedDecrement(&m_Ref
);
36 NTSTATUS
Initialize(IN PUSBHARDWAREDEVICE Hardware
, PDMA_ADAPTER AdapterObject
, IN OPTIONAL PKSPIN_LOCK Lock
);
37 ULONG
GetPendingRequestCount();
38 NTSTATUS
AddUSBRequest(PURB Urb
);
39 NTSTATUS
AddUSBRequest(IUSBRequest
* Request
);
40 NTSTATUS
CancelRequests();
41 NTSTATUS
CreateUSBRequest(IUSBRequest
**OutRequest
);
43 // constructor / destructor
44 CUSBQueue(IUnknown
*OuterUnknown
){}
45 virtual ~CUSBQueue(){}
50 PDMA_ADAPTER m_Adapter
;
51 PQUEUE_HEAD AsyncListQueueHead
;
52 PQUEUE_HEAD PendingListQueueHead
;
54 VOID
LinkQueueHead(PQUEUE_HEAD HeadQueueHead
, PQUEUE_HEAD NewQueueHead
);
55 VOID
UnlinkQueueHead(PQUEUE_HEAD QueueHead
);
56 VOID
LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead
, PQUEUE_HEAD NewQueueHead
);
57 PQUEUE_HEAD
UnlinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead
, ULONG Count
);
60 //=================================================================================================
65 CUSBQueue::QueryInterface(
69 if (IsEqualGUIDAligned(refiid
, IID_IUnknown
))
71 *Output
= PVOID(PUNKNOWN(this));
72 PUNKNOWN(*Output
)->AddRef();
73 return STATUS_SUCCESS
;
76 return STATUS_UNSUCCESSFUL
;
80 CUSBQueue::Initialize(
81 IN PUSBHARDWAREDEVICE Hardware
,
82 PDMA_ADAPTER AdapterObject
,
83 IN OPTIONAL PKSPIN_LOCK Lock
)
85 NTSTATUS Status
= STATUS_SUCCESS
;
87 DPRINT1("CUSBQueue::Initialize()\n");
92 // initialize device lock
94 KeInitializeSpinLock(&m_Lock
);
97 // Get the AsyncQueueHead
99 AsyncListQueueHead
= (PQUEUE_HEAD
)Hardware
->GetAsyncListRegister();
102 // Create the PendingListQueueHead from NONPAGEDPOOL. It will never be linked into the Asynclist Schedule
104 PendingListQueueHead
= (PQUEUE_HEAD
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(QUEUE_HEAD
), TAG_USBEHCI
);
105 if (!PendingListQueueHead
)
107 DPRINT1("Pool Allocation failed!\n");
108 return STATUS_INSUFFICIENT_RESOURCES
;
112 // Initialize the List Head
114 InitializeListHead(&PendingListQueueHead
->LinkedQueueHeads
);
120 CUSBQueue::GetPendingRequestCount()
123 // Loop through the pending list and iterrate one for each QueueHead that
124 // has a IRP to complete.
132 CUSBQueue::AddUSBRequest(
133 IUSBRequest
* Request
)
135 PQUEUE_HEAD QueueHead
;
136 ASSERT(Request
!= NULL
);
138 Request
->GetQueueHead(&QueueHead
);
141 // Add it to the pending list
143 LinkQueueHead(PendingListQueueHead
, QueueHead
);
145 return STATUS_SUCCESS
;
149 CUSBQueue::AddUSBRequest(
153 return STATUS_NOT_IMPLEMENTED
;
157 CUSBQueue::CancelRequests()
160 return STATUS_NOT_IMPLEMENTED
;
164 CUSBQueue::CreateUSBRequest(
165 IUSBRequest
**OutRequest
)
167 PUSBREQUEST UsbRequest
;
171 Status
= InternalCreateUSBRequest(&UsbRequest
);
173 if (NT_SUCCESS(Status
))
175 *OutRequest
= UsbRequest
;
182 // LinkQueueHead - Links one QueueHead to the end of HeadQueueHead list, updating HorizontalLinkPointer.
185 CUSBQueue::LinkQueueHead(
186 PQUEUE_HEAD HeadQueueHead
,
187 PQUEUE_HEAD NewQueueHead
)
189 PQUEUE_HEAD LastQueueHead
, NextQueueHead
;
191 ASSERT(HeadQueueHead
);
192 ASSERT(NewQueueHead
);
195 // Link the LIST_ENTRYs
197 InsertTailList(&HeadQueueHead
->LinkedQueueHeads
, &NewQueueHead
->LinkedQueueHeads
);
200 // Update HLP for Previous QueueHead, which should be the last in list.
202 Entry
= NewQueueHead
->LinkedQueueHeads
.Blink
;
203 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
204 LastQueueHead
->HorizontalLinkPointer
= (NewQueueHead
->PhysicalAddr
| QH_TYPE_QH
);
207 // Update HLP for NewQueueHead to point to next, which should be the HeadQueueHead
209 Entry
= NewQueueHead
->LinkedQueueHeads
.Flink
;
210 NextQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
211 ASSERT(NextQueueHead
== HeadQueueHead
);
212 NewQueueHead
->HorizontalLinkPointer
= NextQueueHead
->PhysicalAddr
;
216 // UnlinkQueueHead - Unlinks one QueueHead, updating HorizontalLinkPointer.
219 CUSBQueue::UnlinkQueueHead(
220 PQUEUE_HEAD QueueHead
)
222 PQUEUE_HEAD PreviousQH
, NextQH
;
225 Entry
= QueueHead
->LinkedQueueHeads
.Blink
;
226 PreviousQH
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
227 Entry
= QueueHead
->LinkedQueueHeads
.Flink
;
228 NextQH
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
229 ASSERT(QueueHead
->HorizontalLinkPointer
== (NextQH
->PhysicalAddr
| QH_TYPE_QH
));
230 PreviousQH
->HorizontalLinkPointer
= NextQH
->PhysicalAddr
| QH_TYPE_QH
;
232 RemoveEntryList(&QueueHead
->LinkedQueueHeads
);
236 // LinkQueueHeadChain - Links a list of QueueHeads to the HeadQueueHead list, updating HorizontalLinkPointer.
239 CUSBQueue::LinkQueueHeadChain(
240 PQUEUE_HEAD HeadQueueHead
,
241 PQUEUE_HEAD NewQueueHead
)
243 PQUEUE_HEAD LastQueueHead
;
245 ASSERT(HeadQueueHead
);
246 ASSERT(NewQueueHead
);
249 // Find the last QueueHead in NewQueueHead
251 Entry
= NewQueueHead
->LinkedQueueHeads
.Blink
;
252 ASSERT(Entry
!= NewQueueHead
->LinkedQueueHeads
.Flink
);
253 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
256 // Set the LinkPointer and Flink
258 LastQueueHead
->HorizontalLinkPointer
= HeadQueueHead
->PhysicalAddr
| QH_TYPE_QH
;
259 LastQueueHead
->LinkedQueueHeads
.Flink
= &HeadQueueHead
->LinkedQueueHeads
;
262 // Fine the last QueueHead in HeadQueueHead
264 Entry
= HeadQueueHead
->LinkedQueueHeads
.Blink
;
265 HeadQueueHead
->LinkedQueueHeads
.Blink
= &LastQueueHead
->LinkedQueueHeads
;
266 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
267 LastQueueHead
->LinkedQueueHeads
.Flink
= &NewQueueHead
->LinkedQueueHeads
;
268 LastQueueHead
->HorizontalLinkPointer
= NewQueueHead
->PhysicalAddr
| QH_TYPE_QH
;
272 // UnlinkQueueHeadChain - Unlinks a list number of QueueHeads from HeadQueueHead list, updating HorizontalLinkPointer.
273 // returns the chain of QueueHeads removed from HeadQueueHead.
276 CUSBQueue::UnlinkQueueHeadChain(
277 PQUEUE_HEAD HeadQueueHead
,
280 PQUEUE_HEAD LastQueueHead
, FirstQueueHead
;
285 // Find the last QueueHead in NewQueueHead
287 Entry
= &HeadQueueHead
->LinkedQueueHeads
;
288 FirstQueueHead
= CONTAINING_RECORD(Entry
->Flink
, QUEUE_HEAD
, LinkedQueueHeads
);
290 for (Index
= 0; Index
< Count
; Index
++)
292 Entry
= Entry
->Flink
;
294 if (Entry
== &HeadQueueHead
->LinkedQueueHeads
)
296 DPRINT1("Warnnig; Only %d QueueHeads in HeadQueueHead\n", Index
);
302 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
303 HeadQueueHead
->LinkedQueueHeads
.Flink
= LastQueueHead
->LinkedQueueHeads
.Flink
;
304 if (Count
+ 1 == Index
)
306 HeadQueueHead
->LinkedQueueHeads
.Blink
= &HeadQueueHead
->LinkedQueueHeads
;
309 HeadQueueHead
->LinkedQueueHeads
.Blink
= LastQueueHead
->LinkedQueueHeads
.Flink
;
311 FirstQueueHead
->LinkedQueueHeads
.Blink
= &LastQueueHead
->LinkedQueueHeads
;
312 LastQueueHead
->LinkedQueueHeads
.Flink
= &FirstQueueHead
->LinkedQueueHeads
;
313 LastQueueHead
->HorizontalLinkPointer
= TERMINATE_POINTER
;
314 return FirstQueueHead
;
319 PUSBQUEUE
*OutUsbQueue
)
324 // allocate controller
326 This
= new(NonPagedPool
, TAG_USBEHCI
) CUSBQueue(0);
330 // failed to allocate
332 return STATUS_INSUFFICIENT_RESOURCES
;
336 // add reference count
343 *OutUsbQueue
= (PUSBQUEUE
)This
;
348 return STATUS_SUCCESS
;