mirror of
https://github.com/reactos/reactos.git
synced 2025-01-04 05:20:54 +00:00
[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:
parent
4dff45da57
commit
982eb59ba0
4 changed files with 227 additions and 0 deletions
|
@ -194,6 +194,7 @@ typedef struct _QUEUE_HEAD
|
|||
PIRP IrpToComplete;
|
||||
PMDL Mdl;
|
||||
PKEVENT Event;
|
||||
PVOID Request;
|
||||
} QUEUE_HEAD, *PQUEUE_HEAD;
|
||||
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue