mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
[USBEHCI_NEW]
- Return the physical address of the async queue head in CUSBHardwareDevice::GetAsyncListRegister - Remove superflous entries from queue head structure, they are processed within IUSBRequest class - Remove USBHI_GetPortHackFlags, this function has been deprecated - Add interface functions for IUSBRequest / IUSBQueue - Callback into IUSBQueue when a hardware interrupt arrives - Implement callback function to check for completed queue heads / free completed queue head depending on the Async Advance interrupt bit svn path=/branches/usb-bringup/; revision=51466
This commit is contained in:
parent
346a95197f
commit
591cffee7c
6 changed files with 386 additions and 55 deletions
|
@ -87,30 +87,39 @@ public:
|
|||
virtual ~CUSBHardwareDevice(){}
|
||||
|
||||
protected:
|
||||
LONG m_Ref;
|
||||
PDRIVER_OBJECT m_DriverObject;
|
||||
PDEVICE_OBJECT m_PhysicalDeviceObject;
|
||||
PDEVICE_OBJECT m_FunctionalDeviceObject;
|
||||
PDEVICE_OBJECT m_NextDeviceObject;
|
||||
KSPIN_LOCK m_Lock;
|
||||
PKINTERRUPT m_Interrupt;
|
||||
KDPC m_IntDpcObject;
|
||||
PVOID VirtualBase;
|
||||
PHYSICAL_ADDRESS PhysicalAddress;
|
||||
PULONG m_Base;
|
||||
PDMA_ADAPTER m_Adapter;
|
||||
ULONG m_MapRegisters;
|
||||
EHCI_CAPS m_Capabilities;
|
||||
USHORT m_VendorID;
|
||||
USHORT m_DeviceID;
|
||||
PQUEUE_HEAD AsyncQueueHead;
|
||||
PUSBQUEUE m_UsbQueue;
|
||||
PDMAMEMORYMANAGER m_MemoryManager;
|
||||
HD_INIT_CALLBACK* m_SCECallBack;
|
||||
PVOID m_SCEContext;
|
||||
LONG m_Ref; // reference count
|
||||
PDRIVER_OBJECT m_DriverObject; // driver object
|
||||
PDEVICE_OBJECT m_PhysicalDeviceObject; // pdo
|
||||
PDEVICE_OBJECT m_FunctionalDeviceObject; // fdo (hcd controller)
|
||||
PDEVICE_OBJECT m_NextDeviceObject; // lower device object
|
||||
KSPIN_LOCK m_Lock; // hardware lock
|
||||
PKINTERRUPT m_Interrupt; // interrupt object
|
||||
KDPC m_IntDpcObject; // dpc object for deferred isr processing
|
||||
PVOID VirtualBase; // virtual base for memory manager
|
||||
PHYSICAL_ADDRESS PhysicalAddress; // physical base for memory manager
|
||||
PULONG m_Base; // EHCI operational port base registers
|
||||
PDMA_ADAPTER m_Adapter; // dma adapter object
|
||||
ULONG m_MapRegisters; // map registers count
|
||||
EHCI_CAPS m_Capabilities; // EHCI caps
|
||||
USHORT m_VendorID; // vendor id
|
||||
USHORT m_DeviceID; // device id
|
||||
PQUEUE_HEAD AsyncQueueHead; // async queue head terminator
|
||||
PUSBQUEUE m_UsbQueue; // usb request queue
|
||||
PDMAMEMORYMANAGER m_MemoryManager; // memory manager
|
||||
HD_INIT_CALLBACK* m_SCECallBack; // status change callback routine
|
||||
PVOID m_SCEContext; // status change callback routine context
|
||||
BOOLEAN m_DoorBellRingInProgress; // door bell ring in progress
|
||||
|
||||
// set command
|
||||
VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
|
||||
|
||||
// get command
|
||||
VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
|
||||
|
||||
// read register
|
||||
ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
|
||||
|
||||
// write register
|
||||
VOID EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value);
|
||||
};
|
||||
|
||||
|
@ -315,6 +324,7 @@ CUSBHardwareDevice::PnpStart(
|
|||
m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 8));
|
||||
|
||||
DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount);
|
||||
DPRINT1("Controller EHCI Version %x\n", m_Capabilities.HCIVersion);
|
||||
if (m_Capabilities.HCSParams.PortRouteRules)
|
||||
{
|
||||
for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++)
|
||||
|
@ -850,7 +860,7 @@ CUSBHardwareDevice::SetPeriodicListRegister(
|
|||
ULONG
|
||||
CUSBHardwareDevice::GetAsyncListRegister()
|
||||
{
|
||||
return PhysicalAddress.LowPart;
|
||||
return AsyncQueueHead->PhysicalAddr;
|
||||
}
|
||||
|
||||
ULONG CUSBHardwareDevice::GetPeriodicListRegister()
|
||||
|
@ -946,11 +956,86 @@ EhciDefferedRoutine(
|
|||
IN PVOID SystemArgument2)
|
||||
{
|
||||
CUSBHardwareDevice *This;
|
||||
ULONG CStatus, PortStatus, PortCount, i;
|
||||
ULONG CStatus, PortStatus, PortCount, i, ShouldRingDoorBell;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
EHCI_USBCMD_CONTENT UsbCmd;
|
||||
|
||||
This = (CUSBHardwareDevice*) SystemArgument1;
|
||||
CStatus = (ULONG) SystemArgument2;
|
||||
|
||||
|
||||
//
|
||||
// check for completion of async schedule
|
||||
//
|
||||
if (CStatus & (EHCI_STS_RECL| EHCI_STS_INT | EHCI_ERROR_INT))
|
||||
{
|
||||
if (CStatus & EHCI_ERROR_INT)
|
||||
{
|
||||
//
|
||||
// controller reported error
|
||||
//
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
//
|
||||
// check if there is a door bell ring in progress
|
||||
//
|
||||
if (This->m_DoorBellRingInProgress == FALSE)
|
||||
{
|
||||
//
|
||||
// inform IUSBQueue of a completed queue head
|
||||
//
|
||||
This->m_UsbQueue->InterruptCallback(Status, &ShouldRingDoorBell);
|
||||
|
||||
//
|
||||
// was a queue head completed?
|
||||
//
|
||||
if (ShouldRingDoorBell)
|
||||
{
|
||||
//
|
||||
// set door ring bell in progress status flag
|
||||
//
|
||||
This->m_DoorBellRingInProgress = TRUE;
|
||||
|
||||
//
|
||||
// get command register
|
||||
//
|
||||
This->GetCommandRegister(&UsbCmd);
|
||||
|
||||
//
|
||||
// set door rang bell bit
|
||||
//
|
||||
UsbCmd.DoorBell = TRUE;
|
||||
|
||||
//
|
||||
// update command status
|
||||
//
|
||||
This->SetCommandRegister(&UsbCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// check if the controller has acknowledged the door bell
|
||||
//
|
||||
if (CStatus & EHCI_STS_IAA)
|
||||
{
|
||||
//
|
||||
// controller has acknowledged, assert we rang the bell
|
||||
//
|
||||
PC_ASSERT(This->m_DoorBellRingInProgress == TRUE);
|
||||
|
||||
//
|
||||
// now notify IUSBQueue that it can free completed requests
|
||||
//
|
||||
This->m_UsbQueue->CompleteAsyncRequests();
|
||||
|
||||
//
|
||||
// door ring bell completed
|
||||
//
|
||||
This->m_DoorBellRingInProgress = FALSE;
|
||||
}
|
||||
|
||||
This->GetDeviceDetails(NULL, NULL, &PortCount, NULL);
|
||||
if (CStatus & EHCI_STS_PCD)
|
||||
{
|
||||
|
|
|
@ -190,10 +190,6 @@ typedef struct _QUEUE_HEAD
|
|||
//Software
|
||||
ULONG PhysicalAddr;
|
||||
LIST_ENTRY LinkedQueueHeads;
|
||||
PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor;
|
||||
PIRP IrpToComplete;
|
||||
PMDL Mdl;
|
||||
PKEVENT Event;
|
||||
PVOID Request;
|
||||
} QUEUE_HEAD, *PQUEUE_HEAD;
|
||||
|
||||
|
|
|
@ -1986,16 +1986,6 @@ USBHI_RestoreUsbDevice(
|
|||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
USB_BUSIFFN
|
||||
USBHI_GetPortHackFlags(
|
||||
PVOID BusContext,
|
||||
PULONG Flags)
|
||||
{
|
||||
UNIMPLEMENTED
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
USB_BUSIFFN
|
||||
USBHI_QueryDeviceInformation(
|
||||
|
@ -2565,7 +2555,6 @@ CHubController::HandleQueryInterface(
|
|||
InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors;
|
||||
InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice;
|
||||
InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice;
|
||||
InterfaceHub->GetPortHackFlags = USBHI_GetPortHackFlags;
|
||||
InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation;
|
||||
}
|
||||
|
||||
|
|
|
@ -482,8 +482,27 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
|||
// Description: frees the queue head with the associated transfer descriptors
|
||||
|
||||
virtual VOID FreeQueueHead(struct _QUEUE_HEAD * QueueHead) = 0;
|
||||
|
||||
//---------------------------------------------------------------------------------------
|
||||
//
|
||||
// GetTransferBuffer
|
||||
//
|
||||
// Description: this function returns the transfer buffer mdl and length
|
||||
// Used by IUSBQueue for mapping buffer contents with DMA
|
||||
|
||||
virtual VOID GetTransferBuffer(OUT PMDL * OutMDL,
|
||||
OUT PULONG TransferLength) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
//
|
||||
// IsQueueHeadComplete
|
||||
//
|
||||
// Description: returns true when the queue head which was passed as a parameter has been completed
|
||||
|
||||
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead) = 0;
|
||||
};
|
||||
|
||||
|
||||
typedef IUSBRequest *PUSBREQUEST;
|
||||
|
||||
//=========================================================================================
|
||||
|
@ -539,6 +558,24 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown)
|
|||
// Description: creates an usb request
|
||||
|
||||
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
//
|
||||
// InterruptCallback
|
||||
//
|
||||
// Description: callback when the periodic / asynchronous queue has been completed / queue head been completed
|
||||
|
||||
virtual VOID InterruptCallback(IN NTSTATUS Status, OUT PULONG ShouldRingDoorBell) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
//
|
||||
// CompleteAsyncRequests
|
||||
//
|
||||
// Description: once a request has been completed it is moved to pending queue. Since a queue head should only be freed
|
||||
// after a door bell ring, this needs some synchronization.
|
||||
// This function gets called by IUSBHardware after it the Interrupt on Async Advance bit has been set
|
||||
|
||||
virtual VOID CompleteAsyncRequests() = 0;
|
||||
};
|
||||
|
||||
typedef IUSBQueue *PUSBQUEUE;
|
||||
|
|
|
@ -33,12 +33,14 @@ public:
|
|||
return m_Ref;
|
||||
}
|
||||
|
||||
NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock);
|
||||
ULONG GetPendingRequestCount();
|
||||
NTSTATUS AddUSBRequest(PURB Urb);
|
||||
NTSTATUS AddUSBRequest(IUSBRequest * Request);
|
||||
NTSTATUS CancelRequests();
|
||||
NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
||||
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock);
|
||||
virtual ULONG GetPendingRequestCount();
|
||||
virtual NTSTATUS AddUSBRequest(PURB Urb);
|
||||
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request);
|
||||
virtual NTSTATUS CancelRequests();
|
||||
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
||||
virtual VOID InterruptCallback(IN NTSTATUS Status, OUT PULONG ShouldRingDoorBell);
|
||||
virtual VOID CompleteAsyncRequests();
|
||||
|
||||
// constructor / destructor
|
||||
CUSBQueue(IUnknown *OuterUnknown){}
|
||||
|
@ -50,6 +52,7 @@ protected:
|
|||
PDMA_ADAPTER m_Adapter;
|
||||
PQUEUE_HEAD AsyncListQueueHead;
|
||||
PQUEUE_HEAD PendingListQueueHead;
|
||||
LIST_ENTRY m_CompletedRequestAsyncList;
|
||||
|
||||
// queue head manipulation functions
|
||||
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
|
||||
|
@ -57,8 +60,11 @@ protected:
|
|||
VOID LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
|
||||
PQUEUE_HEAD UnlinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, ULONG Count);
|
||||
|
||||
// processes the async list
|
||||
VOID ProcessAsyncList(IN NTSTATUS Status, OUT PULONG ShouldRingDoorBell);
|
||||
|
||||
// called for each completed queue head
|
||||
NTSTATUS QueueHeadCompletion(PQUEUE_HEAD QueueHead, NTSTATUS Status);
|
||||
VOID QueueHeadCompletion(PQUEUE_HEAD QueueHead, NTSTATUS Status);
|
||||
|
||||
// called when the completion queue is cleaned up
|
||||
VOID QueueHeadCleanup(PQUEUE_HEAD QueueHead);
|
||||
|
@ -120,6 +126,17 @@ CUSBQueue::Initialize(
|
|||
//
|
||||
InitializeListHead(&PendingListQueueHead->LinkedQueueHeads);
|
||||
|
||||
//
|
||||
// fake the queue head as the first queue head
|
||||
//
|
||||
PendingListQueueHead->PhysicalAddr = ((ULONG_PTR)AsyncListQueueHead | QH_TYPE_QH);
|
||||
|
||||
//
|
||||
// Initialize completed async list head
|
||||
//
|
||||
InitializeListHead(&m_CompletedRequestAsyncList);
|
||||
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -234,13 +251,44 @@ CUSBQueue::UnlinkQueueHead(
|
|||
PQUEUE_HEAD PreviousQH, NextQH;
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
//
|
||||
// sanity check: there must be at least one queue head with halted bit set
|
||||
//
|
||||
PC_ASSERT(QueueHead->Token.Bits.Halted == 0);
|
||||
|
||||
//
|
||||
// get previous link
|
||||
//
|
||||
Entry = QueueHead->LinkedQueueHeads.Blink;
|
||||
|
||||
//
|
||||
// get queue head structure
|
||||
//
|
||||
PreviousQH = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
||||
|
||||
//
|
||||
// get next link
|
||||
//
|
||||
Entry = QueueHead->LinkedQueueHeads.Flink;
|
||||
|
||||
//
|
||||
// get queue head structure
|
||||
//
|
||||
NextQH = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
||||
|
||||
//
|
||||
// sanity check
|
||||
//
|
||||
ASSERT(QueueHead->HorizontalLinkPointer == (NextQH->PhysicalAddr | QH_TYPE_QH));
|
||||
|
||||
//
|
||||
// remove queue head from linked list
|
||||
//
|
||||
PreviousQH->HorizontalLinkPointer = NextQH->PhysicalAddr | QH_TYPE_QH;
|
||||
|
||||
//
|
||||
// remove software link
|
||||
//
|
||||
RemoveEntryList(&QueueHead->LinkedQueueHeads);
|
||||
}
|
||||
|
||||
|
@ -326,7 +374,7 @@ CUSBQueue::UnlinkQueueHeadChain(
|
|||
return FirstQueueHead;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
VOID
|
||||
CUSBQueue::QueueHeadCompletion(
|
||||
PQUEUE_HEAD CurrentQH,
|
||||
NTSTATUS Status)
|
||||
|
@ -415,14 +463,94 @@ CUSBQueue::QueueHeadCompletion(
|
|||
else
|
||||
{
|
||||
//
|
||||
// FIXME: put queue head into completed queue head list
|
||||
// put queue head into completed queue head list
|
||||
//
|
||||
InsertTailList(&m_CompletedRequestAsyncList, &CurrentQH->LinkedQueueHeads);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
CUSBQueue::ProcessAsyncList(
|
||||
IN NTSTATUS Status,
|
||||
OUT PULONG ShouldRingDoorBell)
|
||||
{
|
||||
KIRQL OldLevel;
|
||||
PLIST_ENTRY Entry;
|
||||
PQUEUE_HEAD QueueHead;
|
||||
IUSBRequest * Request;
|
||||
|
||||
//
|
||||
// lock completed async list
|
||||
//
|
||||
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
||||
|
||||
//
|
||||
// walk async list
|
||||
//
|
||||
Entry = PendingListQueueHead->LinkedQueueHeads.Flink;
|
||||
|
||||
while(Entry != &PendingListQueueHead->LinkedQueueHeads)
|
||||
{
|
||||
//
|
||||
// get queue head structure
|
||||
//
|
||||
QueueHead = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
||||
|
||||
//
|
||||
// sanity check
|
||||
//
|
||||
PC_ASSERT(QueueHead->Request);
|
||||
|
||||
//
|
||||
// get IUSBRequest interface
|
||||
//
|
||||
Request = (IUSBRequest*)QueueHead->Request;
|
||||
|
||||
|
||||
//
|
||||
// move to next entry
|
||||
//
|
||||
Entry = Entry->Flink;
|
||||
|
||||
//
|
||||
// check if queue head is complete
|
||||
//
|
||||
if (Request->IsQueueHeadComplete(QueueHead))
|
||||
{
|
||||
//
|
||||
// current queue head is complete
|
||||
//
|
||||
QueueHeadCompletion(QueueHead, Status);
|
||||
|
||||
//
|
||||
// ring door bell is going to be necessary
|
||||
//
|
||||
*ShouldRingDoorBell = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// done
|
||||
// release lock
|
||||
//
|
||||
KeReleaseSpinLock(&m_Lock, OldLevel);
|
||||
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CUSBQueue::InterruptCallback(
|
||||
IN NTSTATUS Status,
|
||||
OUT PULONG ShouldRingDoorBell)
|
||||
{
|
||||
//
|
||||
// iterate asynchronous list
|
||||
//
|
||||
*ShouldRingDoorBell = FALSE;
|
||||
ProcessAsyncList(Status, ShouldRingDoorBell);
|
||||
|
||||
//
|
||||
// TODO: implement periodic schedule processing
|
||||
//
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
|
@ -474,6 +602,47 @@ CUSBQueue::QueueHeadCleanup(
|
|||
//
|
||||
}
|
||||
|
||||
VOID
|
||||
CUSBQueue::CompleteAsyncRequests()
|
||||
{
|
||||
KIRQL OldLevel;
|
||||
PLIST_ENTRY Entry;
|
||||
PQUEUE_HEAD CurrentQH;
|
||||
|
||||
//
|
||||
// first acquire request lock
|
||||
//
|
||||
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
||||
|
||||
//
|
||||
// the list should not be empty
|
||||
//
|
||||
PC_ASSERT(!IsListEmpty(&m_CompletedRequestAsyncList));
|
||||
|
||||
while(!IsListEmpty(&m_CompletedRequestAsyncList))
|
||||
{
|
||||
//
|
||||
// remove first entry
|
||||
//
|
||||
Entry = RemoveHeadList(&m_CompletedRequestAsyncList);
|
||||
|
||||
//
|
||||
// get queue head structure
|
||||
//
|
||||
CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
||||
|
||||
//
|
||||
// complete request now
|
||||
//
|
||||
QueueHeadCleanup(CurrentQH);
|
||||
}
|
||||
|
||||
//
|
||||
// release lock
|
||||
//
|
||||
KeReleaseSpinLock(&m_Lock, OldLevel);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
CreateUSBQueue(
|
||||
PUSBQUEUE *OutUsbQueue)
|
||||
|
|
|
@ -47,6 +47,9 @@ public:
|
|||
virtual BOOLEAN IsRequestInitialized();
|
||||
virtual BOOLEAN ShouldReleaseRequestAfterCompletion();
|
||||
virtual VOID FreeQueueHead(struct _QUEUE_HEAD * QueueHead);
|
||||
virtual VOID GetTransferBuffer(OUT PMDL * OutMDL, OUT PULONG TransferLength);
|
||||
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
||||
|
||||
|
||||
// local functions
|
||||
ULONG InternalGetTransferType();
|
||||
|
@ -640,12 +643,6 @@ CUSBRequest::BuildControlTransferQueueHead(
|
|||
m_TransferDescriptors[1]->Token.Bits.InterruptOnComplete = TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
// Control Transfers have only one in or out buffer if one at all. Put in the QueueHead the
|
||||
// same as BulkTransfers. USBQueue will use the Mdl to fill in the BufferPointers
|
||||
//
|
||||
QueueHead->Mdl = m_TransferBufferMDL;
|
||||
|
||||
//
|
||||
// link setup packet into buffer - Physical Address!!!
|
||||
//
|
||||
|
@ -1149,6 +1146,64 @@ CUSBRequest::FreeQueueHead(
|
|||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
BOOLEAN
|
||||
CUSBRequest::IsQueueHeadComplete(
|
||||
struct _QUEUE_HEAD * QueueHead)
|
||||
{
|
||||
ULONG Index;
|
||||
|
||||
//
|
||||
// first check - is the queue head currently active
|
||||
//
|
||||
if (QueueHead->Token.Bits.Active)
|
||||
{
|
||||
//
|
||||
// queue head is active (currently processed)
|
||||
//
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: support chained queue heads
|
||||
//
|
||||
for(Index = 0; Index < 3; Index++)
|
||||
{
|
||||
//
|
||||
// check transfer descriptors for completion
|
||||
//
|
||||
if (m_TransferDescriptors[Index])
|
||||
{
|
||||
//
|
||||
// check for serious error
|
||||
//
|
||||
PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Halted == 0);
|
||||
|
||||
//
|
||||
// the transfer descriptor should be in the same state as the queue head
|
||||
//
|
||||
PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Active == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
VOID
|
||||
CUSBRequest::GetTransferBuffer(
|
||||
OUT PMDL * OutMDL,
|
||||
OUT PULONG TransferLength)
|
||||
{
|
||||
// sanity checks
|
||||
PC_ASSERT(OutMDL);
|
||||
PC_ASSERT(TransferLength);
|
||||
|
||||
*OutMDL = m_TransferBufferMDL;
|
||||
*TransferLength = m_TransferBufferLength;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
NTSTATUS
|
||||
InternalCreateUSBRequest(
|
||||
PUSBREQUEST *OutRequest)
|
||||
|
|
Loading…
Reference in a new issue