Author: janderwald
Date: Sat Apr 30 17:44:43 2011
New Revision: 51506
URL:
http://svn.reactos.org/svn/reactos?rev=51506&view=rev
Log:
[USBEHCI_NEW]
- Store number of bytes transferred in the transfer descriptors
- Perform queue head completion when the door bell ring has been acknowledged. Fixes race
condition between multiple irps in the async list
- Fix calculation of transfer length when the request is an bulk in operation
- Use EndPointDescriptor member to access transfer type / pid direction
- Use MmGetSystemAddressForMdlSafe to retrieve system address for urb buffer
- Fix check if first transfer buffer finishes on first size if the size is of page_size
- With these changes and little luck and good weather, usb mass storage devices have been
seen to work in Windows XP SP3
- Code inspired of mjmartin usbehci driver and Haiku's usb stack
Modified:
branches/usb-bringup/drivers/usb/usbehci_new/hardware.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.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] Sat Apr 30
17:44:43 2011
@@ -127,6 +127,7 @@
//Software
ULONG PhysicalAddr;
LIST_ENTRY LinkedDescriptors;
+ ULONG TotalBytesToTransfer;
} QUEUE_TRANSFER_DESCRIPTOR, *PQUEUE_TRANSFER_DESCRIPTOR;
//
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] Sat Apr 30
17:44:43 2011
@@ -52,6 +52,8 @@
PDMA_ADAPTER m_Adapter;
PQUEUE_HEAD AsyncListQueueHead;
LIST_ENTRY m_CompletedRequestAsyncList;
+ LIST_ENTRY m_PendingRequestAsyncList;
+
// queue head manipulation functions
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
@@ -119,6 +121,11 @@
// Initialize completed async list head
//
InitializeListHead(&m_CompletedRequestAsyncList);
+
+ //
+ // Initialize pending async list head
+ //
+ InitializeListHead(&m_PendingRequestAsyncList);
return Status;
}
@@ -425,16 +432,154 @@
NTSTATUS Status)
{
IUSBRequest *Request;
+ PQUEUE_HEAD NewQueueHead;
+
+ //
+ // now unlink the queue head
+ // FIXME: implement chained queue heads
+ //
+ UnlinkQueueHead(CurrentQH);
+
+ //
+ // get contained usb request
+ //
+ Request = (IUSBRequest*)CurrentQH->Request;
+
+ //
+ // 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
+ //
+ InsertTailList(&m_PendingRequestAsyncList,
&NewQueueHead->LinkedQueueHeads);
+ }
+
+ //
+ // 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;
+ BOOLEAN IsQueueHeadComplete;
+
+ //
+ // lock completed async list
+ //
+ KeAcquireSpinLock(&m_Lock, &OldLevel);
+
+ //
+ // walk async list
+ //
+ Entry = AsyncListQueueHead->LinkedQueueHeads.Flink;
+
+ while(Entry != &AsyncListQueueHead->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
+ //
+ IsQueueHeadComplete = Request->IsQueueHeadComplete(QueueHead);
+
+ DPRINT1("Request %p QueueHead %p Complete %d\n", Request, QueueHead,
IsQueueHeadComplete);
+
+ //
+ // check if queue head is complete
+ //
+ if (IsQueueHeadComplete)
+ {
+ //
+ // 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)
+{
+
+ DPRINT1("CUSBQueue::InterruptCallback\n");
+
+ //
+ // iterate asynchronous list
+ //
+ *ShouldRingDoorBell = FALSE;
+ ProcessAsyncList(Status, ShouldRingDoorBell);
+
+ //
+ // TODO: implement periodic schedule processing
+ //
+}
+
+VOID
+CUSBQueue::QueueHeadCleanup(
+ PQUEUE_HEAD CurrentQH)
+{
+ IUSBRequest * Request;
+ BOOLEAN ShouldReleaseWhenDone;
USBD_STATUS UrbStatus;
- PQUEUE_HEAD NewQueueHead;
-
- //
- // this function is called when a queue head has been completed
+
+ //
+ // sanity checks
//
PC_ASSERT(CurrentQH->Token.Bits.Active == 0);
-
- //
- // get contained usb request
+ PC_ASSERT(CurrentQH->Request);
+
+
+ //
+ // get request
//
Request = (IUSBRequest*)CurrentQH->Request;
@@ -481,145 +626,7 @@
//
// 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(AsyncListQueueHead, NewQueueHead);
- }
- else
- {
- //
- // 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 = AsyncListQueueHead->LinkedQueueHeads.Flink;
-
- while(Entry != &AsyncListQueueHead->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;
-
- DPRINT1("Request %p QueueHead %p Complete %d\n", Request, QueueHead,
Request->IsQueueHeadComplete(QueueHead));
-
- //
- // 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)
-{
-
- DPRINT1("CUSBQueue::InterruptCallback\n");
-
- //
- // iterate asynchronous list
- //
- *ShouldRingDoorBell = FALSE;
- ProcessAsyncList(Status, ShouldRingDoorBell);
-
- //
- // TODO: implement periodic schedule processing
- //
-}
-
-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;
+ Request->CompletionCallback(STATUS_SUCCESS /*FIXME*/, UrbStatus, CurrentQH);
//
// let IUSBRequest free the queue head
@@ -690,6 +697,27 @@
}
//
+ // is there a pending async entry
+ //
+ if (!IsListEmpty(&m_PendingRequestAsyncList))
+ {
+ //
+ // remove first entry
+ //
+ Entry = RemoveHeadList(&m_CompletedRequestAsyncList);
+
+ //
+ // get queue head structure
+ //
+ CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
+
+ //
+ // Add it to the pending list
+ //
+ LinkQueueHead(AsyncListQueueHead, CurrentQH);
+ }
+
+ //
// release lock
//
KeReleaseSpinLock(&m_Lock, OldLevel);
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] Sat Apr 30
17:44:43 2011
@@ -61,6 +61,7 @@
UCHAR GetDeviceAddress();
NTSTATUS BuildSetupPacket();
NTSTATUS BuildSetupPacketFromURB();
+ ULONG InternalCalculateTransferLength();
// constructor / destructor
CUSBRequest(IUnknown *OuterUnknown){}
@@ -253,9 +254,14 @@
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
+ // sanity check
+ //
+ PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
+
+ //
// Create one using TransferBuffer
//
- DPRINT1("Creating Mdl from Urb Buffer\n");
+ DPRINT1("Creating Mdl from Urb Buffer %p Length %lu\n",
Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
m_TransferBufferMDL =
IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
FALSE,
@@ -370,8 +376,15 @@
//
Urb->UrbHeader.Length = 0;
}
-
- DPRINT1("Request %p Completing Irp %p NtStatusCode %x UrbStatusCode
%x\n", this, m_Irp, NtStatusCode, UrbStatusCode);
+ else
+ {
+ //
+ // calculate transfer length
+ //
+ Urb->UrbBulkOrInterruptTransfer.TransferBufferLength =
InternalCalculateTransferLength();
+ }
+
+ DPRINT1("Request %p Completing Irp %p NtStatusCode %x UrbStatusCode %x
Transferred Length %lu\n", this, m_Irp, NtStatusCode, UrbStatusCode,
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
//
// FIXME: check if the transfer was split
@@ -525,9 +538,6 @@
ULONG
CUSBRequest::InternalGetTransferType()
{
- PIO_STACK_LOCATION IoStack;
- PURB Urb;
- PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
ULONG TransferType;
//
@@ -535,38 +545,12 @@
//
if (m_Irp)
{
- //
- // get stack location
- //
- IoStack = IoGetCurrentIrpStackLocation(m_Irp);
-
- //
- // get urb
- //
- Urb = (PURB)IoStack->Parameters.Others.Argument1;
-
- //
- // check if there is a handle
- //
- if (Urb->UrbBulkOrInterruptTransfer.PipeHandle)
- {
- //
- // cast to end point
- //
- EndpointDescriptor =
(PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
-
- //
- // end point is defined in the low byte of bmAttributes
- //
- TransferType = (EndpointDescriptor->bmAttributes &
USB_ENDPOINT_TYPE_MASK);
- }
- else
- {
- //
- // no pipe handle, assume it is a control transfer
- //
- TransferType = USB_ENDPOINT_TYPE_CONTROL;
- }
+ ASSERT(m_EndpointDescriptor);
+
+ //
+ // end point is defined in the low byte of bmAttributes
+ //
+ TransferType = (m_EndpointDescriptor->bmAttributes &
USB_ENDPOINT_TYPE_MASK);
}
else
{
@@ -585,30 +569,13 @@
UCHAR
CUSBRequest::InternalGetPidDirection()
{
- PIO_STACK_LOCATION IoStack;
- PURB Urb;
- PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
-
ASSERT(m_Irp);
- //
- // get stack location
- //
- IoStack = IoGetCurrentIrpStackLocation(m_Irp);
-
- //
- // get urb
- //
- Urb = (PURB)IoStack->Parameters.Others.Argument1;
-
- //
- // cast to end point
- //
- EndpointDescriptor =
(PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+ ASSERT(m_EndpointDescriptor);
//
// end point is defined in the low byte of bEndpointAddress
//
- return (EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK)
>> 7;
+ return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK)
>> 7;
}
//----------------------------------------------------------------------------------------
@@ -816,16 +783,19 @@
//
// get virtual base of mdl
//
- Base = MmGetMdlVirtualAddress(m_TransferBufferMDL);
+ Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
BytesAvailable = m_TransferBufferLength;
PC_ASSERT(m_EndpointDescriptor);
+ PC_ASSERT(Base);
+
DPRINT1("EndPointAddress %x\n",
m_EndpointDescriptor->bEndpointAddress);
DPRINT1("EndPointDirection %x\n",
USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress));
- DPRINT1("Request %p Base Address %p TransferBytesLength %lu\n", this, Base,
BytesAvailable);
+ DPRINT1("Request %p Base Address %p TransferBytesLength %lu MDL %p\n",
this, Base, BytesAvailable, m_TransferBufferMDL);
DPRINT1("InternalGetPidDirection() %d EndPointAddress %x\n",
InternalGetPidDirection(), m_EndpointDescriptor->bEndpointAddress & 0x0F);
+ DPRINT1("Irp %p QueueHead %p\n", m_Irp, QueueHead);
//PC_ASSERT(InternalGetPidDirection() ==
USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress));
@@ -881,7 +851,7 @@
//
// check if request fills another page
//
- if (PageOffset + BytesAvailable >= PAGE_SIZE)
+ if (PageOffset + BytesAvailable > PAGE_SIZE)
{
//
// move to next page
@@ -977,6 +947,11 @@
}
//
+ // store transfer bytes of descriptor
+ //
+ m_TransferDescriptors[Index]->TotalBytesToTransfer =
m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer;
+
+ //
// Go ahead and link descriptors
//
if (Index > 0)
@@ -1579,6 +1554,36 @@
*OutMDL = m_TransferBufferMDL;
*TransferLength = m_TransferBufferLength;
}
+//-----------------------------------------------------------------------------------------
+ULONG
+CUSBRequest::InternalCalculateTransferLength()
+{
+ if (!m_Irp)
+ {
+ //
+ // FIXME: get length for control request
+ //
+ return m_TransferBufferLength;
+ }
+
+ //
+ // sanity check
+ //
+ ASSERT(m_EndpointDescriptor);
+
+ if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress))
+ {
+ //
+ // bulk in request
+ //
+ return m_TransferDescriptors[0]->TotalBytesToTransfer -
m_TransferDescriptors[0]->Token.Bits.TotalBytesToTransfer;
+ }
+
+ //
+ // bulk out transfer
+ //
+ return m_TransferBufferLength;
+}
//-----------------------------------------------------------------------------------------
NTSTATUS