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 virtual NTSTATUS
Initialize(IN PUSBHARDWAREDEVICE Hardware
, PDMA_ADAPTER AdapterObject
, IN PDMAMEMORYMANAGER MemManager
, IN PKSPIN_LOCK Lock
);
37 virtual ULONG
GetPendingRequestCount();
38 virtual NTSTATUS
AddUSBRequest(PURB Urb
);
39 virtual NTSTATUS
AddUSBRequest(IUSBRequest
* Request
);
40 virtual NTSTATUS
CancelRequests();
41 virtual NTSTATUS
CreateUSBRequest(IUSBRequest
**OutRequest
);
42 virtual VOID
InterruptCallback(IN NTSTATUS Status
, OUT PULONG ShouldRingDoorBell
);
43 virtual VOID
CompleteAsyncRequests();
45 // constructor / destructor
46 CUSBQueue(IUnknown
*OuterUnknown
){}
47 virtual ~CUSBQueue(){}
50 LONG m_Ref
; // reference count
51 PKSPIN_LOCK m_Lock
; // list lock
52 PDMA_ADAPTER m_Adapter
; // dma adapter
53 PUSBHARDWAREDEVICE m_Hardware
; // stores hardware object
54 PQUEUE_HEAD AsyncListQueueHead
; // async queue head
55 LIST_ENTRY m_CompletedRequestAsyncList
; // completed async request list
56 LIST_ENTRY m_PendingRequestAsyncList
; // pending async request list
57 ULONG m_MaxPeriodicListEntries
; // max perdiodic list entries
58 ULONG m_MaxPollingInterval
; // max polling interval
59 PHYSICAL_ADDRESS m_SyncFrameListAddr
; // physical address of sync frame list
60 PULONG m_SyncFrameList
; // virtual address of sync frame list
61 PQUEUE_HEAD
* m_SyncFrameListQueueHeads
; // stores the frame list of queue head
63 // queue head manipulation functions
64 VOID
LinkQueueHead(PQUEUE_HEAD HeadQueueHead
, PQUEUE_HEAD NewQueueHead
);
65 VOID
UnlinkQueueHead(PQUEUE_HEAD QueueHead
);
66 VOID
LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead
, PQUEUE_HEAD NewQueueHead
);
67 PQUEUE_HEAD
UnlinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead
, ULONG Count
);
69 // processes the async list
70 VOID
ProcessAsyncList(IN NTSTATUS Status
, OUT PULONG ShouldRingDoorBell
);
72 // called for each completed queue head
73 VOID
QueueHeadCompletion(PQUEUE_HEAD QueueHead
, NTSTATUS Status
);
75 // called when the completion queue is cleaned up
76 VOID
QueueHeadCleanup(PQUEUE_HEAD QueueHead
);
78 // intializes the sync schedule
79 NTSTATUS
InitializeSyncSchedule(IN PUSBHARDWAREDEVICE Hardware
, IN PDMAMEMORYMANAGER MemManager
);
82 //=================================================================================================
87 CUSBQueue::QueryInterface(
91 if (IsEqualGUIDAligned(refiid
, IID_IUnknown
))
93 *Output
= PVOID(PUNKNOWN(this));
94 PUNKNOWN(*Output
)->AddRef();
95 return STATUS_SUCCESS
;
98 return STATUS_UNSUCCESSFUL
;
102 CUSBQueue::Initialize(
103 IN PUSBHARDWAREDEVICE Hardware
,
104 IN PDMA_ADAPTER AdapterObject
,
105 IN PDMAMEMORYMANAGER MemManager
,
106 IN OPTIONAL PKSPIN_LOCK Lock
)
108 NTSTATUS Status
= STATUS_SUCCESS
;
110 DPRINT("CUSBQueue::Initialize()\n");
115 // initialize device lock
120 // Get the AsyncQueueHead
122 AsyncListQueueHead
= (PQUEUE_HEAD
)Hardware
->GetAsyncListQueueHead();
125 // Initialize the List Head
127 InitializeListHead(&AsyncListQueueHead
->LinkedQueueHeads
);
130 // Initialize completed async list head
132 InitializeListHead(&m_CompletedRequestAsyncList
);
135 // Initialize pending async list head
137 InitializeListHead(&m_PendingRequestAsyncList
);
140 // now initialize sync schedule
142 Status
= InitializeSyncSchedule(Hardware
, MemManager
);
148 CUSBQueue::InitializeSyncSchedule(
149 IN PUSBHARDWAREDEVICE Hardware
,
150 IN PDMAMEMORYMANAGER MemManager
)
152 PHYSICAL_ADDRESS QueueHeadPhysAddr
;
155 PQUEUE_HEAD QueueHead
;
158 // FIXME: check if smaller list sizes are supported
160 m_MaxPeriodicListEntries
= 1024;
163 // use polling scheme of 32ms
165 m_MaxPollingInterval
= 32;
168 // allocate dummy frame list array
170 m_SyncFrameListQueueHeads
= (PQUEUE_HEAD
*)ExAllocatePool(NonPagedPool
, m_MaxPollingInterval
* sizeof(PQUEUE_HEAD
));
171 if (!m_SyncFrameListQueueHeads
)
176 return STATUS_INSUFFICIENT_RESOURCES
;
181 // first allocate a page to hold the queue array
183 Status
= MemManager
->Allocate(m_MaxPeriodicListEntries
* sizeof(PVOID
), (PVOID
*)&m_SyncFrameList
, &m_SyncFrameListAddr
);
184 if (!NT_SUCCESS(Status
))
187 // failed to allocate sync frame list array
189 DPRINT1("Failed to allocate sync frame list\n");
190 ExFreePool(m_SyncFrameListQueueHeads
);
192 return STATUS_INSUFFICIENT_RESOURCES
;
196 // now allocate queue head descriptors for the polling interval
198 for(Index
= 0; Index
< m_MaxPeriodicListEntries
; Index
++)
201 // check if is inside our polling interrupt frequency window
203 if (Index
< m_MaxPollingInterval
)
206 // allocate queue head
208 Status
= MemManager
->Allocate(sizeof(QUEUE_HEAD
), (PVOID
*)&QueueHead
, &QueueHeadPhysAddr
);
211 // initialize queue head
213 QueueHead
->HorizontalLinkPointer
= TERMINATE_POINTER
;
214 QueueHead
->AlternateNextPointer
= TERMINATE_POINTER
;
215 QueueHead
->NextPointer
= TERMINATE_POINTER
;
218 // 1 for non high speed, 0 for high speed device
220 QueueHead
->EndPointCharacteristics
.ControlEndPointFlag
= 0;
221 QueueHead
->EndPointCharacteristics
.HeadOfReclamation
= FALSE
;
222 QueueHead
->EndPointCharacteristics
.MaximumPacketLength
= 64;
225 // Set NakCountReload to max value possible
227 QueueHead
->EndPointCharacteristics
.NakCountReload
= 0xF;
230 // Get the Initial Data Toggle from the QEDT
232 QueueHead
->EndPointCharacteristics
.QEDTDataToggleControl
= FALSE
;
235 // FIXME: check if High Speed Device
237 QueueHead
->EndPointCharacteristics
.EndPointSpeed
= QH_ENDPOINT_HIGHSPEED
;
238 QueueHead
->EndPointCapabilities
.NumberOfTransactionPerFrame
= 0x03;
239 QueueHead
->Token
.DWord
= 0;
240 QueueHead
->Token
.Bits
.InterruptOnComplete
= FALSE
;
241 QueueHead
->PhysicalAddr
= QueueHeadPhysAddr
.LowPart
;
245 // store in queue head array
247 m_SyncFrameListQueueHeads
[Index
] = QueueHead
;
254 QueueHead
= m_SyncFrameListQueueHeads
[m_MaxPeriodicListEntries
% m_MaxPollingInterval
];
260 m_SyncFrameList
[Index
] = (QueueHead
->PhysicalAddr
| 0x2);
264 // now set the sync base
266 Hardware
->SetPeriodicListRegister(m_SyncFrameListAddr
.LowPart
);
269 // sync frame list initialized
271 return STATUS_SUCCESS
;
275 CUSBQueue::GetPendingRequestCount()
278 // Loop through the pending list and iterrate one for each QueueHead that
279 // has a IRP to complete.
286 CUSBQueue::AddUSBRequest(
287 IUSBRequest
* Request
)
289 PQUEUE_HEAD QueueHead
;
297 ASSERT(Request
!= NULL
);
302 Type
= Request
->GetTransferType();
305 // check if supported
309 case USB_ENDPOINT_TYPE_ISOCHRONOUS
:
310 case USB_ENDPOINT_TYPE_INTERRUPT
:
311 /* NOT IMPLEMENTED IN QUEUE */
312 Status
= STATUS_NOT_SUPPORTED
;
314 case USB_ENDPOINT_TYPE_BULK
:
315 case USB_ENDPOINT_TYPE_CONTROL
:
316 Status
= STATUS_SUCCESS
;
321 Status
= STATUS_NOT_SUPPORTED
;
327 if (!NT_SUCCESS(Status
))
330 // request not supported, please try later
335 if (Type
== USB_ENDPOINT_TYPE_BULK
|| Type
== USB_ENDPOINT_TYPE_CONTROL
)
340 Status
= Request
->GetQueueHead(&QueueHead
);
345 if (!NT_SUCCESS(Status
))
348 // failed to get queue head
353 DPRINT("Request %p QueueHead %p inserted into AsyncQueue\n", Request
, QueueHead
);
356 // Add it to the pending list
358 DPRINT(__FUNCTION__
" acquire\n");
359 KeAcquireSpinLock(m_Lock
, &OldLevel
);
360 DPRINT(__FUNCTION__
" acquired\n");
362 LinkQueueHead(AsyncListQueueHead
, QueueHead
);
363 DPRINT(__FUNCTION__
"release\n");
364 KeReleaseSpinLock(m_Lock
, OldLevel
);
369 // add extra reference which is released when the request is completed
374 return STATUS_SUCCESS
;
378 CUSBQueue::AddUSBRequest(
382 return STATUS_NOT_IMPLEMENTED
;
386 CUSBQueue::CancelRequests()
389 return STATUS_NOT_IMPLEMENTED
;
393 CUSBQueue::CreateUSBRequest(
394 IUSBRequest
**OutRequest
)
396 PUSBREQUEST UsbRequest
;
400 Status
= InternalCreateUSBRequest(&UsbRequest
);
402 if (NT_SUCCESS(Status
))
404 *OutRequest
= UsbRequest
;
411 // LinkQueueHead - Links one QueueHead to the end of HeadQueueHead list, updating HorizontalLinkPointer.
414 CUSBQueue::LinkQueueHead(
415 PQUEUE_HEAD HeadQueueHead
,
416 PQUEUE_HEAD NewQueueHead
)
418 PQUEUE_HEAD LastQueueHead
, NextQueueHead
;
420 ASSERT(HeadQueueHead
);
421 ASSERT(NewQueueHead
);
424 // Link the LIST_ENTRYs
426 InsertTailList(&HeadQueueHead
->LinkedQueueHeads
, &NewQueueHead
->LinkedQueueHeads
);
429 // Update HLP for Previous QueueHead, which should be the last in list.
431 Entry
= NewQueueHead
->LinkedQueueHeads
.Blink
;
432 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
433 LastQueueHead
->HorizontalLinkPointer
= (NewQueueHead
->PhysicalAddr
| QH_TYPE_QH
);
436 // Update HLP for NewQueueHead to point to next, which should be the HeadQueueHead
438 Entry
= NewQueueHead
->LinkedQueueHeads
.Flink
;
439 NextQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
440 ASSERT(NextQueueHead
== HeadQueueHead
);
441 NewQueueHead
->HorizontalLinkPointer
= (NextQueueHead
->PhysicalAddr
| QH_TYPE_QH
);
445 // UnlinkQueueHead - Unlinks one QueueHead, updating HorizontalLinkPointer.
448 CUSBQueue::UnlinkQueueHead(
449 PQUEUE_HEAD QueueHead
)
451 PQUEUE_HEAD PreviousQH
, NextQH
;
455 // sanity check: there must be at least one queue head with halted bit set
457 PC_ASSERT(QueueHead
->Token
.Bits
.Halted
== 0);
462 Entry
= QueueHead
->LinkedQueueHeads
.Blink
;
465 // get queue head structure
467 PreviousQH
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
472 Entry
= QueueHead
->LinkedQueueHeads
.Flink
;
475 // get queue head structure
477 NextQH
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
482 ASSERT(QueueHead
->HorizontalLinkPointer
== (NextQH
->PhysicalAddr
| QH_TYPE_QH
));
485 // remove queue head from linked list
487 PreviousQH
->HorizontalLinkPointer
= NextQH
->PhysicalAddr
| QH_TYPE_QH
;
490 // remove software link
492 RemoveEntryList(&QueueHead
->LinkedQueueHeads
);
496 // LinkQueueHeadChain - Links a list of QueueHeads to the HeadQueueHead list, updating HorizontalLinkPointer.
499 CUSBQueue::LinkQueueHeadChain(
500 PQUEUE_HEAD HeadQueueHead
,
501 PQUEUE_HEAD NewQueueHead
)
503 PQUEUE_HEAD LastQueueHead
;
505 ASSERT(HeadQueueHead
);
506 ASSERT(NewQueueHead
);
509 // Find the last QueueHead in NewQueueHead
511 Entry
= NewQueueHead
->LinkedQueueHeads
.Blink
;
512 ASSERT(Entry
!= NewQueueHead
->LinkedQueueHeads
.Flink
);
513 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
516 // Set the LinkPointer and Flink
518 LastQueueHead
->HorizontalLinkPointer
= HeadQueueHead
->PhysicalAddr
| QH_TYPE_QH
;
519 LastQueueHead
->LinkedQueueHeads
.Flink
= &HeadQueueHead
->LinkedQueueHeads
;
522 // Fine the last QueueHead in HeadQueueHead
524 Entry
= HeadQueueHead
->LinkedQueueHeads
.Blink
;
525 HeadQueueHead
->LinkedQueueHeads
.Blink
= &LastQueueHead
->LinkedQueueHeads
;
526 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
527 LastQueueHead
->LinkedQueueHeads
.Flink
= &NewQueueHead
->LinkedQueueHeads
;
528 LastQueueHead
->HorizontalLinkPointer
= NewQueueHead
->PhysicalAddr
| QH_TYPE_QH
;
532 // UnlinkQueueHeadChain - Unlinks a list number of QueueHeads from HeadQueueHead list, updating HorizontalLinkPointer.
533 // returns the chain of QueueHeads removed from HeadQueueHead.
536 CUSBQueue::UnlinkQueueHeadChain(
537 PQUEUE_HEAD HeadQueueHead
,
540 PQUEUE_HEAD LastQueueHead
, FirstQueueHead
;
545 // Find the last QueueHead in NewQueueHead
547 Entry
= &HeadQueueHead
->LinkedQueueHeads
;
548 FirstQueueHead
= CONTAINING_RECORD(Entry
->Flink
, QUEUE_HEAD
, LinkedQueueHeads
);
550 for (Index
= 0; Index
< Count
; Index
++)
552 Entry
= Entry
->Flink
;
554 if (Entry
== &HeadQueueHead
->LinkedQueueHeads
)
556 DPRINT1("Warnnig; Only %d QueueHeads in HeadQueueHead\n", Index
);
562 LastQueueHead
= CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
563 HeadQueueHead
->LinkedQueueHeads
.Flink
= LastQueueHead
->LinkedQueueHeads
.Flink
;
564 if (Count
+ 1 == Index
)
566 HeadQueueHead
->LinkedQueueHeads
.Blink
= &HeadQueueHead
->LinkedQueueHeads
;
569 HeadQueueHead
->LinkedQueueHeads
.Blink
= LastQueueHead
->LinkedQueueHeads
.Flink
;
571 FirstQueueHead
->LinkedQueueHeads
.Blink
= &LastQueueHead
->LinkedQueueHeads
;
572 LastQueueHead
->LinkedQueueHeads
.Flink
= &FirstQueueHead
->LinkedQueueHeads
;
573 LastQueueHead
->HorizontalLinkPointer
= TERMINATE_POINTER
;
574 return FirstQueueHead
;
578 CUSBQueue::QueueHeadCompletion(
579 PQUEUE_HEAD CurrentQH
,
583 // now unlink the queue head
584 // FIXME: implement chained queue heads
585 // no need to acquire locks, as it is called with locks held
591 UnlinkQueueHead(CurrentQH
);
594 // insert into completed list
596 InsertTailList(&m_CompletedRequestAsyncList
, &CurrentQH
->LinkedQueueHeads
);
600 CUSBQueue::ProcessAsyncList(
602 OUT PULONG ShouldRingDoorBell
)
606 PQUEUE_HEAD QueueHead
;
607 IUSBRequest
* Request
;
608 BOOLEAN IsQueueHeadComplete
;
611 // lock completed async list
613 DPRINT(__FUNCTION__
" acquire\n");
614 KeAcquireSpinLock(m_Lock
, &OldLevel
);
615 DPRINT(__FUNCTION__
" acquired\n");
620 Entry
= AsyncListQueueHead
->LinkedQueueHeads
.Flink
;
622 while(Entry
!= &AsyncListQueueHead
->LinkedQueueHeads
)
625 // get queue head structure
627 QueueHead
= (PQUEUE_HEAD
)CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
632 PC_ASSERT(QueueHead
->Request
);
635 // get IUSBRequest interface
637 Request
= (IUSBRequest
*)QueueHead
->Request
;
640 // move to next entry
642 Entry
= Entry
->Flink
;
645 // check if queue head is complete
647 IsQueueHeadComplete
= Request
->IsQueueHeadComplete(QueueHead
);
649 DPRINT("Request %p QueueHead %p Complete %d\n", Request
, QueueHead
, IsQueueHeadComplete
);
652 // check if queue head is complete
654 if (IsQueueHeadComplete
)
657 // current queue head is complete
659 QueueHeadCompletion(QueueHead
, Status
);
662 // ring door bell is going to be necessary
664 *ShouldRingDoorBell
= TRUE
;
671 DPRINT(__FUNCTION__
"release\n");
672 KeReleaseSpinLock(m_Lock
, OldLevel
);
677 CUSBQueue::InterruptCallback(
679 OUT PULONG ShouldRingDoorBell
)
682 DPRINT("CUSBQueue::InterruptCallback\n");
685 // iterate asynchronous list
687 *ShouldRingDoorBell
= FALSE
;
688 ProcessAsyncList(Status
, ShouldRingDoorBell
);
691 // TODO: implement periodic schedule processing
696 CUSBQueue::QueueHeadCleanup(
697 PQUEUE_HEAD CurrentQH
)
699 PQUEUE_HEAD NewQueueHead
;
700 IUSBRequest
* Request
;
701 BOOLEAN ShouldReleaseWhenDone
;
702 USBD_STATUS UrbStatus
;
708 PC_ASSERT(CurrentQH
->Token
.Bits
.Active
== 0);
709 PC_ASSERT(CurrentQH
->Request
);
715 Request
= (IUSBRequest
*)CurrentQH
->Request
;
723 // check if the queue head was completed with errors
725 if (CurrentQH
->Token
.Bits
.Halted
)
727 if (CurrentQH
->Token
.Bits
.DataBufferError
)
732 UrbStatus
= USBD_STATUS_DATA_BUFFER_ERROR
;
734 else if (CurrentQH
->Token
.Bits
.BabbleDetected
)
739 UrbStatus
= USBD_STATUS_BABBLE_DETECTED
;
746 UrbStatus
= USBD_STATUS_STALL_PID
;
754 UrbStatus
= USBD_STATUS_SUCCESS
;
758 // Check if the transfer was completed and if UrbStatus is ok
760 if ((Request
->IsRequestComplete() == FALSE
) && (UrbStatus
== USBD_STATUS_SUCCESS
))
763 // let IUSBRequest free the queue head
765 Request
->FreeQueueHead(CurrentQH
);
768 // request is incomplete, get new queue head
770 if (Request
->GetQueueHead(&NewQueueHead
) == STATUS_SUCCESS
)
773 // first acquire request lock
775 DPRINT(__FUNCTION__
" acquire\n");
776 KeAcquireSpinLock(m_Lock
, &OldLevel
);
777 DPRINT(__FUNCTION__
" acquired\n");
780 // add to pending list
782 InsertTailList(&m_PendingRequestAsyncList
, &NewQueueHead
->LinkedQueueHeads
);
785 // release queue head
787 DPRINT(__FUNCTION__
"release\n");
788 KeReleaseSpinLock(m_Lock
, OldLevel
);
795 DPRINT1("Unable to create a new QueueHead\n");
799 // Else there was a problem
800 // FIXME: Find better return
801 UrbStatus
= USBD_STATUS_INSUFFICIENT_RESOURCES
;
804 if (UrbStatus
!= USBD_STATUS_SUCCESS
) PC_ASSERT(FALSE
);
807 // notify request that a transfer has completed
809 Request
->CompletionCallback(UrbStatus
!= USBD_STATUS_SUCCESS
? STATUS_UNSUCCESSFUL
: STATUS_SUCCESS
,
814 // let IUSBRequest free the queue head
816 Request
->FreeQueueHead(CurrentQH
);
819 // check if we should release request when done
821 ShouldReleaseWhenDone
= Request
->ShouldReleaseRequestAfterCompletion();
824 // release reference when the request was added
829 // check if the operation was asynchronous
831 if (ShouldReleaseWhenDone
)
834 // release outstanding reference count
840 // request is now released
845 CUSBQueue::CompleteAsyncRequests()
849 PQUEUE_HEAD CurrentQH
;
850 IUSBRequest
*Request
;
852 DPRINT("CUSBQueue::CompleteAsyncRequests\n");
855 // first acquire request lock
857 DPRINT(__FUNCTION__
" acquire\n");
858 KeAcquireSpinLock(m_Lock
, &OldLevel
);
859 DPRINT(__FUNCTION__
" acquired\n");
862 // the list should not be empty
864 PC_ASSERT(!IsListEmpty(&m_CompletedRequestAsyncList
));
866 while(!IsListEmpty(&m_CompletedRequestAsyncList
))
869 // remove first entry
871 Entry
= RemoveHeadList(&m_CompletedRequestAsyncList
);
874 // get queue head structure
876 CurrentQH
= (PQUEUE_HEAD
)CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
879 // Get the Request for this QueueHead
881 Request
= (IUSBRequest
*) CurrentQH
->Request
;
886 DPRINT(__FUNCTION__
"release\n");
887 KeReleaseSpinLock(m_Lock
, OldLevel
);
890 // complete request now
892 QueueHeadCleanup(CurrentQH
);
895 // first acquire request lock
897 DPRINT(__FUNCTION__
" acquire\n");
898 KeAcquireSpinLock(m_Lock
, &OldLevel
);
899 DPRINT(__FUNCTION__
" acquired\n");
904 // is there a pending async entry
906 if (!IsListEmpty(&m_PendingRequestAsyncList
))
909 // remove first entry
911 Entry
= RemoveHeadList(&m_PendingRequestAsyncList
);
914 // get queue head structure
916 CurrentQH
= (PQUEUE_HEAD
)CONTAINING_RECORD(Entry
, QUEUE_HEAD
, LinkedQueueHeads
);
919 // Add it to the AsyncList list
921 LinkQueueHead(AsyncListQueueHead
, CurrentQH
);
927 DPRINT(__FUNCTION__
"release\n");
928 KeReleaseSpinLock(m_Lock
, OldLevel
);
933 PUSBQUEUE
*OutUsbQueue
)
938 // allocate controller
940 This
= new(NonPagedPool
, TAG_USBEHCI
) CUSBQueue(0);
944 // failed to allocate
946 return STATUS_INSUFFICIENT_RESOURCES
;
950 // add reference count
957 *OutUsbQueue
= (PUSBQUEUE
)This
;
962 return STATUS_SUCCESS
;