[USBEHCI]

- Abort pipe when performing sync reset request
- add assert to check for bogus interface descriptors
- use endpoint max packet size when available
- flip data toggle after each transfer
- remove dead code
- use maximum of 4 pages or rest current buffer size when performing a bulk requests
- use nak reload count 3
- perform 1 transaction per frame


svn path=/trunk/; revision=55634
This commit is contained in:
Johannes Anderwald 2012-02-16 14:49:59 +00:00
parent bd3f5b9708
commit df5cd2fcac
4 changed files with 153 additions and 35 deletions

View file

@ -1740,7 +1740,7 @@ CHubController::HandleSyncResetAndClearStall(
//
if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)))
{
DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
DPRINT1("HandleSyncResetAndClearStall invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle);
//
// invalid device handle
@ -1748,6 +1748,19 @@ CHubController::HandleSyncResetAndClearStall(
return STATUS_DEVICE_NOT_CONNECTED;
}
//
// abort pipe
//
Status = HandleAbortPipe(Irp, Urb);
if (!NT_SUCCESS(Status))
{
//
// failed
//
DPRINT1("[USBEHCI] failed to reset pipe %x\n", Status)
}
//
// get endpoint descriptor
//

View file

@ -819,6 +819,7 @@ CUSBDevice::CreateConfigurationDescriptor(
//
// move to next descriptor
//
ASSERT(InterfaceDescriptor->bLength);
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
}

View file

@ -427,7 +427,7 @@ CUSBQueue::LinkQueueHead(
//
// Link the LIST_ENTRYs
//
ASSERT(IsListEmpty(&HeadQueueHead->LinkedQueueHeads));
//ASSERT(IsListEmpty(&HeadQueueHead->LinkedQueueHeads));
InsertTailList(&HeadQueueHead->LinkedQueueHeads, &NewQueueHead->LinkedQueueHeads);
//
@ -435,7 +435,7 @@ CUSBQueue::LinkQueueHead(
//
Entry = NewQueueHead->LinkedQueueHeads.Blink;
LastQueueHead = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
ASSERT(LastQueueHead == HeadQueueHead);
//ASSERT(LastQueueHead == HeadQueueHead);
LastQueueHead->HorizontalLinkPointer = (NewQueueHead->PhysicalAddr | QH_TYPE_QH);
//
@ -443,7 +443,7 @@ CUSBQueue::LinkQueueHead(
//
Entry = NewQueueHead->LinkedQueueHeads.Flink;
NextQueueHead = CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
ASSERT(NextQueueHead == HeadQueueHead);
//ASSERT(NextQueueHead == HeadQueueHead);
NewQueueHead->HorizontalLinkPointer = (NextQueueHead->PhysicalAddr | QH_TYPE_QH);
//
@ -858,7 +858,6 @@ CUSBQueue::CompleteAsyncRequests()
KIRQL OldLevel;
PLIST_ENTRY Entry;
PQUEUE_HEAD CurrentQH;
IUSBRequest *Request;
DPRINT("CUSBQueue::CompleteAsyncRequests\n");
@ -884,11 +883,6 @@ CUSBQueue::CompleteAsyncRequests()
//
CurrentQH = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
//
// Get the Request for this QueueHead
//
Request = (IUSBRequest*) CurrentQH->Request;
//
// release lock
//
@ -937,8 +931,82 @@ CUSBQueue::AbortDevicePipe(
IN UCHAR DeviceAddress,
IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
KIRQL OldLevel;
PLIST_ENTRY Entry;
PQUEUE_HEAD QueueHead;
LIST_ENTRY ListHead;
//
// lock completed async list
//
KeAcquireSpinLock(m_Lock, &OldLevel);
DPRINT1("AbortDevicePipe DeviceAddress %x EndpointDescriptor %p Addr %x\n", DeviceAddress, EndpointDescriptor, EndpointDescriptor->bEndpointAddress);
//
// init list head
//
InitializeListHead(&ListHead);
//
// walk async list
//
ASSERT(AsyncListQueueHead);
Entry = AsyncListQueueHead->LinkedQueueHeads.Flink;
while(Entry != &AsyncListQueueHead->LinkedQueueHeads)
{
//
// get queue head structure
//
QueueHead = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
ASSERT(QueueHead);
//
// move to next entry
//
Entry = Entry->Flink;
if (QueueHead->EndPointCharacteristics.DeviceAddress == DeviceAddress &&
QueueHead->EndPointCharacteristics.EndPointNumber == (EndpointDescriptor->bEndpointAddress & 0xF) && QueueHead->Token.Bits.Halted)
{
//
// unlink queue head
//
UnlinkQueueHead(QueueHead);
//
// add to temp list
//
InsertTailList(&ListHead, &QueueHead->LinkedQueueHeads);
}
}
//
// release lock
//
KeReleaseSpinLock(m_Lock, OldLevel);
while(!IsListEmpty(&ListHead))
{
//
// remove entry
//
Entry = RemoveHeadList(&ListHead);
//
// get queue head structure
//
QueueHead = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads);
ASSERT(QueueHead);
//
// cleanup queue head
//
QueueHeadCleanup(QueueHead);
}
return STATUS_SUCCESS;
}

View file

@ -62,11 +62,10 @@ public:
NTSTATUS BuildSetupPacket();
NTSTATUS BuildSetupPacketFromURB();
ULONG InternalCalculateTransferLength();
NTSTATUS BuildTransferDescriptorChain(IN PQUEUE_HEAD QueueHead, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR InitialDataToggle, OUT PQUEUE_TRANSFER_DESCRIPTOR * OutFirstDescriptor, OUT PQUEUE_TRANSFER_DESCRIPTOR * OutLastDescriptor, OUT PUCHAR OutDataToggle, OUT PULONG OutTransferBufferOffset);
NTSTATUS BuildTransferDescriptorChain(IN PQUEUE_HEAD QueueHead, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR InitialDataToggle, IN PQUEUE_TRANSFER_DESCRIPTOR AlternativeDescriptor, OUT PQUEUE_TRANSFER_DESCRIPTOR * OutFirstDescriptor, OUT PQUEUE_TRANSFER_DESCRIPTOR * OutLastDescriptor, OUT PUCHAR OutDataToggle, OUT PULONG OutTransferBufferOffset);
VOID InitDescriptor(IN PQUEUE_TRANSFER_DESCRIPTOR CurrentDescriptor, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR DataToggle, OUT PULONG OutDescriptorLength);
VOID DumpQueueHead(IN PQUEUE_HEAD QueueHead);
// constructor / destructor
CUSBRequest(IUnknown *OuterUnknown){}
virtual ~CUSBRequest(){}
@ -734,6 +733,7 @@ CUSBRequest::BuildTransferDescriptorChain(
IN ULONG TransferBufferLength,
IN UCHAR PidCode,
IN UCHAR InitialDataToggle,
IN PQUEUE_TRANSFER_DESCRIPTOR AlternativeDescriptor,
OUT PQUEUE_TRANSFER_DESCRIPTOR * OutFirstDescriptor,
OUT PQUEUE_TRANSFER_DESCRIPTOR * OutLastDescriptor,
OUT PUCHAR OutDataToggle,
@ -742,6 +742,19 @@ CUSBRequest::BuildTransferDescriptorChain(
PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL;
NTSTATUS Status;
ULONG DescriptorLength, TransferBufferOffset = 0;
ULONG MaxPacketSize = 0, TransferSize;
//
// is there an endpoint descriptor
//
if (m_EndpointDescriptor)
{
//
// use endpoint packet size
//
MaxPacketSize = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
}
do
{
@ -754,8 +767,22 @@ CUSBRequest::BuildTransferDescriptorChain(
//
// failed to allocate transfer descriptor
//
ASSERT(FALSE);
return Status;
return STATUS_INSUFFICIENT_RESOURCES;
}
if (MaxPacketSize)
{
//
// transfer size is minimum available buffer or endpoint size
//
TransferSize = min(TransferBufferLength - TransferBufferOffset, MaxPacketSize);
}
else
{
//
// use available buffer
//
TransferSize = TransferBufferLength - TransferBufferOffset;
}
//
@ -763,7 +790,7 @@ CUSBRequest::BuildTransferDescriptorChain(
//
InitDescriptor(CurrentDescriptor,
(PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset),
TransferBufferLength - TransferBufferOffset,
TransferSize,
PidCode,
InitialDataToggle,
&DescriptorLength);
@ -783,9 +810,17 @@ CUSBRequest::BuildTransferDescriptorChain(
//
// link to current descriptor
//
LastDescriptor->AlternateNextPointer = CurrentDescriptor->PhysicalAddr;
LastDescriptor->NextPointer = CurrentDescriptor->PhysicalAddr;
LastDescriptor = CurrentDescriptor;
if (AlternativeDescriptor)
{
//
// link to alternative next pointer
//
LastDescriptor->AlternateNextPointer = AlternativeDescriptor->PhysicalAddr;
}
}
else
{
@ -795,6 +830,11 @@ CUSBRequest::BuildTransferDescriptorChain(
LastDescriptor = FirstDescriptor = CurrentDescriptor;
}
//
// flip data toggle
//
InitialDataToggle = !InitialDataToggle;
if(TransferBufferLength == TransferBufferOffset)
{
//
@ -802,6 +842,7 @@ CUSBRequest::BuildTransferDescriptorChain(
//
break;
}
}while(TRUE);
if (OutFirstDescriptor)
@ -822,11 +863,6 @@ CUSBRequest::BuildTransferDescriptorChain(
if (OutDataToggle)
{
//
// flip data toggle
//
InitialDataToggle = !InitialDataToggle;
//
// store result data toggle
//
@ -918,14 +954,7 @@ CUSBRequest::BuildControlTransferQueueHead(
//
QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
if (m_EndpointDescriptor)
{
//
// set endpoint address and max packet length
//
QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0x0F;
QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
}
ASSERT(m_EndpointDescriptor == FALSE);
//
// init setup descriptor
@ -954,6 +983,7 @@ CUSBRequest::BuildControlTransferQueueHead(
m_TransferBufferLength,
InternalGetPidDirection(),
TRUE,
NULL,
&FirstDescriptor,
&LastDescriptor,
NULL,
@ -1136,14 +1166,20 @@ CUSBRequest::BuildBulkTransferQueueHead(
//
ASSERT(m_EndpointDescriptor);
//
// use 4 * PAGE_SIZE at max for each new request
//
ULONG MaxTransferLength = min(4 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted);
//
// build bulk transfer descriptor chain
//
Status = BuildTransferDescriptorChain(QueueHead,
Base,
m_TransferBufferLength - m_TransferBufferLengthCompleted,
MaxTransferLength,
InternalGetPidDirection(),
m_EndpointDescriptor->DataToggle,
NULL,
&FirstDescriptor,
&LastDescriptor,
&m_EndpointDescriptor->DataToggle,
@ -1152,7 +1188,7 @@ CUSBRequest::BuildBulkTransferQueueHead(
//
// FIXME: handle errors
//
ASSERT(ChainDescriptorLength == m_TransferBufferLength);
//ASSERT(ChainDescriptorLength == m_TransferBufferLength);
//
// move to next offset
@ -1279,7 +1315,7 @@ CUSBRequest::CreateQueueHead(
//
// Set NakCountReload to max value possible
//
QueueHead->EndPointCharacteristics.NakCountReload = 0xF;
QueueHead->EndPointCharacteristics.NakCountReload = 0x3;
//
// Get the Initial Data Toggle from the QEDT
@ -1290,7 +1326,7 @@ CUSBRequest::CreateQueueHead(
// FIXME: check if High Speed Device
//
QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x01;
QueueHead->Token.DWord = 0;
QueueHead->Token.Bits.InterruptOnComplete = FALSE;