[USBEHCI_NEW]

- Modify BuildBulkTransferQueueHead to support TransferBufferLengths larger than PAGE_SIZE * 5.
- Acquire a SpinLock before adding QueueHeads to AsyncList and PendingList.
- Dont request a new QueueHead for incomplete transfers in QueueHeadCompletion, as the memory for the just completed QueueHead has not been released yet. Doing so overwrites the m_TransferDescriptor[x] members with new address resulting in memory leaks. Instead request a new QueueHead after the QueueHead has been freed in QueueHeadCleanup.
- Fix a bug where a QueueHead was removed from the m_CompletedRequestAsyncList instead of the m_PendingRequestAsyncList.
- Temporary hackfix InternalCalculateTransferLength to return the TransferBufferLength. This hack will be removed as soon as possible.
- With these changes the hub and ehci driver allow viewing content of and transfers to/from usb disks.

svn path=/branches/usb-bringup/; revision=51684
This commit is contained in:
Michael Martin 2011-05-12 13:35:06 +00:00
parent 8d98341ac8
commit 76310d7679
2 changed files with 209 additions and 108 deletions

View file

@ -137,8 +137,7 @@ CUSBQueue::GetPendingRequestCount()
// Loop through the pending list and iterrate one for each QueueHead that // Loop through the pending list and iterrate one for each QueueHead that
// has a IRP to complete. // has a IRP to complete.
// //
return 0; return 0;
} }
@ -149,6 +148,7 @@ CUSBQueue::AddUSBRequest(
PQUEUE_HEAD QueueHead; PQUEUE_HEAD QueueHead;
NTSTATUS Status; NTSTATUS Status;
ULONG Type; ULONG Type;
KIRQL OldLevel;
// //
// sanity check // sanity check
@ -214,7 +214,9 @@ CUSBQueue::AddUSBRequest(
// //
// Add it to the pending list // Add it to the pending list
// //
KeAcquireSpinLock(&m_Lock, &OldLevel);
LinkQueueHead(AsyncListQueueHead, QueueHead); LinkQueueHead(AsyncListQueueHead, QueueHead);
KeReleaseSpinLock(&m_Lock, OldLevel);
} }
@ -251,12 +253,12 @@ CUSBQueue::CreateUSBRequest(
*OutRequest = NULL; *OutRequest = NULL;
Status = InternalCreateUSBRequest(&UsbRequest); Status = InternalCreateUSBRequest(&UsbRequest);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
*OutRequest = UsbRequest; *OutRequest = UsbRequest;
} }
return Status; return Status;
} }
@ -432,42 +434,21 @@ CUSBQueue::QueueHeadCompletion(
PQUEUE_HEAD CurrentQH, PQUEUE_HEAD CurrentQH,
NTSTATUS Status) NTSTATUS Status)
{ {
IUSBRequest *Request; KIRQL OldLevel;
PQUEUE_HEAD NewQueueHead;
// //
// now unlink the queue head // now unlink the queue head
// FIXME: implement chained queue heads // FIXME: implement chained queue heads
// //
KeAcquireSpinLock(&m_Lock, &OldLevel);
UnlinkQueueHead(CurrentQH); 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); InsertTailList(&m_CompletedRequestAsyncList, &CurrentQH->LinkedQueueHeads);
KeReleaseSpinLock(&m_Lock, OldLevel);
} }
VOID VOID
@ -508,7 +489,6 @@ CUSBQueue::ProcessAsyncList(
// //
Request = (IUSBRequest*)QueueHead->Request; Request = (IUSBRequest*)QueueHead->Request;
// //
// move to next entry // move to next entry
// //
@ -568,6 +548,7 @@ VOID
CUSBQueue::QueueHeadCleanup( CUSBQueue::QueueHeadCleanup(
PQUEUE_HEAD CurrentQH) PQUEUE_HEAD CurrentQH)
{ {
PQUEUE_HEAD NewQueueHead;
IUSBRequest * Request; IUSBRequest * Request;
BOOLEAN ShouldReleaseWhenDone; BOOLEAN ShouldReleaseWhenDone;
USBD_STATUS UrbStatus; USBD_STATUS UrbStatus;
@ -625,9 +606,47 @@ CUSBQueue::QueueHeadCleanup(
} }
// //
// notify request that a queue head has been completed // Check if the transfer was completed and if UrbStatus is ok
// //
Request->CompletionCallback(STATUS_SUCCESS /*FIXME*/, UrbStatus, CurrentQH); if ((Request->IsRequestComplete() == FALSE) && (UrbStatus == USBD_STATUS_SUCCESS))
{
//
// let IUSBRequest free the queue head
//
Request->FreeQueueHead(CurrentQH);
//
// request is incomplete, get new queue head
//
if (Request->GetQueueHead(&NewQueueHead) == STATUS_SUCCESS)
{
//
// add to pending list
//
InsertTailList(&m_PendingRequestAsyncList, &NewQueueHead->LinkedQueueHeads);
//
// Done for now
//
return;
}
DPRINT1("Unable to create a new QueueHead\n");
PC_ASSERT(FALSE);
//
// Else there was a problem
// FIXME: Find better return
UrbStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
}
if (UrbStatus != USBD_STATUS_SUCCESS) PC_ASSERT(FALSE);
//
// notify request that a transfer has completed
//
Request->CompletionCallback(UrbStatus != USBD_STATUS_SUCCESS ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS,
UrbStatus,
CurrentQH);
// //
// let IUSBRequest free the queue head // let IUSBRequest free the queue head
@ -666,6 +685,7 @@ CUSBQueue::CompleteAsyncRequests()
KIRQL OldLevel; KIRQL OldLevel;
PLIST_ENTRY Entry; PLIST_ENTRY Entry;
PQUEUE_HEAD CurrentQH; PQUEUE_HEAD CurrentQH;
IUSBRequest *Request;
DPRINT("CUSBQueue::CompleteAsyncRequests\n"); DPRINT("CUSBQueue::CompleteAsyncRequests\n");
@ -691,6 +711,11 @@ CUSBQueue::CompleteAsyncRequests()
// //
CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads); CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
//
// Get the Request for this QueueHead
//
Request = (IUSBRequest*) CurrentQH->Request;
// //
// complete request now // complete request now
// //
@ -705,7 +730,7 @@ CUSBQueue::CompleteAsyncRequests()
// //
// remove first entry // remove first entry
// //
Entry = RemoveHeadList(&m_CompletedRequestAsyncList); Entry = RemoveHeadList(&m_PendingRequestAsyncList);
// //
// get queue head structure // get queue head structure
@ -713,7 +738,7 @@ CUSBQueue::CompleteAsyncRequests()
CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads); CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
// //
// Add it to the pending list // Add it to the AsyncList list
// //
LinkQueueHead(AsyncListQueueHead, CurrentQH); LinkQueueHead(AsyncListQueueHead, CurrentQH);
} }

