Author: janderwald
Date: Wed Apr 27 16:23:42 2011
New Revision: 51466
URL:
http://svn.reactos.org/svn/reactos?rev=51466&view=rev
Log:
[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
Modified:
branches/usb-bringup/drivers/usb/usbehci_new/hardware.cpp
branches/usb-bringup/drivers/usb/usbehci_new/hardware.h
branches/usb-bringup/drivers/usb/usbehci_new/hub_controller.cpp
branches/usb-bringup/drivers/usb/usbehci_new/interfaces.h
branches/usb-bringup/drivers/usb/usbehci_new/usb_queue.cpp
branches/usb-bringup/drivers/usb/usbehci_new/usb_request.cpp
Modified: branches/usb-bringup/drivers/usb/usbehci_new/hardware.cpp
URL:
http://svn.reactos.org/svn/reactos/branches/usb-bringup/drivers/usb/usbehci…
==============================================================================
--- branches/usb-bringup/drivers/usb/usbehci_new/hardware.cpp [iso-8859-1] (original)
+++ branches/usb-bringup/drivers/usb/usbehci_new/hardware.cpp [iso-8859-1] Wed Apr 27
16:23:42 2011
@@ -87,30 +87,39 @@
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 @@
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 @@
ULONG
CUSBHardwareDevice::GetAsyncListRegister()
{
- return PhysicalAddress.LowPart;
+ return AsyncQueueHead->PhysicalAddr;
}
ULONG CUSBHardwareDevice::GetPeriodicListRegister()
@@ -946,10 +956,85 @@
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)
Modified: branches/usb-bringup/drivers/usb/usbehci_new/hardware.h
URL:
http://svn.reactos.org/svn/reactos/branches/usb-bringup/drivers/usb/usbehci…
==============================================================================
--- branches/usb-bringup/drivers/usb/usbehci_new/hardware.h [iso-8859-1] (original)
+++ branches/usb-bringup/drivers/usb/usbehci_new/hardware.h [iso-8859-1] Wed Apr 27
16:23:42 2011
@@ -190,10 +190,6 @@
//Software
ULONG PhysicalAddr;
LIST_ENTRY LinkedQueueHeads;
- PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor;
- PIRP IrpToComplete;
- PMDL Mdl;
- PKEVENT Event;
PVOID Request;
} QUEUE_HEAD, *PQUEUE_HEAD;
Modified: branches/usb-bringup/drivers/usb/usbehci_new/hub_controller.cpp
URL:
http://svn.reactos.org/svn/reactos/branches/usb-bringup/drivers/usb/usbehci…
==============================================================================
--- branches/usb-bringup/drivers/usb/usbehci_new/hub_controller.cpp [iso-8859-1]
(original)
+++ branches/usb-bringup/drivers/usb/usbehci_new/hub_controller.cpp [iso-8859-1] Wed Apr
27 16:23:42 2011
@@ -1988,16 +1988,6 @@
NTSTATUS
USB_BUSIFFN
-USBHI_GetPortHackFlags(
- PVOID BusContext,
- PULONG Flags)
-{
- UNIMPLEMENTED
- return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-USB_BUSIFFN
USBHI_QueryDeviceInformation(
PVOID BusContext,
PUSB_DEVICE_HANDLE DeviceHandle,
@@ -2565,7 +2555,6 @@
InterfaceHub->GetUsbDescriptors = USBHI_GetUsbDescriptors;
InterfaceHub->RemoveUsbDevice = USBHI_RemoveUsbDevice;
InterfaceHub->RestoreUsbDevice = USBHI_RestoreUsbDevice;
- InterfaceHub->GetPortHackFlags = USBHI_GetPortHackFlags;
InterfaceHub->QueryDeviceInformation = USBHI_QueryDeviceInformation;
}
Modified: branches/usb-bringup/drivers/usb/usbehci_new/interfaces.h
URL:
http://svn.reactos.org/svn/reactos/branches/usb-bringup/drivers/usb/usbehci…
==============================================================================
--- branches/usb-bringup/drivers/usb/usbehci_new/interfaces.h [iso-8859-1] (original)
+++ branches/usb-bringup/drivers/usb/usbehci_new/interfaces.h [iso-8859-1] Wed Apr 27
16:23:42 2011
@@ -482,7 +482,26 @@
// 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 @@
// 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;
Modified: branches/usb-bringup/drivers/usb/usbehci_new/usb_queue.cpp
URL:
http://svn.reactos.org/svn/reactos/branches/usb-bringup/drivers/usb/usbehci…
==============================================================================
--- branches/usb-bringup/drivers/usb/usbehci_new/usb_queue.cpp [iso-8859-1] (original)
+++ branches/usb-bringup/drivers/usb/usbehci_new/usb_queue.cpp [iso-8859-1] Wed Apr 27
16:23:42 2011
@@ -33,12 +33,14 @@
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 @@
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 @@
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 @@
//
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 @@
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 @@
return FirstQueueHead;
}
-NTSTATUS
+VOID
CUSBQueue::QueueHeadCompletion(
PQUEUE_HEAD CurrentQH,
NTSTATUS Status)
@@ -415,14 +463,94 @@
else
{
//
- // FIXME: put queue head into completed queue head list
- //
- }
-
- //
- // done
- //
- return STATUS_SUCCESS;
+ // 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;
+ }
+ }
+
+ //
+ // 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
+ //
}
VOID
@@ -472,6 +600,47 @@
//
// request is now released
//
+}
+
+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
Modified: branches/usb-bringup/drivers/usb/usbehci_new/usb_request.cpp
URL:
http://svn.reactos.org/svn/reactos/branches/usb-bringup/drivers/usb/usbehci…
==============================================================================
--- branches/usb-bringup/drivers/usb/usbehci_new/usb_request.cpp [iso-8859-1] (original)
+++ branches/usb-bringup/drivers/usb/usbehci_new/usb_request.cpp [iso-8859-1] Wed Apr 27
16:23:42 2011
@@ -47,6 +47,9 @@
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();
@@ -641,12 +644,6 @@
}
//
- // 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!!!
//
m_TransferDescriptors[0]->BufferPointer[0] =
(ULONG)PtrToUlong(m_DescriptorSetupPacket.LowPart);
@@ -1149,6 +1146,64 @@
}
}
+//-----------------------------------------------------------------------------------------
+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)