Author: janderwald
Date: Wed Feb 22 17:24:43 2012
New Revision: 55809
URL:
http://svn.reactos.org/svn/reactos?rev=55809&view=rev
Log:
[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
Modified:
trunk/reactos/drivers/usb/usbuhci/hardware.cpp
trunk/reactos/drivers/usb/usbuhci/hardware.h
trunk/reactos/drivers/usb/usbuhci/interfaces.h
trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp
trunk/reactos/drivers/usb/usbuhci/usb_request.cpp
Modified: trunk/reactos/drivers/usb/usbuhci/hardware.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/hardwa…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/hardware.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/hardware.cpp [iso-8859-1] Wed Feb 22 17:24:43 2012
@@ -686,7 +686,7 @@
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 @@
}
}
+ 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 @@
DPRINT1("[USBUHCI] Failed to allocate queue head %x Index %x\n",
Status, Index);
return Status;
}
-
+#if 0
//
// init stray descriptor
//
@@ -722,7 +764,7 @@
//
m_QueueHead[4]->LinkPhysical = m_StrayDescriptor->PhysicalAddress;
m_QueueHead[4]->NextLogicalDescriptor = m_StrayDescriptor;
-
+#endif
//
// allocate frame bandwidth array
@@ -1271,7 +1313,14 @@
if (Acknowledge)
{
//
+ // acknowledge interrupt
+ //
This->WriteRegister16(UHCI_USBSTS, Acknowledge);
+
+ //
+ // queue dpc
+ //
+ KeInsertQueueDpc(&This->m_IntDpcObject, UlongToPtr(Status), NULL);
}
//
@@ -1356,6 +1405,7 @@
IN PVOID SystemArgument2)
{
CUSBHardwareDevice *This;
+ ULONG Status;
//
// get parameters
@@ -1363,8 +1413,24 @@
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
Modified: trunk/reactos/drivers/usb/usbuhci/hardware.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/hardwa…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/hardware.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/hardware.h [iso-8859-1] Wed Feb 22 17:24:43 2012
@@ -92,10 +92,11 @@
ULONG BufferPhysical; // pointer to the buffer
// Software part
- ULONG PhysicalAddress; // Physical address of this descriptor
+ ULONG PhysicalAddress; // Physical address of this descriptor
PVOID NextLogicalDescriptor;
- ULONG BufferSize; // Size of the buffer
- PVOID BufferLogical; // Logical pointer to the buffer
+ 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
Modified: trunk/reactos/drivers/usb/usbuhci/interfaces.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/interf…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/interfaces.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/interfaces.h [iso-8859-1] Wed Feb 22 17:24:43 2012
@@ -437,6 +437,22 @@
// 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;
};
@@ -505,6 +521,14 @@
// Description: aborts all pending requsts of an device
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;
};
Modified: trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/usb_qu…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp [iso-8859-1] Wed Feb 22 17:24:43 2012
@@ -40,10 +40,16 @@
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 @@
LONG m_Ref;
// reference count
KSPIN_LOCK m_Lock;
// list lock
PUSBHARDWAREDEVICE m_Hardware;
// hardware
+
};
//=================================================================================================
@@ -106,25 +113,23 @@
}
NTSTATUS
-CUSBQueue::AddUSBRequest(
- IUSBRequest * Request)
-{
- PUHCI_QUEUE_HEAD NewQueueHead, QueueHead = NULL;
- NTSTATUS Status;
-
- DPRINT("CUSBQueue::AddUSBRequest\n");
-
- //
- // 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;
+CUSBQueue::AddQueueHead(
+ PUHCI_QUEUE_HEAD NewQueueHead)
+{
+ PUSBREQUEST Request;
+ PUHCI_QUEUE_HEAD QueueHead = NULL;
+
+
+ //
+ // get request
+ //
+ Request = (PUSBREQUEST)NewQueueHead->Request;
+ if (!Request)
+ {
+ //
+ // no request
+ //
+ return STATUS_INVALID_PARAMETER;
}
if (Request->GetTransferType() == USB_ENDPOINT_TYPE_CONTROL)
@@ -184,6 +189,40 @@
//
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 @@
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 @@
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)
Modified: trunk/reactos/drivers/usb/usbuhci/usb_request.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/usb_re…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/usb_request.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/usb_request.cpp [iso-8859-1] Wed Feb 22 17:24:43
2012
@@ -46,7 +46,8 @@
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 @@
//
// FIXME FIXME FIXME FIXME FIXME
//
- MaxPacketSize = 1280;
+ MaxPacketSize = 64; //1280;
do
{
@@ -857,7 +858,14 @@
//
// 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 @@
Status =
BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL),
m_TransferBufferLength,
Direction ? TD_TOKEN_IN : TD_TOKEN_OUT,
- FALSE,
+ TRUE,
&FirstDescriptor,
&LastDescriptor,
&ChainDescriptorLength,
@@ -1131,6 +1139,173 @@
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(