[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
This commit is contained in:
Johannes Anderwald 2011-04-23 19:36:23 +00:00
parent 4dff45da57
commit 982eb59ba0
4 changed files with 227 additions and 0 deletions

View file

@ -194,6 +194,7 @@ typedef struct _QUEUE_HEAD
PIRP IrpToComplete;
PMDL Mdl;
PKEVENT Event;
PVOID Request;
} QUEUE_HEAD, *PQUEUE_HEAD;
//

View file

@ -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;

View file

@ -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)

View file

@ -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)