View file

@ -85,6 +85,16 @@ protected:
// //
ULONG m_TransferBufferLength; ULONG m_TransferBufferLength;
//
// current transfer length
//
ULONG m_TransferBufferLengthCompleted;
//
// Total Transfer Length
//
ULONG m_TotalBytesTransferred;
// //
// transfer buffer MDL // transfer buffer MDL
// //
@ -169,6 +179,12 @@ CUSBRequest::InitializeWithSetupPacket(
m_TransferBufferMDL = TransferBuffer; m_TransferBufferMDL = TransferBuffer;
m_DeviceAddress = DeviceAddress; m_DeviceAddress = DeviceAddress;
m_EndpointDescriptor = EndpointDescriptor; m_EndpointDescriptor = EndpointDescriptor;
m_TotalBytesTransferred = 0;
//
// Set Length Completed to 0
//
m_TransferBufferLengthCompleted = 0;
// //
// allocate completion event // allocate completion event
@ -208,6 +224,7 @@ CUSBRequest::InitializeWithIrp(
PC_ASSERT(Irp); PC_ASSERT(Irp);
m_DmaManager = DmaManager; m_DmaManager = DmaManager;
m_TotalBytesTransferred = 0;
// //
// get current irp stack location // get current irp stack location
@ -244,7 +261,7 @@ CUSBRequest::InitializeWithIrp(
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{ {
// //
// bulk / interrupt transfer // bulk interrupt transfer
// //
if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength) if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
{ {
@ -281,6 +298,10 @@ CUSBRequest::InitializeWithIrp(
// FIXME: Does hub driver already do this when passing MDL? // FIXME: Does hub driver already do this when passing MDL?
// //
MmBuildMdlForNonPagedPool(m_TransferBufferMDL); MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
//
// Keep that ehci created the MDL and needs to free it.
//
} }
else else
{ {
@ -292,6 +313,11 @@ CUSBRequest::InitializeWithIrp(
// //
m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
//
// Set Length Completed to 0
//
m_TransferBufferLengthCompleted = 0;
// //
// get endpoint descriptor // get endpoint descriptor
// //
@ -357,7 +383,6 @@ CUSBRequest::CompletionCallback(
// //
// Check if the MDL was created // Check if the MDL was created
// //
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL) if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{ {
// //
@ -439,6 +464,7 @@ CUSBRequest::CancelCallback(
// //
// store urb status // store urb status
// //
DPRINT1("Request Cancelled\n");
Urb->UrbHeader.Status = USBD_STATUS_CANCELED; Urb->UrbHeader.Status = USBD_STATUS_CANCELED;
Urb->UrbHeader.Length = 0; Urb->UrbHeader.Length = 0;
@ -521,6 +547,18 @@ CUSBRequest::IsRequestComplete()
// //
// FIXME: check if request was split // FIXME: check if request was split
// //
//
// Check if the transfer was completed, only valid for Bulk Transfers
//
if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
&& (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
{
//
// Transfer not completed
//
return FALSE;
}
return TRUE; return TRUE;
} }
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
@ -642,7 +680,7 @@ CUSBRequest::BuildControlTransferQueueHead(
// now initialize the queue head // now initialize the queue head
// //
QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress(); QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
if (m_EndpointDescriptor) if (m_EndpointDescriptor)
{ {
// //
@ -751,7 +789,7 @@ CUSBRequest::BuildBulkTransferQueueHead(
ULONG TransferDescriptorCount, Index; ULONG TransferDescriptorCount, Index;
ULONG BytesAvailable, BufferIndex; ULONG BytesAvailable, BufferIndex;
PVOID Base; PVOID Base;
ULONG PageOffset; ULONG PageOffset, CurrentTransferBufferLength;
// //
// Allocate the queue head // Allocate the queue head
@ -770,24 +808,59 @@ CUSBRequest::BuildBulkTransferQueueHead(
// sanity checks // sanity checks
// //
PC_ASSERT(QueueHead); PC_ASSERT(QueueHead);
//
// FIXME: support more than one descriptor
//
PC_ASSERT(m_TransferBufferLength < PAGE_SIZE * 5);
PC_ASSERT(m_TransferBufferLength); PC_ASSERT(m_TransferBufferLength);
TransferDescriptorCount = 1; //
// Max default of 3 descriptors
//
TransferDescriptorCount = 3;
// //
// get virtual base of mdl // get virtual base of mdl
// //
Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority); Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
BytesAvailable = m_TransferBufferLength;
//
// Increase the size of last transfer, 0 in case this is the first
//
Base = (PVOID)((ULONG_PTR)Base + m_TransferBufferLengthCompleted);
PC_ASSERT(m_EndpointDescriptor); PC_ASSERT(m_EndpointDescriptor);
PC_ASSERT(Base); PC_ASSERT(Base);
//
// Get the offset from page size
//
PageOffset = BYTE_OFFSET(Base);
//
// PageOffset should only be > 0 if this is the first transfer for this requests
//
if ((PageOffset != 0) && (m_TransferBufferLengthCompleted != 0))
{
ASSERT(FALSE);
}
//
// Calculate the size of this transfer
//
if ((PageOffset != 0) && ((m_TransferBufferLength - m_TransferBufferLengthCompleted) >= (PAGE_SIZE * 4) + PageOffset))
{
CurrentTransferBufferLength = (PAGE_SIZE * 4) + PageOffset;
}
else if ((m_TransferBufferLength - m_TransferBufferLengthCompleted) >= PAGE_SIZE * 5)
{
CurrentTransferBufferLength = PAGE_SIZE * 5;
}
else
CurrentTransferBufferLength = (m_TransferBufferLength - m_TransferBufferLengthCompleted);
//
// Add current transfer length to transfer length completed
//
m_TransferBufferLengthCompleted += CurrentTransferBufferLength;
BytesAvailable = CurrentTransferBufferLength;
DPRINT("CurrentTransferBufferLength %x, m_TransferBufferLengthCompleted %x\n", CurrentTransferBufferLength, m_TransferBufferLengthCompleted);
DPRINT("EndPointAddress %x\n", m_EndpointDescriptor->bEndpointAddress); DPRINT("EndPointAddress %x\n", m_EndpointDescriptor->bEndpointAddress);
DPRINT("EndPointDirection %x\n", USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress)); DPRINT("EndPointDirection %x\n", USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress));
@ -833,9 +906,9 @@ CUSBRequest::BuildBulkTransferQueueHead(
for(BufferIndex = 0; BufferIndex < 5; BufferIndex++) for(BufferIndex = 0; BufferIndex < 5; BufferIndex++)
{ {
// //
// setup buffer // If this is the first buffer of the first descriptor and there is a PageOffset
// //
if (BufferIndex == 0) if ((BufferIndex == 0) && (PageOffset != 0) && (Index == 0))
{ {
// //
// use physical address // use physical address
@ -843,45 +916,25 @@ CUSBRequest::BuildBulkTransferQueueHead(
m_TransferDescriptors[Index]->BufferPointer[0] = MmGetPhysicalAddress(Base).LowPart; m_TransferDescriptors[Index]->BufferPointer[0] = MmGetPhysicalAddress(Base).LowPart;
// //
// get offset within page // move to next page
// //
PageOffset = BYTE_OFFSET(m_TransferDescriptors[Index]->BufferPointer[0]); Base = (PVOID)ROUND_TO_PAGES(Base);
// //
// check if request fills another page // increment transfer bytes
// //
if (PageOffset + BytesAvailable > PAGE_SIZE) if (CurrentTransferBufferLength > PAGE_SIZE - PageOffset)
{
//
// move to next page
//
Base = (PVOID)ROUND_TO_PAGES(Base);
//
// increment transfer bytes
//
m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = PAGE_SIZE - PageOffset; m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = PAGE_SIZE - PageOffset;
else
m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = CurrentTransferBufferLength;
// //
// decrement available byte count // decrement available byte count
// //
BytesAvailable -= m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer; BytesAvailable -= m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer;
DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex], DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex],
BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable); BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable);
}
else
{
//
// request ends on the first buffer page
//
m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = BytesAvailable;
BytesAvailable = 0;
DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex],
BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable);
break;
}
} }
else else
{ {
@ -935,7 +988,7 @@ CUSBRequest::BuildBulkTransferQueueHead(
BytesAvailable -= BytesAvailable; BytesAvailable -= BytesAvailable;
// //
// done // done as this is the last partial or full page
// //
DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex], DPRINT("TransferDescriptor %p BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], m_TransferDescriptors[Index]->BufferPointer[BufferIndex],
BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable); BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable);
@ -943,6 +996,12 @@ CUSBRequest::BuildBulkTransferQueueHead(
break; break;
} }
} }
//
// Check if all bytes have been consumed
//
if (BytesAvailable == 0)
break;
} }
// //
@ -971,6 +1030,12 @@ CUSBRequest::BuildBulkTransferQueueHead(
// //
// FIXME need dead queue transfer descriptor? // FIXME need dead queue transfer descriptor?
// //
//
// Check if all bytes have been consumed
//
if (BytesAvailable == 0)
break;
} }
// //
@ -982,7 +1047,7 @@ CUSBRequest::BuildBulkTransferQueueHead(
// Initialize the QueueHead // Initialize the QueueHead
// //
QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress(); QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
if (m_EndpointDescriptor) if (m_EndpointDescriptor)
{ {
// //
@ -1440,10 +1505,12 @@ VOID
CUSBRequest::FreeQueueHead( CUSBRequest::FreeQueueHead(
IN struct _QUEUE_HEAD * QueueHead) IN struct _QUEUE_HEAD * QueueHead)
{ {
LONG DescriptorCount;
// //
// FIXME: support chained queue heads // FIXME: support chained queue heads
// //
PC_ASSERT(QueueHead == m_QueueHead); //PC_ASSERT(QueueHead == m_QueueHead);
// //
// release queue head // release queue head
@ -1458,32 +1525,40 @@ CUSBRequest::FreeQueueHead(
// //
// release transfer descriptors // release transfer descriptors
// //
for (DescriptorCount = 0; DescriptorCount < 3; DescriptorCount++)
if (m_TransferDescriptors[0])
{ {
// if (m_TransferDescriptors[DescriptorCount])
// release transfer descriptors {
// //
m_DmaManager->Release(m_TransferDescriptors[0], sizeof(QUEUE_TRANSFER_DESCRIPTOR)); // Calculate Total Bytes Transferred
m_TransferDescriptors[0] = 0; // FIXME: Is this the correct method of determine bytes transferred?
} //
if (USB_ENDPOINT_TYPE_BULK == GetTransferType())
{
//
// sanity check
//
ASSERT(m_EndpointDescriptor);
if (m_TransferDescriptors[1]) if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress))
{ {
// DPRINT1("m_TotalBytesTransferred %x, %x - %x\n",
// release transfer descriptors m_TotalBytesTransferred,
// m_TransferDescriptors[DescriptorCount]->TotalBytesToTransfer,
m_DmaManager->Release(m_TransferDescriptors[1], sizeof(QUEUE_TRANSFER_DESCRIPTOR)); m_TransferDescriptors[DescriptorCount]->Token.Bits.TotalBytesToTransfer);
m_TransferDescriptors[1] = 0;
}
if (m_TransferDescriptors[2]) m_TotalBytesTransferred +=
{ m_TransferDescriptors[DescriptorCount]->TotalBytesToTransfer -
// m_TransferDescriptors[DescriptorCount]->Token.Bits.TotalBytesToTransfer;
// release transfer descriptors }
// }
m_DmaManager->Release(m_TransferDescriptors[2], sizeof(QUEUE_TRANSFER_DESCRIPTOR));
m_TransferDescriptors[2] = 0; //
// release transfer descriptors
//
m_DmaManager->Release(m_TransferDescriptors[DescriptorCount], sizeof(QUEUE_TRANSFER_DESCRIPTOR));
m_TransferDescriptors[DescriptorCount] = 0;
}
} }
if (m_DescriptorPacket) if (m_DescriptorPacket)
@ -1573,8 +1648,9 @@ CUSBRequest::InternalCalculateTransferLength()
{ {
// //
// bulk in request // bulk in request
// HACK: Properly determine transfer length
// //
return m_TransferDescriptors[0]->TotalBytesToTransfer - m_TransferDescriptors[0]->Token.Bits.TotalBytesToTransfer; return m_TransferBufferLength;//m_TotalBytesTransferred;
} }
// //