mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 09:25:10 +00:00
[USBUHCI]
- Queue dpc when the interrupt indicates completion of a transfer or an error interrupt - Implement checking if a queue head is complete - Free queue heads and associated endpoint descriptors svn path=/trunk/; revision=55809
This commit is contained in:
parent
e9cca27577
commit
6528183f15
5 changed files with 550 additions and 22 deletions
|
@ -686,7 +686,7 @@ CUSBHardwareDevice::InitializeController()
|
|||
m_QueueHead[Index]->PhysicalAddress = Address.LowPart;
|
||||
m_QueueHead[Index]->ElementPhysical = QH_TERMINATE;
|
||||
|
||||
if (Index > 1)
|
||||
if (Index > 0)
|
||||
{
|
||||
//
|
||||
// link queue heads
|
||||
|
@ -696,6 +696,48 @@ CUSBHardwareDevice::InitializeController()
|
|||
}
|
||||
}
|
||||
|
||||
DPRINT1("Index %lu QueueHead %p LinkPhysical %x ElementPhysical %x PhysicalAddress %x Request %x NextElementDescriptor %x\n",
|
||||
0,
|
||||
m_QueueHead[0],
|
||||
m_QueueHead[0]->LinkPhysical,
|
||||
m_QueueHead[0]->ElementPhysical,
|
||||
m_QueueHead[0]->PhysicalAddress,
|
||||
m_QueueHead[0]->Request,
|
||||
m_QueueHead[0]->NextElementDescriptor);
|
||||
DPRINT1("Index %lu QueueHead %p LinkPhysical %x ElementPhysical %x PhysicalAddress %x Request %x NextElementDescriptor %x\n",
|
||||
1,
|
||||
m_QueueHead[1],
|
||||
m_QueueHead[1]->LinkPhysical,
|
||||
m_QueueHead[1]->ElementPhysical,
|
||||
m_QueueHead[1]->PhysicalAddress,
|
||||
m_QueueHead[1]->Request,
|
||||
m_QueueHead[1]->NextElementDescriptor);
|
||||
|
||||
DPRINT1("Index %lu QueueHead %p LinkPhysical %x ElementPhysical %x PhysicalAddress %x Request %x NextElementDescriptor %x\n",
|
||||
2,
|
||||
m_QueueHead[2],
|
||||
m_QueueHead[2]->LinkPhysical,
|
||||
m_QueueHead[2]->ElementPhysical,
|
||||
m_QueueHead[2]->PhysicalAddress,
|
||||
m_QueueHead[2]->Request,
|
||||
m_QueueHead[2]->NextElementDescriptor);
|
||||
DPRINT1("Index %lu QueueHead %p LinkPhysical %x ElementPhysical %x PhysicalAddress %x Request %x NextElementDescriptor %x\n",
|
||||
3,
|
||||
m_QueueHead[3],
|
||||
m_QueueHead[3]->LinkPhysical,
|
||||
m_QueueHead[3]->ElementPhysical,
|
||||
m_QueueHead[3]->PhysicalAddress,
|
||||
m_QueueHead[3]->Request,
|
||||
m_QueueHead[3]->NextElementDescriptor);
|
||||
DPRINT1("Index %lu QueueHead %p LinkPhysical %x ElementPhysical %x PhysicalAddress %x Request %x NextElementDescriptor %x\n",
|
||||
4,
|
||||
m_QueueHead[4],
|
||||
m_QueueHead[4]->LinkPhysical,
|
||||
m_QueueHead[4]->ElementPhysical,
|
||||
m_QueueHead[4]->PhysicalAddress,
|
||||
m_QueueHead[4]->Request,
|
||||
m_QueueHead[4]->NextElementDescriptor);
|
||||
|
||||
//
|
||||
// terminate last queue head with stray descriptor
|
||||
//
|
||||
|
@ -708,7 +750,7 @@ CUSBHardwareDevice::InitializeController()
|
|||
DPRINT1("[USBUHCI] Failed to allocate queue head %x Index %x\n", Status, Index);
|
||||
return Status;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// init stray descriptor
|
||||
//
|
||||
|
@ -722,7 +764,7 @@ CUSBHardwareDevice::InitializeController()
|
|||
//
|
||||
m_QueueHead[4]->LinkPhysical = m_StrayDescriptor->PhysicalAddress;
|
||||
m_QueueHead[4]->NextLogicalDescriptor = m_StrayDescriptor;
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// allocate frame bandwidth array
|
||||
|
@ -1270,8 +1312,15 @@ InterruptServiceRoutine(
|
|||
//
|
||||
if (Acknowledge)
|
||||
{
|
||||
//
|
||||
// acknowledge interrupt
|
||||
//
|
||||
This->WriteRegister16(UHCI_USBSTS, Acknowledge);
|
||||
|
||||
//
|
||||
// queue dpc
|
||||
//
|
||||
KeInsertQueueDpc(&This->m_IntDpcObject, UlongToPtr(Status), NULL);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1356,6 +1405,7 @@ OhciDefferedRoutine(
|
|||
IN PVOID SystemArgument2)
|
||||
{
|
||||
CUSBHardwareDevice *This;
|
||||
ULONG Status;
|
||||
|
||||
//
|
||||
// get parameters
|
||||
|
@ -1363,8 +1413,24 @@ OhciDefferedRoutine(
|
|||
This = (CUSBHardwareDevice*)DeferredContext;
|
||||
|
||||
DPRINT("OhciDefferedRoutine\n");
|
||||
ASSERT(FALSE);
|
||||
|
||||
//
|
||||
// get status
|
||||
//
|
||||
Status = PtrToUlong(SystemArgument1);
|
||||
if (Status & (UHCI_USBSTS_USBINT | UHCI_USBSTS_ERRINT))
|
||||
{
|
||||
//
|
||||
// a transfer finished, inform the queue
|
||||
//
|
||||
This->m_UsbQueue->TransferInterrupt(Status & UHCI_USBSTS_USBINT);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// other event
|
||||
//
|
||||
DPRINT1("[USBUHCI] Status %x not handled\n", Status);
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
|
@ -96,6 +96,7 @@ typedef struct _UHCI_TRANSFER_DESCRIPTOR
|
|||
PVOID NextLogicalDescriptor;
|
||||
ULONG BufferSize; // Size of the buffer
|
||||
PVOID BufferLogical; // Logical pointer to the buffer
|
||||
PVOID UserBuffer;
|
||||
}UHCI_TRANSFER_DESCRIPTOR, *PUHCI_TRANSFER_DESCRIPTOR;
|
||||
|
||||
#define TD_NEXT_IS_QH 0x02
|
||||
|
|
|
@ -437,6 +437,22 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
|||
// Description: returns device speed
|
||||
|
||||
virtual USB_DEVICE_SPEED GetDeviceSpeed() = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//
|
||||
// CompletionCallback
|
||||
//
|
||||
// Description: notifies request that the endpoint descriptor is complete
|
||||
|
||||
virtual VOID CompletionCallback() = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//
|
||||
// FreeEndpointDescriptor
|
||||
//
|
||||
// Description: frees the associated endpoint descriptor and its general descriptors
|
||||
|
||||
virtual VOID FreeEndpointDescriptor(struct _UHCI_QUEUE_HEAD * OutDescriptor) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -506,6 +522,14 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown)
|
|||
|
||||
virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN struct _USB_ENDPOINT * EndpointDescriptor) = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//
|
||||
// TransferInterrupt
|
||||
//
|
||||
// Description: informs the queue that a interrupt completed
|
||||
|
||||
virtual VOID TransferInterrupt(UCHAR ErrorInterrupt) = 0;
|
||||
|
||||
};
|
||||
|
||||
typedef IUSBQueue *PUSBQUEUE;
|
||||
|
|
|
@ -40,10 +40,16 @@ public:
|
|||
virtual NTSTATUS CancelRequests();
|
||||
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
||||
virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN struct _USB_ENDPOINT * EndpointDescriptor);
|
||||
virtual VOID TransferInterrupt(UCHAR ErrorInterrupt);
|
||||
|
||||
|
||||
// local
|
||||
VOID LinkQueueHead(PUHCI_QUEUE_HEAD QueueHead, PUHCI_QUEUE_HEAD NextQueueHead);
|
||||
VOID UnLinkQueueHead(PUHCI_QUEUE_HEAD PreviousQueueHead, PUHCI_QUEUE_HEAD NextQueueHead);
|
||||
BOOLEAN IsQueueHeadComplete(PUHCI_QUEUE_HEAD QueueHead);
|
||||
NTSTATUS AddQueueHead(PUHCI_QUEUE_HEAD NewQueueHead);
|
||||
VOID QueueHeadCleanup(IN PUHCI_QUEUE_HEAD QueueHead, IN PUHCI_QUEUE_HEAD PreviousQueueHead, OUT PUHCI_QUEUE_HEAD *NextQueueHead);
|
||||
|
||||
|
||||
// constructor / destructor
|
||||
CUSBQueue(IUnknown *OuterUnknown){}
|
||||
|
@ -53,6 +59,7 @@ protected:
|
|||
LONG m_Ref; // reference count
|
||||
KSPIN_LOCK m_Lock; // list lock
|
||||
PUSBHARDWAREDEVICE m_Hardware; // hardware
|
||||
|
||||
};
|
||||
|
||||
//=================================================================================================
|
||||
|
@ -106,25 +113,23 @@ CUSBQueue::GetPendingRequestCount()
|
|||
}
|
||||
|
||||
NTSTATUS
|
||||
CUSBQueue::AddUSBRequest(
|
||||
IUSBRequest * Request)
|
||||
CUSBQueue::AddQueueHead(
|
||||
PUHCI_QUEUE_HEAD NewQueueHead)
|
||||
{
|
||||
PUHCI_QUEUE_HEAD NewQueueHead, QueueHead = NULL;
|
||||
NTSTATUS Status;
|
||||
PUSBREQUEST Request;
|
||||
PUHCI_QUEUE_HEAD QueueHead = NULL;
|
||||
|
||||
DPRINT("CUSBQueue::AddUSBRequest\n");
|
||||
|
||||
//
|
||||
// get queue head
|
||||
// get request
|
||||
//
|
||||
Status = Request->GetEndpointDescriptor(&NewQueueHead);
|
||||
if (!NT_SUCCESS(Status))
|
||||
Request = (PUSBREQUEST)NewQueueHead->Request;
|
||||
if (!Request)
|
||||
{
|
||||
//
|
||||
// failed to create queue head
|
||||
// no request
|
||||
//
|
||||
DPRINT1("[USBUHCI] Failed to create queue head %x\n", Status);
|
||||
return Status;
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (Request->GetTransferType() == USB_ENDPOINT_TYPE_CONTROL)
|
||||
|
@ -184,6 +189,40 @@ CUSBQueue::AddUSBRequest(
|
|||
//
|
||||
LinkQueueHead(QueueHead, NewQueueHead);
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
CUSBQueue::AddUSBRequest(
|
||||
IUSBRequest * Request)
|
||||
{
|
||||
PUHCI_QUEUE_HEAD NewQueueHead;
|
||||
NTSTATUS Status;
|
||||
|
||||
//
|
||||
// get queue head
|
||||
//
|
||||
Status = Request->GetEndpointDescriptor(&NewQueueHead);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
//
|
||||
// failed to create queue head
|
||||
//
|
||||
DPRINT1("[USBUHCI] Failed to create queue head %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// sanity check
|
||||
//
|
||||
ASSERT(PVOID(Request) == NewQueueHead->Request);
|
||||
|
||||
//
|
||||
// add queue head
|
||||
//
|
||||
DPRINT1("AddUSBRequest Request %p\n", Request);
|
||||
DPRINT1("NewQueueHead %p\n", NewQueueHead);
|
||||
return AddQueueHead(NewQueueHead);
|
||||
}
|
||||
|
||||
VOID
|
||||
|
@ -198,6 +237,17 @@ CUSBQueue::LinkQueueHead(
|
|||
QueueHead->NextLogicalDescriptor = (PVOID)NextQueueHead;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
CUSBQueue::UnLinkQueueHead(
|
||||
PUHCI_QUEUE_HEAD QueueHeadToRemove,
|
||||
PUHCI_QUEUE_HEAD PreviousQueueHead)
|
||||
{
|
||||
PreviousQueueHead->LinkPhysical = QueueHeadToRemove->LinkPhysical;
|
||||
PreviousQueueHead->NextLogicalDescriptor = QueueHeadToRemove->NextLogicalDescriptor;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CUSBQueue::CancelRequests()
|
||||
{
|
||||
|
@ -233,6 +283,218 @@ CUSBQueue::CreateUSBRequest(
|
|||
return Status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
CUSBQueue::IsQueueHeadComplete(
|
||||
IN PUHCI_QUEUE_HEAD QueueHead)
|
||||
{
|
||||
PUHCI_TRANSFER_DESCRIPTOR Descriptor;
|
||||
ULONG ErrorCount;
|
||||
|
||||
if (QueueHead->NextElementDescriptor == NULL)
|
||||
{
|
||||
//
|
||||
// empty queue head
|
||||
//
|
||||
DPRINT1("QueueHead %p empty element physical\n", QueueHead);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// check all descriptors
|
||||
//
|
||||
Descriptor = (PUHCI_TRANSFER_DESCRIPTOR)QueueHead->NextElementDescriptor;
|
||||
while(Descriptor)
|
||||
{
|
||||
if (Descriptor->Status & TD_STATUS_ACTIVE)
|
||||
{
|
||||
//
|
||||
// descriptor is still active
|
||||
//
|
||||
DPRINT1("Descriptor %p is active Status %x BufferSize %lu\n", Descriptor, Descriptor->Status, Descriptor->BufferSize);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Descriptor->Status & TD_ERROR_MASK)
|
||||
{
|
||||
//
|
||||
// error happened
|
||||
//
|
||||
DPRINT1("[USBUHCI] Error detected at descriptor %p Physical %x\n", Descriptor, Descriptor->PhysicalAddress);
|
||||
|
||||
//
|
||||
// get error count
|
||||
//
|
||||
ErrorCount = (Descriptor->Status >> TD_ERROR_COUNT_SHIFT) & TD_ERROR_COUNT_MASK;
|
||||
if (ErrorCount == 0)
|
||||
{
|
||||
//
|
||||
// error retry count elapsed
|
||||
//
|
||||
DPRINT1("[USBUHCI] ErrorBuffer %x TimeOut %x Nak %x BitStuff %x\n",
|
||||
Descriptor->Status & TD_STATUS_ERROR_BUFFER,
|
||||
Descriptor->Status & TD_STATUS_ERROR_TIMEOUT,
|
||||
Descriptor->Status & TD_STATUS_ERROR_NAK,
|
||||
Descriptor->Status & TD_STATUS_ERROR_BITSTUFF);
|
||||
return TRUE;
|
||||
}
|
||||
else if (Descriptor->Status & TD_STATUS_ERROR_BABBLE)
|
||||
{
|
||||
//
|
||||
// babble error
|
||||
//
|
||||
DPRINT1("[USBUHCI] Babble detected\n");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// stall detected
|
||||
//
|
||||
DPRINT1("[USBUHCI] Stall detected\n");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// move to next descriptor
|
||||
//
|
||||
Descriptor = (PUHCI_TRANSFER_DESCRIPTOR)Descriptor->NextLogicalDescriptor;
|
||||
}
|
||||
|
||||
//
|
||||
// request is complete
|
||||
//
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
CUSBQueue::QueueHeadCleanup(
|
||||
IN PUHCI_QUEUE_HEAD QueueHead,
|
||||
IN PUHCI_QUEUE_HEAD PreviousQueueHead,
|
||||
OUT PUHCI_QUEUE_HEAD *NextQueueHead)
|
||||
{
|
||||
PUSBREQUEST Request;
|
||||
PUHCI_QUEUE_HEAD NewQueueHead;
|
||||
NTSTATUS Status;
|
||||
|
||||
//
|
||||
// unlink queue head
|
||||
//
|
||||
UnLinkQueueHead(QueueHead, PreviousQueueHead);
|
||||
|
||||
//
|
||||
// get next queue head
|
||||
//
|
||||
*NextQueueHead = (PUHCI_QUEUE_HEAD)PreviousQueueHead->NextLogicalDescriptor;
|
||||
ASSERT(*NextQueueHead != QueueHead);
|
||||
|
||||
//
|
||||
// the queue head is complete, is the transfer now completed?
|
||||
//
|
||||
Request = (PUSBREQUEST)QueueHead->Request;
|
||||
ASSERT(Request);
|
||||
|
||||
//
|
||||
// free queue head
|
||||
//
|
||||
DPRINT1("Request %p\n", Request);
|
||||
Request->FreeEndpointDescriptor(QueueHead);
|
||||
|
||||
//
|
||||
// check if transfer is complete
|
||||
//
|
||||
if (Request->IsRequestComplete())
|
||||
{
|
||||
//
|
||||
// the transfer is complete
|
||||
//
|
||||
Request->CompletionCallback();
|
||||
Request->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// grab new queue head
|
||||
//
|
||||
Status = Request->GetEndpointDescriptor(&NewQueueHead);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
//
|
||||
// failed to get new queue head
|
||||
//
|
||||
DPRINT1("[USBUHCI] Failed to get new queue head with %x\n", Status);
|
||||
Request->CompletionCallback();
|
||||
Request->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Link queue head
|
||||
//
|
||||
Status = AddQueueHead(NewQueueHead);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
//
|
||||
// failed to get new queue head
|
||||
//
|
||||
DPRINT1("[USBUHCI] Failed to add queue head with %x\n", Status);
|
||||
Request->CompletionCallback();
|
||||
Request->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VOID
|
||||
CUSBQueue::TransferInterrupt(
|
||||
UCHAR ErrorInterrupt)
|
||||
{
|
||||
KIRQL OldLevel;
|
||||
PUHCI_QUEUE_HEAD QueueHead, PreviousQueueHead = NULL;
|
||||
BOOLEAN IsComplete;
|
||||
|
||||
//
|
||||
// acquire lock
|
||||
//
|
||||
KeAcquireSpinLock(&m_Lock, &OldLevel);
|
||||
|
||||
//
|
||||
// get queue head
|
||||
//
|
||||
m_Hardware->GetQueueHead(UHCI_INTERRUPT_QUEUE, &QueueHead);
|
||||
|
||||
while(QueueHead)
|
||||
{
|
||||
//
|
||||
// is queue head complete
|
||||
//
|
||||
DPRINT1("QueueHead %p\n", QueueHead);
|
||||
IsComplete = IsQueueHeadComplete(QueueHead);
|
||||
if (IsComplete)
|
||||
{
|
||||
//
|
||||
// cleanup queue head
|
||||
//
|
||||
QueueHeadCleanup(QueueHead, PreviousQueueHead, &QueueHead);
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// backup previous queue head
|
||||
//
|
||||
PreviousQueueHead = QueueHead;
|
||||
|
||||
//
|
||||
// get next queue head
|
||||
//
|
||||
QueueHead = (PUHCI_QUEUE_HEAD)QueueHead->NextLogicalDescriptor;
|
||||
}
|
||||
|
||||
//
|
||||
// release lock
|
||||
//
|
||||
KeReleaseSpinLock(&m_Lock, OldLevel);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
CreateUSBQueue(
|
||||
PUSBQUEUE *OutUsbQueue)
|
||||
|
|
|
@ -46,7 +46,8 @@ public:
|
|||
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
||||
virtual UCHAR GetInterval();
|
||||
virtual USB_DEVICE_SPEED GetDeviceSpeed();
|
||||
|
||||
virtual VOID CompletionCallback();
|
||||
virtual VOID FreeEndpointDescriptor(struct _UHCI_QUEUE_HEAD * OutDescriptor);
|
||||
|
||||
// local functions
|
||||
ULONG InternalGetTransferType();
|
||||
|
@ -829,7 +830,7 @@ CUSBRequest::BuildTransferDescriptorChain(
|
|||
//
|
||||
// FIXME FIXME FIXME FIXME FIXME
|
||||
//
|
||||
MaxPacketSize = 1280;
|
||||
MaxPacketSize = 64; //1280;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -857,7 +858,14 @@ CUSBRequest::BuildTransferDescriptorChain(
|
|||
//
|
||||
// copy buffer
|
||||
//
|
||||
RtlCopyMemory(CurrentDescriptor->BufferLogical, TransferBuffer, CurrentBufferSize);
|
||||
RtlCopyMemory(CurrentDescriptor->BufferLogical, (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset), CurrentBufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// store user buffer
|
||||
//
|
||||
CurrentDescriptor->UserBuffer = (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset);
|
||||
}
|
||||
|
||||
if (!FirstDescriptor)
|
||||
|
@ -1075,7 +1083,7 @@ CUSBRequest::BuildControlTransferDescriptor(
|
|||
Status = BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL),
|
||||
m_TransferBufferLength,
|
||||
Direction ? TD_TOKEN_IN : TD_TOKEN_OUT,
|
||||
FALSE,
|
||||
TRUE,
|
||||
&FirstDescriptor,
|
||||
&LastDescriptor,
|
||||
&ChainDescriptorLength,
|
||||
|
@ -1131,6 +1139,173 @@ CUSBRequest::GetDeviceSpeed()
|
|||
return m_DeviceSpeed;
|
||||
}
|
||||
|
||||
VOID
|
||||
CUSBRequest::FreeEndpointDescriptor(
|
||||
struct _UHCI_QUEUE_HEAD * OutDescriptor)
|
||||
{
|
||||
PUHCI_TRANSFER_DESCRIPTOR Descriptor, NextDescriptor;
|
||||
ULONG ErrorCount;
|
||||
|
||||
//
|
||||
// grab first transfer descriptor
|
||||
//
|
||||
Descriptor = (PUHCI_TRANSFER_DESCRIPTOR)OutDescriptor->NextElementDescriptor;
|
||||
while(Descriptor)
|
||||
{
|
||||
if (Descriptor->Status & TD_ERROR_MASK)
|
||||
{
|
||||
//
|
||||
// error happened
|
||||
//
|
||||
DPRINT1("[USBUHCI] Error detected at descriptor %p Physical %x\n", Descriptor, Descriptor->PhysicalAddress);
|
||||
|
||||
//
|
||||
// get error count
|
||||
//
|
||||
ErrorCount = (Descriptor->Status >> TD_ERROR_COUNT_SHIFT) & TD_ERROR_COUNT_MASK;
|
||||
if (ErrorCount == 0)
|
||||
{
|
||||
//
|
||||
// error retry count elapsed
|
||||
//
|
||||
m_NtStatusCode = STATUS_UNSUCCESSFUL;
|
||||
|
||||
if (Descriptor->Status & TD_STATUS_ERROR_BUFFER)
|
||||
{
|
||||
DPRINT1("[USBUHCI] Buffer Error detected in descriptor %p\n", Descriptor);
|
||||
m_UrbStatusCode = USBD_STATUS_DATA_BUFFER_ERROR;
|
||||
}
|
||||
else if (Descriptor->Status & TD_STATUS_ERROR_TIMEOUT)
|
||||
{
|
||||
DPRINT1("[USBUHCI] Timeout detected in descriptor %p\n", Descriptor);
|
||||
m_UrbStatusCode = USBD_STATUS_TIMEOUT;
|
||||
}
|
||||
else if (Descriptor->Status & TD_STATUS_ERROR_NAK)
|
||||
{
|
||||
DPRINT1("[USBUHCI] Unexpected pid detected in descriptor %p\n", Descriptor);
|
||||
m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
|
||||
}
|
||||
else if (Descriptor->Status & TD_STATUS_ERROR_BITSTUFF)
|
||||
{
|
||||
DPRINT1("[USBUHCI] BitStuff detected in descriptor %p\n", Descriptor);
|
||||
m_UrbStatusCode = USBD_STATUS_BTSTUFF;
|
||||
}
|
||||
}
|
||||
else if (Descriptor->Status & TD_STATUS_ERROR_BABBLE)
|
||||
{
|
||||
//
|
||||
// babble error
|
||||
//
|
||||
DPRINT1("[USBUHCI] Babble detected in descriptor %p\n", Descriptor);
|
||||
m_UrbStatusCode = USBD_STATUS_BABBLE_DETECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// stall detected
|
||||
//
|
||||
DPRINT1("[USBUHCI] Stall detected\n");
|
||||
m_UrbStatusCode = USBD_STATUS_STALL_PID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// FIXME detect actual length
|
||||
//
|
||||
if (Descriptor->UserBuffer)
|
||||
{
|
||||
//
|
||||
// copy contents back
|
||||
//
|
||||
RtlCopyMemory(Descriptor->UserBuffer, Descriptor->BufferLogical, Descriptor->BufferSize);
|
||||
}
|
||||
}
|
||||
//
|
||||
// move to next descriptor
|
||||
//
|
||||
NextDescriptor = (PUHCI_TRANSFER_DESCRIPTOR)Descriptor->NextLogicalDescriptor;
|
||||
|
||||
//
|
||||
// free endpoint descriptor
|
||||
//
|
||||
FreeDescriptor(Descriptor);
|
||||
|
||||
//
|
||||
// move to next
|
||||
//
|
||||
Descriptor = NextDescriptor;
|
||||
}
|
||||
|
||||
//
|
||||
// now free queue head
|
||||
//
|
||||
m_DmaManager->Release(OutDescriptor, sizeof(UHCI_QUEUE_HEAD));
|
||||
|
||||
}
|
||||
|
||||
VOID
|
||||
CUSBRequest::CompletionCallback()
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
PURB Urb;
|
||||
|
||||
DPRINT("CUSBRequest::CompletionCallback\n");
|
||||
|
||||
if (m_Irp)
|
||||
{
|
||||
//
|
||||
// set irp completion status
|
||||
//
|
||||
m_Irp->IoStatus.Status = m_NtStatusCode;
|
||||
|
||||
//
|
||||
// get current irp stack location
|
||||
//
|
||||
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
|
||||
|
||||
//
|
||||
// get urb
|
||||
//
|
||||
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
||||
|
||||
//
|
||||
// store urb status
|
||||
//
|
||||
Urb->UrbHeader.Status = m_UrbStatusCode;
|
||||
|
||||
//
|
||||
// Check if the MDL was created
|
||||
//
|
||||
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
|
||||
{
|
||||
//
|
||||
// Free Mdl
|
||||
//
|
||||
IoFreeMdl(m_TransferBufferMDL);
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME calculate length
|
||||
//
|
||||
|
||||
//
|
||||
// complete request
|
||||
//
|
||||
IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// signal completion event
|
||||
//
|
||||
PC_ASSERT(m_CompletionEvent);
|
||||
KeSetEvent(m_CompletionEvent, 0, FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
NTSTATUS
|
||||
InternalCreateUSBRequest(
|
||||
|
|
Loading…
Reference in a new issue