From 982eb59ba0d19eb10f794c5710e16b35ddb6c15e Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Sat, 23 Apr 2011 19:36:23 +0000 Subject: [PATCH] [USBEHCI_NEW] - Create member for storing the request object - Add interface function which is invoked when the queue head should be freed - Add support functions which deal with completed queue heads svn path=/branches/usb-bringup/; revision=51440 --- drivers/usb/usbehci_new/hardware.h | 1 + drivers/usb/usbehci_new/interfaces.h | 8 ++ drivers/usb/usbehci_new/usb_queue.cpp | 160 ++++++++++++++++++++++++ drivers/usb/usbehci_new/usb_request.cpp | 58 +++++++++ 4 files changed, 227 insertions(+) diff --git a/drivers/usb/usbehci_new/hardware.h b/drivers/usb/usbehci_new/hardware.h index a6047caa5be..321e9a92522 100644 --- a/drivers/usb/usbehci_new/hardware.h +++ b/drivers/usb/usbehci_new/hardware.h @@ -194,6 +194,7 @@ typedef struct _QUEUE_HEAD PIRP IrpToComplete; PMDL Mdl; PKEVENT Event; + PVOID Request; } QUEUE_HEAD, *PQUEUE_HEAD; // diff --git a/drivers/usb/usbehci_new/interfaces.h b/drivers/usb/usbehci_new/interfaces.h index 591dba24fa6..26c757b9fe5 100644 --- a/drivers/usb/usbehci_new/interfaces.h +++ b/drivers/usb/usbehci_new/interfaces.h @@ -474,6 +474,14 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) // If the request was initialized with an setup packet, it will return false virtual BOOLEAN ShouldReleaseRequestAfterCompletion() = 0; + +//---------------------------------------------------------------------------------------- +// +// FreeQueueHead +// +// Description: frees the queue head with the associated transfer descriptors + + virtual VOID FreeQueueHead(struct _QUEUE_HEAD * QueueHead) = 0; }; typedef IUSBRequest *PUSBREQUEST; diff --git a/drivers/usb/usbehci_new/usb_queue.cpp b/drivers/usb/usbehci_new/usb_queue.cpp index 50540fc931c..7bae9c680cc 100644 --- a/drivers/usb/usbehci_new/usb_queue.cpp +++ b/drivers/usb/usbehci_new/usb_queue.cpp @@ -51,10 +51,17 @@ protected: PQUEUE_HEAD AsyncListQueueHead; PQUEUE_HEAD PendingListQueueHead; + // queue head manipulation functions VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead); VOID UnlinkQueueHead(PQUEUE_HEAD QueueHead); VOID LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead); PQUEUE_HEAD UnlinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, ULONG Count); + + // called for each completed queue head + NTSTATUS QueueHeadCompletion(PQUEUE_HEAD QueueHead, NTSTATUS Status); + + // called when the completion queue is cleaned up + VOID QueueHeadCleanup(PQUEUE_HEAD QueueHead); }; //================================================================================================= @@ -142,6 +149,11 @@ CUSBQueue::AddUSBRequest( // LinkQueueHead(PendingListQueueHead, QueueHead); + // + // add extra reference which is released when the request is completed + // + Request->AddRef(); + return STATUS_SUCCESS; } @@ -314,6 +326,154 @@ CUSBQueue::UnlinkQueueHeadChain( return FirstQueueHead; } +NTSTATUS +CUSBQueue::QueueHeadCompletion( + PQUEUE_HEAD CurrentQH, + NTSTATUS Status) +{ + IUSBRequest *Request; + USBD_STATUS UrbStatus; + PQUEUE_HEAD NewQueueHead; + + // + // this function is called when a queue head has been completed + // + PC_ASSERT(CurrentQH->Token.Bits.Active == 0); + + // + // get contained usb request + // + Request = (IUSBRequest*)CurrentQH->Request; + + // + // sanity check + // + PC_ASSERT(Request); + + // + // check if the queue head was completed with errors + // + if (CurrentQH->Token.Bits.Halted) + { + if (CurrentQH->Token.Bits.DataBufferError) + { + // + // data buffer error + // + UrbStatus = USBD_STATUS_DATA_BUFFER_ERROR; + } + else if (CurrentQH->Token.Bits.BabbleDetected) + { + // + // babble detected + // + UrbStatus = USBD_STATUS_BABBLE_DETECTED; + } + else + { + // + // stall pid + // + UrbStatus = USBD_STATUS_STALL_PID; + } + } + else + { + // + // well done ;) + // + UrbStatus = USBD_STATUS_SUCCESS; + } + + // + // notify request that a queue head has been completed + // + Request->CompletionCallback(Status, UrbStatus, CurrentQH); + + // + // now unlink the queue head + // FIXME: implement chained queue heads + // + UnlinkQueueHead(CurrentQH); + + // + // check if the request is complete + // + if (Request->IsRequestComplete() == FALSE) + { + // + // request is still in complete + // get new queue head + // + Status = Request->GetQueueHead(&NewQueueHead); + + // + // add to pending list + // + LinkQueueHead(PendingListQueueHead, NewQueueHead); + } + else + { + // + // FIXME: put queue head into completed queue head list + // + } + + // + // done + // + return STATUS_SUCCESS; +} + +VOID +CUSBQueue::QueueHeadCleanup( + PQUEUE_HEAD CurrentQH) +{ + IUSBRequest * Request; + BOOLEAN ShouldReleaseWhenDone; + + // + // sanity checks + // + PC_ASSERT(CurrentQH->Token.Bits.Active == 0); + PC_ASSERT(CurrentQH->Request); + + // + // get request + // + Request = (IUSBRequest*)CurrentQH->Request; + + // + // let IUSBRequest free the queue head + // + Request->FreeQueueHead(CurrentQH); + + // + // check if we should release request when done + // + ShouldReleaseWhenDone = Request->ShouldReleaseRequestAfterCompletion(); + + // + // release reference when the request was added + // + Request->Release(); + + // + // check if the operation was asynchronous + // + if (ShouldReleaseWhenDone) + { + // + // release outstanding reference count + // + Request->Release(); + } + + // + // request is now released + // +} + NTSTATUS CreateUSBQueue( PUSBQUEUE *OutUsbQueue) diff --git a/drivers/usb/usbehci_new/usb_request.cpp b/drivers/usb/usbehci_new/usb_request.cpp index 013ab6eb27d..680cd6bc722 100644 --- a/drivers/usb/usbehci_new/usb_request.cpp +++ b/drivers/usb/usbehci_new/usb_request.cpp @@ -46,6 +46,7 @@ public: virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode); virtual BOOLEAN IsRequestInitialized(); virtual BOOLEAN ShouldReleaseRequestAfterCompletion(); + virtual VOID FreeQueueHead(struct _QUEUE_HEAD * QueueHead); // local functions ULONG InternalGetTransferType(); @@ -416,6 +417,11 @@ CUSBRequest::GetQueueHead( // store queue head // m_QueueHead = *OutHead; + + // + // store request object + // + (*OutHead)->Request = PVOID(this); } // @@ -936,6 +942,58 @@ CUSBRequest::ShouldReleaseRequestAfterCompletion() } } +//----------------------------------------------------------------------------------------- +VOID +CUSBRequest::FreeQueueHead( + IN struct _QUEUE_HEAD * QueueHead) +{ + // + // FIXME: support chained queue heads + // + PC_ASSERT(QueueHead == m_QueueHead); + + // + // release queue head + // + m_DmaManager->Release(QueueHead, sizeof(QUEUE_HEAD)); + + // + // nullify pointer + // + m_QueueHead = 0; + + // + // release transfer descriptors + // + + if (m_TransferDescriptors[0]) + { + // + // release transfer descriptors + // + m_DmaManager->Release(m_TransferDescriptors[0], sizeof(QUEUE_TRANSFER_DESCRIPTOR)); + m_TransferDescriptors[0] = 0; + } + + if (m_TransferDescriptors[1]) + { + // + // release transfer descriptors + // + m_DmaManager->Release(m_TransferDescriptors[1], sizeof(QUEUE_TRANSFER_DESCRIPTOR)); + m_TransferDescriptors[1] = 0; + } + + if (m_TransferDescriptors[2]) + { + // + // release transfer descriptors + // + m_DmaManager->Release(m_TransferDescriptors[2], sizeof(QUEUE_TRANSFER_DESCRIPTOR)); + m_TransferDescriptors[2] = 0; + } +} + NTSTATUS InternalCreateUSBRequest( PUSBREQUEST *OutRequest)