mirror of
https://github.com/reactos/reactos.git
synced 2025-02-25 01:39:30 +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(){}
|
virtual ~CUSBHardwareDevice(){}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LONG m_Ref;
|
LONG m_Ref; // reference count
|
||||||
PDRIVER_OBJECT m_DriverObject;
|
PDRIVER_OBJECT m_DriverObject; // driver object
|
||||||
PDEVICE_OBJECT m_PhysicalDeviceObject;
|
PDEVICE_OBJECT m_PhysicalDeviceObject; // pdo
|
||||||
PDEVICE_OBJECT m_FunctionalDeviceObject;
|
PDEVICE_OBJECT m_FunctionalDeviceObject; // fdo (hcd controller)
|
||||||
PDEVICE_OBJECT m_NextDeviceObject;
|
PDEVICE_OBJECT m_NextDeviceObject; // lower device object
|
||||||
KSPIN_LOCK m_Lock;
|
KSPIN_LOCK m_Lock; // hardware lock
|
||||||
PKINTERRUPT m_Interrupt;
|
PKINTERRUPT m_Interrupt; // interrupt object
|
||||||
KDPC m_IntDpcObject;
|
KDPC m_IntDpcObject; // dpc object for deferred isr processing
|
||||||
PVOID VirtualBase;
|
PVOID VirtualBase; // virtual base for memory manager
|
||||||
PHYSICAL_ADDRESS PhysicalAddress;
|
PHYSICAL_ADDRESS PhysicalAddress; // physical base for memory manager
|
||||||
PULONG m_Base;
|
PULONG m_Base; // EHCI operational port base registers
|
||||||
PDMA_ADAPTER m_Adapter;
|
PDMA_ADAPTER m_Adapter; // dma adapter object
|
||||||
ULONG m_MapRegisters;
|
ULONG m_MapRegisters; // map registers count
|
||||||
EHCI_CAPS m_Capabilities;
|
EHCI_CAPS m_Capabilities; // EHCI caps
|
||||||
USHORT m_VendorID;
|
USHORT m_VendorID; // vendor id
|
||||||
USHORT m_DeviceID;
|
USHORT m_DeviceID; // device id
|
||||||
PQUEUE_HEAD AsyncQueueHead;
|
PQUEUE_HEAD AsyncQueueHead; // async queue head terminator
|
||||||
PUSBQUEUE m_UsbQueue;
|
PUSBQUEUE m_UsbQueue; // usb request queue
|
||||||
PDMAMEMORYMANAGER m_MemoryManager;
|
PDMAMEMORYMANAGER m_MemoryManager; // memory manager
|
||||||
HD_INIT_CALLBACK* m_SCECallBack;
|
HD_INIT_CALLBACK* m_SCECallBack; // status change callback routine
|
||||||
PVOID m_SCEContext;
|
PVOID m_SCEContext; // status change callback routine context
|
||||||
|
BOOLEAN m_DoorBellRingInProgress; // door bell ring in progress
|
||||||
|
|
||||||
|
// set command
|
||||||
VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
|
VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
|
||||||
|
|
||||||
|
// get command
|
||||||
VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
|
VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
|
||||||
|
|
||||||
|
// read register
|
||||||
ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
|
ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
|
||||||
|
|
||||||
|
// write register
|
||||||
VOID EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value);
|
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));
|
m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 8));
|
||||||
|
|
||||||
DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount);
|
DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount);
|
||||||
|
DPRINT1("Controller EHCI Version %x\n", m_Capabilities.HCIVersion);
|
||||||
if (m_Capabilities.HCSParams.PortRouteRules)
|
if (m_Capabilities.HCSParams.PortRouteRules)
|
||||||
{
|
{
|
||||||
for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++)
|
for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++)
|
||||||
|
@ -850,7 +860,7 @@ CUSBHardwareDevice::SetPeriodicListRegister(
|
||||||
ULONG
|
ULONG
|
||||||
CUSBHardwareDevice::GetAsyncListRegister()
|
CUSBHardwareDevice::GetAsyncListRegister()
|
||||||
{
|
{
|
||||||
return PhysicalAddress.LowPart;
|
return AsyncQueueHead->PhysicalAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG CUSBHardwareDevice::GetPeriodicListRegister()
|
ULONG CUSBHardwareDevice::GetPeriodicListRegister()
|
||||||
|
@ -946,11 +956,86 @@ EhciDefferedRoutine(
|
||||||
IN PVOID SystemArgument2)
|
IN PVOID SystemArgument2)
|
||||||
{
|
{
|
||||||
CUSBHardwareDevice *This;
|
CUSBHardwareDevice *This;
|
||||||
ULONG CStatus, PortStatus, PortCount, i;
|
ULONG CStatus, PortStatus, PortCount, i, ShouldRingDoorBell;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
EHCI_USBCMD_CONTENT UsbCmd;
|
||||||
|
|
||||||
This = (CUSBHardwareDevice*) SystemArgument1;
|
This = (CUSBHardwareDevice*) SystemArgument1;
|
||||||
CStatus = (ULONG) SystemArgument2;
|
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);
|
This->GetDeviceDetails(NULL, NULL, &PortCount, NULL);
|
||||||
if (CStatus & EHCI_STS_PCD)
|
if (CStatus & EHCI_STS_PCD)
|
||||||
{
|
{
|
||||||
|
|
|
@ -190,10 +190,6 @@ typedef struct _QUEUE_HEAD
|
||||||
//Software
|
//Software
|
||||||
ULONG PhysicalAddr;
|
ULONG PhysicalAddr;
|
||||||
LIST_ENTRY LinkedQueueHeads;
|
LIST_ENTRY LinkedQueueHeads;
|
||||||
PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor;
|
|
||||||
PIRP IrpToComplete;
|
|
||||||
PMDL Mdl;
|
|
||||||
PKEVENT Event;
|
|
||||||
PVOID Request;
|
PVOID Request;
|
||||||
} QUEUE_HEAD, *PQUEUE_HEAD;
|
} QUEUE_HEAD, *PQUEUE_HEAD;
|
||||||
|
|
||||||
|
|
|
@ -1986,16 +1986,6 @@ USBHI_RestoreUsbDevice(
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
USB_BUSIFFN
|
|
||||||
USBHI_GetPortHackFlags(
|
|
||||||
PVOID BusContext,
|
|
||||||
PULONG Flags)
|
|
||||||
{
|
|
||||||
UNIMPLEMENTED
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
USB_BUSIFFN
|
USB_BUSIFFN
|
||||||
USBHI_QueryDeviceInformation(
|
USBHI_QueryDeviceInformation(
|
||||||
|
@ -2565,7 +2555,6 @@ CHubController::HandleQueryInterface(
|
||||||
InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors;
|
InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors;
|
||||||
InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice;
|
InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice;
|
||||||
InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice;
|
InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice;
|
||||||
InterfaceHub->GetPortHackFlags = USBHI_GetPortHackFlags;
|
|
||||||
InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation;
|
InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -482,8 +482,27 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
||||||
// Description: frees the queue head with the associated transfer descriptors
|
// Description: frees the queue head with the associated transfer descriptors
|
||||||
|
|
||||||
virtual VOID FreeQueueHead(struct _QUEUE_HEAD * QueueHead) = 0;
|
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;
|
typedef IUSBRequest *PUSBREQUEST;
|
||||||
|
|
||||||
//=========================================================================================
|
//=========================================================================================
|
||||||
|
@ -539,6 +558,24 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown)
|
||||||
// Description: creates an usb request
|
// Description: creates an usb request
|
||||||
|
|
||||||
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest) = 0;
|
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;
|
typedef IUSBQueue *PUSBQUEUE;
|
||||||
|
|
|
@ -33,12 +33,14 @@ public:
|
||||||
return m_Ref;
|
return m_Ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock);
|
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN OPTIONAL PKSPIN_LOCK Lock);
|
||||||
ULONG GetPendingRequestCount();
|
virtual ULONG GetPendingRequestCount();
|
||||||
NTSTATUS AddUSBRequest(PURB Urb);
|
virtual NTSTATUS AddUSBRequest(PURB Urb);
|
||||||
NTSTATUS AddUSBRequest(IUSBRequest * Request);
|
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request);
|
||||||
NTSTATUS CancelRequests();
|
virtual NTSTATUS CancelRequests();
|
||||||
NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
||||||
|
virtual VOID InterruptCallback(IN NTSTATUS Status, OUT PULONG ShouldRingDoorBell);
|
||||||
|
virtual VOID CompleteAsyncRequests();
|
||||||
|
|
||||||
// constructor / destructor
|
// constructor / destructor
|
||||||
CUSBQueue(IUnknown *OuterUnknown){}
|
CUSBQueue(IUnknown *OuterUnknown){}
|
||||||
|
@ -50,6 +52,7 @@ protected:
|
||||||
PDMA_ADAPTER m_Adapter;
|
PDMA_ADAPTER m_Adapter;
|
||||||
PQUEUE_HEAD AsyncListQueueHead;
|
PQUEUE_HEAD AsyncListQueueHead;
|
||||||
PQUEUE_HEAD PendingListQueueHead;
|
PQUEUE_HEAD PendingListQueueHead;
|
||||||
|
LIST_ENTRY m_CompletedRequestAsyncList;
|
||||||
|
|
||||||
// queue head manipulation functions
|
// queue head manipulation functions
|
||||||
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
|
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
|
||||||
|
@ -57,8 +60,11 @@ protected:
|
||||||
VOID LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
|
VOID LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
|
||||||
PQUEUE_HEAD UnlinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, ULONG Count);
|
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
|
// 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
|
// called when the completion queue is cleaned up
|
||||||
VOID QueueHeadCleanup(PQUEUE_HEAD QueueHead);
|
VOID QueueHeadCleanup(PQUEUE_HEAD QueueHead);
|
||||||
|
@ -120,6 +126,17 @@ CUSBQueue::Initialize(
|
||||||
//
|
//
|
||||||
InitializeListHead(&PendingListQueueHead->LinkedQueueHeads);
|
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;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,13 +251,44 @@ CUSBQueue::UnlinkQueueHead(
|
||||||
PQUEUE_HEAD PreviousQH, NextQH;
|
PQUEUE_HEAD PreviousQH, NextQH;
|
||||||
PLIST_ENTRY Entry;
|
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;
|
Entry = QueueHead->LinkedQueueHeads.Blink;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get queue head structure
|
||||||
|
//
|
||||||
PreviousQH = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
PreviousQH = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get next link
|
||||||
|
//
|
||||||
Entry = QueueHead->LinkedQueueHeads.Flink;
|
Entry = QueueHead->LinkedQueueHeads.Flink;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get queue head structure
|
||||||
|
//
|
||||||
NextQH = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
NextQH = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
ASSERT(QueueHead->HorizontalLinkPointer == (NextQH->PhysicalAddr | QH_TYPE_QH));
|
ASSERT(QueueHead->HorizontalLinkPointer == (NextQH->PhysicalAddr | QH_TYPE_QH));
|
||||||
|
|
||||||
|
//
|
||||||
|
// remove queue head from linked list
|
||||||
|
//
|
||||||
PreviousQH->HorizontalLinkPointer = NextQH->PhysicalAddr | QH_TYPE_QH;
|
PreviousQH->HorizontalLinkPointer = NextQH->PhysicalAddr | QH_TYPE_QH;
|
||||||
|
|
||||||
|
//
|
||||||
|
// remove software link
|
||||||
|
//
|
||||||
RemoveEntryList(&QueueHead->LinkedQueueHeads);
|
RemoveEntryList(&QueueHead->LinkedQueueHeads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +374,7 @@ CUSBQueue::UnlinkQueueHeadChain(
|
||||||
return FirstQueueHead;
|
return FirstQueueHead;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
VOID
|
||||||
CUSBQueue::QueueHeadCompletion(
|
CUSBQueue::QueueHeadCompletion(
|
||||||
PQUEUE_HEAD CurrentQH,
|
PQUEUE_HEAD CurrentQH,
|
||||||
NTSTATUS Status)
|
NTSTATUS Status)
|
||||||
|
@ -415,14 +463,94 @@ CUSBQueue::QueueHeadCompletion(
|
||||||
else
|
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
|
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
|
NTSTATUS
|
||||||
CreateUSBQueue(
|
CreateUSBQueue(
|
||||||
PUSBQUEUE *OutUsbQueue)
|
PUSBQUEUE *OutUsbQueue)
|
||||||
|
|
|
@ -47,6 +47,9 @@ public:
|
||||||
virtual BOOLEAN IsRequestInitialized();
|
virtual BOOLEAN IsRequestInitialized();
|
||||||
virtual BOOLEAN ShouldReleaseRequestAfterCompletion();
|
virtual BOOLEAN ShouldReleaseRequestAfterCompletion();
|
||||||
virtual VOID FreeQueueHead(struct _QUEUE_HEAD * QueueHead);
|
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
|
// local functions
|
||||||
ULONG InternalGetTransferType();
|
ULONG InternalGetTransferType();
|
||||||
|
@ -640,12 +643,6 @@ CUSBRequest::BuildControlTransferQueueHead(
|
||||||
m_TransferDescriptors[1]->Token.Bits.InterruptOnComplete = TRUE;
|
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!!!
|
// 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
|
NTSTATUS
|
||||||
InternalCreateUSBRequest(
|
InternalCreateUSBRequest(
|
||||||
PUSBREQUEST *OutRequest)
|
PUSBREQUEST *OutRequest)
|
||||||
|
|
Loading…
Reference in a new issue