diff --git a/drivers/usb/usbehci_new/hardware.h b/drivers/usb/usbehci_new/hardware.h index eb8e74d7958..4c5e01eb6a1 100644 --- a/drivers/usb/usbehci_new/hardware.h +++ b/drivers/usb/usbehci_new/hardware.h @@ -127,6 +127,7 @@ typedef struct _QUEUE_TRANSFER_DESCRIPTOR //Software ULONG PhysicalAddr; LIST_ENTRY LinkedDescriptors; + ULONG TotalBytesToTransfer; } QUEUE_TRANSFER_DESCRIPTOR, *PQUEUE_TRANSFER_DESCRIPTOR; // diff --git a/drivers/usb/usbehci_new/usb_queue.cpp b/drivers/usb/usbehci_new/usb_queue.cpp index 2ff58218ef5..426d72cd03f 100644 --- a/drivers/usb/usbehci_new/usb_queue.cpp +++ b/drivers/usb/usbehci_new/usb_queue.cpp @@ -52,6 +52,8 @@ protected: 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); @@ -120,6 +122,11 @@ CUSBQueue::Initialize( // InitializeListHead(&m_CompletedRequestAsyncList); + // + // Initialize pending async list head + // + InitializeListHead(&m_PendingRequestAsyncList); + return Status; } @@ -425,19 +432,157 @@ CUSBQueue::QueueHeadCompletion( NTSTATUS Status) { IUSBRequest *Request; - USBD_STATUS UrbStatus; PQUEUE_HEAD NewQueueHead; // - // this function is called when a queue head has been completed + // now unlink the queue head + // FIXME: implement chained queue heads // - PC_ASSERT(CurrentQH->Token.Bits.Active == 0); + 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; + + // + // sanity checks + // + PC_ASSERT(CurrentQH->Token.Bits.Active == 0); + PC_ASSERT(CurrentQH->Request); + + + // + // get request + // + Request = (IUSBRequest*)CurrentQH->Request; + // // sanity check // @@ -481,145 +626,7 @@ CUSBQueue::QueueHeadCompletion( // // 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 @@ -689,6 +696,27 @@ CUSBQueue::CompleteAsyncRequests() QueueHeadCleanup(CurrentQH); } + // + // 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 // diff --git a/drivers/usb/usbehci_new/usb_request.cpp b/drivers/usb/usbehci_new/usb_request.cpp index 02ccfbe592a..d5dd5bed89d 100644 --- a/drivers/usb/usbehci_new/usb_request.cpp +++ b/drivers/usb/usbehci_new/usb_request.cpp @@ -61,6 +61,7 @@ public: UCHAR GetDeviceAddress(); NTSTATUS BuildSetupPacket(); NTSTATUS BuildSetupPacketFromURB(); + ULONG InternalCalculateTransferLength(); // constructor / destructor CUSBRequest(IUnknown *OuterUnknown){} @@ -252,10 +253,15 @@ CUSBRequest::InitializeWithIrp( // 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 @@ CUSBRequest::CompletionCallback( // Urb->UrbHeader.Length = 0; } + else + { + // + // calculate transfer length + // + Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = InternalCalculateTransferLength(); + } - DPRINT1("Request %p Completing Irp %p NtStatusCode %x UrbStatusCode %x\n", this, m_Irp, NtStatusCode, UrbStatusCode); + 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 @@ CUSBRequest::GetTransferType() ULONG CUSBRequest::InternalGetTransferType() { - PIO_STACK_LOCATION IoStack; - PURB Urb; - PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; ULONG TransferType; // @@ -535,38 +545,12 @@ CUSBRequest::InternalGetTransferType() // if (m_Irp) { - // - // get stack location - // - IoStack = IoGetCurrentIrpStackLocation(m_Irp); + ASSERT(m_EndpointDescriptor); // - // get urb + // end point is defined in the low byte of bmAttributes // - 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; - } + TransferType = (m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK); } else { @@ -585,30 +569,13 @@ CUSBRequest::InternalGetTransferType() 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 @@ CUSBRequest::BuildBulkTransferQueueHead( // // 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 @@ CUSBRequest::BuildBulkTransferQueueHead( // // check if request fills another page // - if (PageOffset + BytesAvailable >= PAGE_SIZE) + if (PageOffset + BytesAvailable > PAGE_SIZE) { // // move to next page @@ -976,6 +946,11 @@ CUSBRequest::BuildBulkTransferQueueHead( } } + // + // store transfer bytes of descriptor + // + m_TransferDescriptors[Index]->TotalBytesToTransfer = m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer; + // // Go ahead and link descriptors // @@ -1579,6 +1554,36 @@ CUSBRequest::GetTransferBuffer( *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