From 1ecef805ff39ad385dcce03f9b6a56933ae630b2 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Fri, 10 Feb 2012 20:15:39 +0000 Subject: [PATCH] [USBEHCI] - Partly revert 55516, as the memory bug got fixed svn path=/branches/usb-bringup-trunk/; revision=55530 --- drivers/usb/usbehci/hardware.cpp | 1 + drivers/usb/usbehci/hardware.h | 15 +- drivers/usb/usbehci/hub_controller.cpp | 222 +++++- drivers/usb/usbehci/interfaces.h | 21 +- drivers/usb/usbehci/usb_device.cpp | 41 +- drivers/usb/usbehci/usb_queue.cpp | 22 +- drivers/usb/usbehci/usb_request.cpp | 928 ++++++++++++++----------- drivers/usb/usbehci/usbehci.h | 22 + 8 files changed, 823 insertions(+), 449 deletions(-) diff --git a/drivers/usb/usbehci/hardware.cpp b/drivers/usb/usbehci/hardware.cpp index 82da8d7a73f..5af6529f382 100644 --- a/drivers/usb/usbehci/hardware.cpp +++ b/drivers/usb/usbehci/hardware.cpp @@ -1339,6 +1339,7 @@ EhciDefferedRoutine( // controller reported error // DPRINT1("CStatus %x\n", CStatus); + ASSERT(FALSE); } // diff --git a/drivers/usb/usbehci/hardware.h b/drivers/usb/usbehci/hardware.h index 12df5c8fcbd..b940ab2097b 100644 --- a/drivers/usb/usbehci/hardware.h +++ b/drivers/usb/usbehci/hardware.h @@ -148,7 +148,7 @@ typedef struct _QUEUE_TRANSFER_DESCRIPTOR //Software ULONG PhysicalAddr; - LIST_ENTRY LinkedDescriptors; + LIST_ENTRY DescriptorEntry; ULONG TotalBytesToTransfer; } QUEUE_TRANSFER_DESCRIPTOR, *PQUEUE_TRANSFER_DESCRIPTOR; @@ -216,9 +216,21 @@ typedef struct _QUEUE_HEAD //Software ULONG PhysicalAddr; LIST_ENTRY LinkedQueueHeads; + LIST_ENTRY TransferDescriptorListHead; PVOID Request; } QUEUE_HEAD, *PQUEUE_HEAD; +C_ASSERT(sizeof(END_POINT_CHARACTERISTICS) == 4); +C_ASSERT(sizeof(END_POINT_CAPABILITIES) == 4); + +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, HorizontalLinkPointer) == 0x00); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, EndPointCharacteristics) == 0x04); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, EndPointCapabilities) == 0x08); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, CurrentLinkPointer) == 0xC); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, NextPointer) == 0x10); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, AlternateNextPointer) == 0x14); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, Token) == 0x18); +C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, BufferPointer) == 0x1C); C_ASSERT(FIELD_OFFSET(QUEUE_HEAD, PhysicalAddr) == 0x30); @@ -292,3 +304,4 @@ typedef struct ULONG PortChange; }EHCI_PORT_STATUS; + diff --git a/drivers/usb/usbehci/hub_controller.cpp b/drivers/usb/usbehci/hub_controller.cpp index 8342a7d17b9..5c49c219911 100644 --- a/drivers/usb/usbehci/hub_controller.cpp +++ b/drivers/usb/usbehci/hub_controller.cpp @@ -70,6 +70,9 @@ public: NTSTATUS HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleClearStall(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleSyncResetAndClearStall(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleAbortPipe(IN OUT PIRP Irp, PURB Urb); friend VOID StatusChangeEndpointCallBack(PVOID Context); @@ -1675,12 +1678,21 @@ CHubController::HandleClassEndpoint( // // initialize setup packet // - CtrlSetup.bmRequestType.B = 0xa2; //FIXME: Const. + CtrlSetup.bmRequestType.B = 0x22; //FIXME: Const. CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength; + if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + // + // data direction is device to host + // + CtrlSetup.bmRequestType.B |= 0x80; + } + + // // issue request // @@ -1698,6 +1710,185 @@ CHubController::HandleClassEndpoint( return Status; } +NTSTATUS +CHubController::HandleSyncResetAndClearStall( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + NTSTATUS Status = STATUS_SUCCESS; + PUSB_ENDPOINT EndpointDescriptor; + ULONG Type; + + // + // sanity check + // + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + PC_ASSERT(Urb->UrbPipeRequest.PipeHandle); + + // + // check if this is a valid usb device handle + // + if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) + { + DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbPipeRequest.PipeHandle; + + // + // get type + // + Type = (EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK); + if (Type != USB_ENDPOINT_TYPE_ISOCHRONOUS) + { + // + // clear stall + // + Status = HandleClearStall(Irp, Urb); + } + DPRINT1("URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL Status %x\n", Status); + + // + // reset data toggle + // + ASSERT(NT_SUCCESS(Status)); + EndpointDescriptor->DataToggle = 0x0; + + // + // done + // + return Status; +} + +NTSTATUS +CHubController::HandleAbortPipe( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + NTSTATUS Status; + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + + // + // sanity check + // + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + PC_ASSERT(Urb->UrbPipeRequest.PipeHandle); + + // + // check if this is a valid usb device handle + // + if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) + { + DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle; + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + + // + // issue request + // + Status = UsbDevice->AbortPipe(EndpointDescriptor); + DPRINT1("URB_FUNCTION_ABORT_PIPE Status %x\n", Status); + + // + // done + // + return Status; +} + + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleClearStall( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + + + // + // sanity check + // + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + PC_ASSERT(Urb->UrbPipeRequest.PipeHandle); + + // + // check if this is a valid usb device handle + // + if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) + { + DPRINT1("HandleClearStall invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle; + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + DPRINT1("URB_FUNCTION_SYNC_CLEAR_STALL\n"); + + // + // initialize setup packet + // + CtrlSetup.bmRequestType.B = 0x02; + CtrlSetup.bRequest = USB_REQUEST_CLEAR_FEATURE; + CtrlSetup.wValue.W = USB_FEATURE_ENDPOINT_STALL; + CtrlSetup.wIndex.W = EndpointDescriptor->bEndpointAddress; + CtrlSetup.wLength = 0; + CtrlSetup.wValue.W = 0; + + // + // issue request + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, 0, 0); + + DPRINT1("URB_FUNCTION_CLEAR_STALL Status %x\n", Status); + + // + // done + // + return Status; +} + + //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleClassInterface( @@ -1747,12 +1938,20 @@ CHubController::HandleClassInterface( // // initialize setup packet // - CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const. + CtrlSetup.bmRequestType.B = 0x21; CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request; CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value; CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index; CtrlSetup.wLength = Urb->UrbControlVendorClassRequest.TransferBufferLength; + if (Urb->UrbControlVendorClassRequest.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + { + // + // data direction is device to host + // + CtrlSetup.bmRequestType.B |= 0x80; + } + // // issue request // @@ -1761,8 +1960,13 @@ CHubController::HandleClassInterface( // // assert on failure // - PC_ASSERT(NT_SUCCESS(Status)); - + if (!NT_SUCCESS(Status)) + { + // + // display error + // + DPRINT1("URB_FUNCTION_CLASS_INTERFACE failed with Urb Status %x\n", Urb->UrbHeader.Status); + } // // done @@ -1806,6 +2010,16 @@ CHubController::HandleDeviceControl( switch (Urb->UrbHeader.Function) { + case URB_FUNCTION_SYNC_RESET_PIPE: + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + Status = HandleSyncResetAndClearStall(Irp, Urb); + break; + case URB_FUNCTION_ABORT_PIPE: + Status = HandleAbortPipe(Irp, Urb); + break; + case URB_FUNCTION_SYNC_CLEAR_STALL: + Status = HandleClearStall(Irp, Urb); + break; case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: Status = HandleGetDescriptorFromInterface(Irp, Urb); break; diff --git a/drivers/usb/usbehci/interfaces.h b/drivers/usb/usbehci/interfaces.h index 242ffb16611..8527948903d 100644 --- a/drivers/usb/usbehci/interfaces.h +++ b/drivers/usb/usbehci/interfaces.h @@ -379,6 +379,7 @@ typedef IDMAMemoryManager *PDMAMEMORYMANAGER; // struct _QUEUE_HEAD; +struct _USB_ENDPOINT; DECLARE_INTERFACE_(IUSBRequest, IUnknown) { @@ -395,7 +396,7 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, - IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, + IN OPTIONAL struct _USB_ENDPOINT *EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer) = 0; @@ -588,6 +589,15 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown) // This function gets called by IUSBHardware after it the Interrupt on Async Advance bit has been set virtual VOID CompleteAsyncRequests() = 0; + +//----------------------------------------------------------------------------------------- +// +// AbortDevicePipe +// +// Description: aborts all pending requsts of an device + + virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) = 0; + }; typedef IUSBQueue *PUSBQUEUE; @@ -841,6 +851,15 @@ DECLARE_INTERFACE_(IUSBDevice, IUnknown) virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, IN OUT PUSBD_INTERFACE_INFORMATION Interface) = 0; + +//----------------------------------------------------------------------------------------- +// +// AbortPipe +// +// Description: aborts all pending requsts + + virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) = 0; + }; typedef IUSBDevice *PUSBDEVICE; diff --git a/drivers/usb/usbehci/usb_device.cpp b/drivers/usb/usbehci/usb_device.cpp index 04d63701f3b..323207737ac 100644 --- a/drivers/usb/usbehci/usb_device.cpp +++ b/drivers/usb/usbehci/usb_device.cpp @@ -11,24 +11,6 @@ #define INITGUID #include "usbehci.h" -typedef struct _USB_ENDPOINT -{ - USB_ENDPOINT_DESCRIPTOR EndPointDescriptor; -} USB_ENDPOINT, *PUSB_ENDPOINT; - -typedef struct _USB_INTERFACE -{ - USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; - USB_ENDPOINT *EndPoints; -} USB_INTERFACE, *PUSB_INTERFACE; - -typedef struct _USB_CONFIGURATION -{ - USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; - USB_INTERFACE *Interfaces; -} USB_CONFIGURATION, *PUSB_CONFIGURATION; - - class CUSBDevice : public IUSBDevice { public: @@ -70,10 +52,12 @@ public: virtual NTSTATUS SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, OUT ULONG BufferLength, OUT PVOID Buffer); virtual NTSTATUS SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN PUSBD_INTERFACE_INFORMATION Interface, OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle); virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, IN OUT PUSBD_INTERFACE_INFORMATION Interface); + virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor); + // local function virtual NTSTATUS CommitIrp(PIRP Irp); - virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl); + virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl); virtual NTSTATUS CreateConfigurationDescriptor(ULONG ConfigurationIndex); virtual NTSTATUS CreateDeviceDescriptor(); virtual VOID DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor); @@ -537,7 +521,7 @@ CUSBDevice::SubmitIrp( NTSTATUS CUSBDevice::CommitSetupPacket( IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, - IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, + IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl) { @@ -1273,6 +1257,23 @@ CUSBDevice::SelectInterface( return Status; } +NTSTATUS +CUSBDevice::AbortPipe( + IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) +{ + // + // let it handle usb queue + // + ASSERT(m_Queue); + ASSERT(m_DeviceAddress); + + // + // done + // + return m_Queue->AbortDevicePipe(m_DeviceAddress, EndpointDescriptor); +} + + //---------------------------------------------------------------------------------------- NTSTATUS CreateUSBDevice( diff --git a/drivers/usb/usbehci/usb_queue.cpp b/drivers/usb/usbehci/usb_queue.cpp index 4206d5a9020..36a90e704da 100644 --- a/drivers/usb/usbehci/usb_queue.cpp +++ b/drivers/usb/usbehci/usb_queue.cpp @@ -41,6 +41,8 @@ public: virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest); virtual VOID InterruptCallback(IN NTSTATUS Status, OUT PULONG ShouldRingDoorBell); virtual VOID CompleteAsyncRequests(); + virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor); + // constructor / destructor CUSBQueue(IUnknown *OuterUnknown){} @@ -499,11 +501,6 @@ CUSBQueue::UnlinkQueueHead( // remove software link // RemoveEntryList(&QueueHead->LinkedQueueHeads); - - // - // FIXME: clear failure - // - QueueHead->Token.Bits.Halted = FALSE; } // @@ -629,6 +626,7 @@ CUSBQueue::ProcessAsyncList( // // walk async list // + ASSERT(AsyncListQueueHead); Entry = AsyncListQueueHead->LinkedQueueHeads.Flink; while(Entry != &AsyncListQueueHead->LinkedQueueHeads) @@ -637,6 +635,7 @@ CUSBQueue::ProcessAsyncList( // get queue head structure // QueueHead = (PQUEUE_HEAD)CONTAINING_RECORD(Entry, QUEUE_HEAD, LinkedQueueHeads); + ASSERT(QueueHead); // // sanity check @@ -658,7 +657,7 @@ CUSBQueue::ProcessAsyncList( // IsQueueHeadComplete = Request->IsQueueHeadComplete(QueueHead); - DPRINT1("Request %p QueueHead %p Complete %d\n", Request, QueueHead, IsQueueHeadComplete); + DPRINT("Request %p QueueHead %p Complete %d\n", Request, QueueHead, IsQueueHeadComplete); // // check if queue head is complete @@ -929,6 +928,16 @@ CUSBQueue::CompleteAsyncRequests() KeReleaseSpinLock(m_Lock, OldLevel); } +NTSTATUS +CUSBQueue::AbortDevicePipe( + IN UCHAR DeviceAddress, + IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} + + NTSTATUS CreateUSBQueue( PUSBQUEUE *OutUsbQueue) @@ -962,3 +971,4 @@ CreateUSBQueue( // return STATUS_SUCCESS; } + diff --git a/drivers/usb/usbehci/usb_request.cpp b/drivers/usb/usbehci/usb_request.cpp index cc16e25661b..c1dfd171251 100644 --- a/drivers/usb/usbehci/usb_request.cpp +++ b/drivers/usb/usbehci/usb_request.cpp @@ -36,7 +36,7 @@ public: } // IUSBRequest interface functions - virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer); + virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer); virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp); virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode, IN ULONG UrbStatusCode, IN struct _QUEUE_HEAD *QueueHead); virtual VOID CancelCallback(IN NTSTATUS NtStatusCode, IN struct _QUEUE_HEAD *QueueHead); @@ -62,6 +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); + 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){} @@ -118,18 +122,13 @@ protected: // // store end point address // - PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor; + PUSB_ENDPOINT m_EndpointDescriptor; // // DMA queue head // PQUEUE_HEAD m_QueueHead; - // - // DMA transfer descriptors linked to the queue head - // - PQUEUE_TRANSFER_DESCRIPTOR m_TransferDescriptors[4]; - // // allocated setup packet from the DMA pool // @@ -142,6 +141,8 @@ protected: NTSTATUS m_NtStatusCode; ULONG m_UrbStatusCode; + PVOID m_Base; + }; //---------------------------------------------------------------------------------------- @@ -160,7 +161,7 @@ CUSBRequest::InitializeWithSetupPacket( IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, - IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, + IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer) { @@ -321,7 +322,7 @@ CUSBRequest::InitializeWithIrp( // // get endpoint descriptor // - m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle; + m_EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbBulkOrInterruptTransfer.PipeHandle; } break; @@ -587,7 +588,7 @@ CUSBRequest::InternalGetTransferType() // // end point is defined in the low byte of bmAttributes // - TransferType = (m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK); + TransferType = (m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK); } else { @@ -595,6 +596,7 @@ CUSBRequest::InternalGetTransferType() // initialized with setup packet, must be a control transfer // TransferType = USB_ENDPOINT_TYPE_CONTROL; + ASSERT(m_EndpointDescriptor == FALSE); } // @@ -606,13 +608,243 @@ CUSBRequest::InternalGetTransferType() UCHAR CUSBRequest::InternalGetPidDirection() { - ASSERT(m_Irp); - ASSERT(m_EndpointDescriptor); + if (m_EndpointDescriptor) + { + // + // end point direction is highest bit in bEndpointAddress + // + return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7; + } + else + { + // + // request arrives on the control pipe, extract direction from setup packet + // + ASSERT(m_DescriptorPacket); + return (m_DescriptorPacket->bmRequestType.B >> 7); + } +} + +VOID +CUSBRequest::InitDescriptor( + IN PQUEUE_TRANSFER_DESCRIPTOR CurrentDescriptor, + IN PVOID TransferBuffer, + IN ULONG TransferBufferLength, + IN UCHAR PidCode, + IN UCHAR DataToggle, + OUT PULONG OutDescriptorLength) +{ + ULONG Index, Length = 0, PageOffset, BufferLength; // - // end point is defined in the low byte of bEndpointAddress + // init transfer descriptor // - return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7; + CurrentDescriptor->Token.Bits.PIDCode = PidCode; + CurrentDescriptor->Token.Bits.TotalBytesToTransfer = 0; + CurrentDescriptor->Token.Bits.DataToggle = DataToggle; + + // + // sanity check + // + ASSERT(TransferBufferLength); + + // + // store buffers + // + Index = 0; + do + { + // + // use physical address + // + CurrentDescriptor->BufferPointer[Index] = MmGetPhysicalAddress(TransferBuffer).LowPart; + + // + // Get the offset from page size + // + PageOffset = BYTE_OFFSET(CurrentDescriptor->BufferPointer[Index]); + if (PageOffset != 0) + { + // + // move to next page + // + TransferBuffer = (PVOID)ROUND_TO_PAGES(TransferBuffer); + } + else + { + // + // move to next page + // + TransferBuffer = (PVOID)((ULONG_PTR)TransferBuffer + PAGE_SIZE); + } + + // + // calculate buffer length + // + BufferLength = min(TransferBufferLength, PAGE_SIZE - PageOffset); + + // + // increment transfer bytes + // + CurrentDescriptor->Token.Bits.TotalBytesToTransfer += BufferLength; + CurrentDescriptor->TotalBytesToTransfer += BufferLength; + Length += BufferLength; + DPRINT("Index %lu TransferBufferLength %lu PageOffset %x BufferLength %lu Buffer Phy %p TransferBuffer %p\n", Index, TransferBufferLength, PageOffset, BufferLength, CurrentDescriptor->BufferPointer[Index], TransferBuffer); + + // + // decrement available byte count + // + TransferBufferLength -= BufferLength; + if (TransferBufferLength == 0) + { + // + // end reached + // + break; + } + + // + // sanity check + // + if (Index > 1) + { + // + // no equal buffers + // + ASSERT(CurrentDescriptor->BufferPointer[Index] != CurrentDescriptor->BufferPointer[Index-1]); + } + + // + // next descriptor index + // + Index++; + }while(Index < 5); + + // + // store result + // + *OutDescriptorLength = Length; +} + + +NTSTATUS +CUSBRequest::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) +{ + PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL; + NTSTATUS Status; + ULONG DescriptorLength, TransferBufferOffset = 0; + + do + { + // + // allocate transfer descriptor + // + Status = CreateDescriptor(&CurrentDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate transfer descriptor + // + ASSERT(FALSE); + return Status; + } + + // + // now init the descriptor + // + InitDescriptor(CurrentDescriptor, + (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset), + TransferBufferLength - TransferBufferOffset, + PidCode, + InitialDataToggle, + &DescriptorLength); + + // + // insert into queue head + // + InsertTailList(&QueueHead->TransferDescriptorListHead, &CurrentDescriptor->DescriptorEntry); + + // + // adjust offset + // + TransferBufferOffset += DescriptorLength; + + if (LastDescriptor) + { + // + // link to current descriptor + // + LastDescriptor->AlternateNextPointer = CurrentDescriptor->PhysicalAddr; + LastDescriptor->NextPointer = CurrentDescriptor->PhysicalAddr; + LastDescriptor = CurrentDescriptor; + } + else + { + // + // first descriptor in chain + // + LastDescriptor = FirstDescriptor = CurrentDescriptor; + } + + if(TransferBufferLength == TransferBufferOffset) + { + // + // end reached + // + break; + } + }while(TRUE); + + if (OutFirstDescriptor) + { + // + // store first descriptor + // + *OutFirstDescriptor = FirstDescriptor; + } + + if (OutLastDescriptor) + { + // + // store last descriptor + // + *OutLastDescriptor = CurrentDescriptor; + } + + if (OutDataToggle) + { + // + // flip data toggle + // + InitialDataToggle = !InitialDataToggle; + + // + // store result data toggle + // + *OutDataToggle = InitialDataToggle; + } + + if (OutTransferBufferOffset) + { + // + // store offset + // + *OutTransferBufferOffset = TransferBufferOffset; + } + + // + // done + // + return STATUS_SUCCESS; } //---------------------------------------------------------------------------------------- @@ -621,8 +853,9 @@ CUSBRequest::BuildControlTransferQueueHead( PQUEUE_HEAD * OutHead) { NTSTATUS Status; - ULONG NumTransferDescriptors, Index; + ULONG DescriptorChainLength; PQUEUE_HEAD QueueHead; + PQUEUE_TRANSFER_DESCRIPTOR SetupDescriptor, StatusDescriptor, FirstDescriptor, LastDescriptor; // // first allocate the queue head @@ -650,30 +883,34 @@ CUSBRequest::BuildControlTransferQueueHead( // // failed to allocate setup packet // + ASSERT(FALSE); return STATUS_INSUFFICIENT_RESOURCES; } // - // calculate num of transfer descriptors + // create setup descriptor // - NumTransferDescriptors = m_TransferBufferMDL != 0 ? 3 : 2; - - // - // allocate transfer descriptors - // - for(Index = 0; Index < NumTransferDescriptors; Index++) + Status = CreateDescriptor(&SetupDescriptor); + if (!NT_SUCCESS(Status)) { // - // allocate transfer descriptor + // failed to allocate transfer descriptor // - Status = CreateDescriptor(&m_TransferDescriptors[Index]); - if (!NT_SUCCESS(Status)) - { - // - // failed to allocate transfer descriptor - // - return Status; - } + ASSERT(FALSE); + return Status; + } + + // + // create status descriptor + // + Status = CreateDescriptor(&StatusDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate transfer descriptor + // + ASSERT(FALSE); + return Status; } // @@ -686,114 +923,168 @@ CUSBRequest::BuildControlTransferQueueHead( // // set endpoint address and max packet length // - QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->bEndpointAddress & 0x0F; - QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->wMaxPacketSize; + QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0x0F; + QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize; } // - // setup descriptors + // init setup descriptor // - m_TransferDescriptors[0]->Token.Bits.PIDCode = PID_CODE_SETUP_TOKEN; - m_TransferDescriptors[0]->Token.Bits.TotalBytesToTransfer = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET); - m_TransferDescriptors[0]->Token.Bits.DataToggle = FALSE; - m_TransferDescriptors[0]->BufferPointer[0] = (ULONG)PtrToUlong(m_DescriptorSetupPacket.LowPart); - m_TransferDescriptors[0]->NextPointer = m_TransferDescriptors[1]->PhysicalAddr; - m_TransferDescriptors[0]->AlternateNextPointer = m_TransferDescriptors[1]->PhysicalAddr; + SetupDescriptor->Token.Bits.PIDCode = PID_CODE_SETUP_TOKEN; + SetupDescriptor->Token.Bits.TotalBytesToTransfer = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET); + SetupDescriptor->Token.Bits.DataToggle = FALSE; + SetupDescriptor->BufferPointer[0] = (ULONG)PtrToUlong(m_DescriptorSetupPacket.LowPart); + InsertTailList(&QueueHead->TransferDescriptorListHead, &SetupDescriptor->DescriptorEntry); - if (m_TransferBufferMDL) + + // + // init status descriptor + // + StatusDescriptor->Token.Bits.TotalBytesToTransfer = 0; + StatusDescriptor->Token.Bits.DataToggle = TRUE; + StatusDescriptor->Token.Bits.InterruptOnComplete = TRUE; + + // + // is there data + // + if (m_TransferBufferLength) { - // - // setup in descriptor - // - m_TransferDescriptors[1]->Token.Bits.PIDCode = PID_CODE_IN_TOKEN; - m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer = m_TransferBufferLength; - m_TransferDescriptors[1]->NextPointer = m_TransferDescriptors[2]->PhysicalAddr; - m_TransferDescriptors[1]->Token.Bits.DataToggle = TRUE; - m_TransferDescriptors[1]->AlternateNextPointer = m_TransferDescriptors[2]->PhysicalAddr; + Status = BuildTransferDescriptorChain(QueueHead, + MmGetMdlVirtualAddress(m_TransferBufferMDL), + m_TransferBufferLength, + InternalGetPidDirection(), + TRUE, + &FirstDescriptor, + &LastDescriptor, + NULL, + &DescriptorChainLength); // - // FIXME: check if the request spawns over a page -> fill other members + // FIXME handle errors // - PC_ASSERT(m_TransferBufferLength <= PAGE_SIZE); - m_TransferDescriptors[1]->BufferPointer[0] = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart; + ASSERT(Status == STATUS_SUCCESS); + ASSERT(DescriptorChainLength == m_TransferBufferLength); // - // setup out descriptor + // now link the descriptors // - m_TransferDescriptors[2]->Token.Bits.PIDCode = PID_CODE_OUT_TOKEN; - m_TransferDescriptors[2]->Token.Bits.TotalBytesToTransfer = 0; - m_TransferDescriptors[2]->Token.Bits.DataToggle = TRUE; + SetupDescriptor->NextPointer = FirstDescriptor->PhysicalAddr; + SetupDescriptor->AlternateNextPointer = FirstDescriptor->PhysicalAddr; + LastDescriptor->NextPointer = StatusDescriptor->PhysicalAddr; + LastDescriptor->AlternateNextPointer = StatusDescriptor->PhysicalAddr; + // - // special case, setup alternative next descriptor in case of error - // HAIKU links to dead descriptor + // pid code is flipped for ops with data stage // - - // - // interrupt on completion - // - m_TransferDescriptors[2]->Token.Bits.InterruptOnComplete = TRUE; + StatusDescriptor->Token.Bits.PIDCode = !InternalGetPidDirection(); } else { // - // no buffer, setup in descriptor + // direct link // - m_TransferDescriptors[1]->Token.Bits.PIDCode = PID_CODE_IN_TOKEN; - m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer = 0; - m_TransferDescriptors[1]->Token.Bits.DataToggle = TRUE; + SetupDescriptor->NextPointer = StatusDescriptor->PhysicalAddr; + SetupDescriptor->AlternateNextPointer = StatusDescriptor->PhysicalAddr; // - // interrupt on completion + // retrieve result of operation // - m_TransferDescriptors[1]->Token.Bits.InterruptOnComplete = TRUE; + StatusDescriptor->Token.Bits.PIDCode = PID_CODE_IN_TOKEN; } + // + // insert status descriptor + // + InsertTailList(&QueueHead->TransferDescriptorListHead, &StatusDescriptor->DescriptorEntry); + + // // link transfer descriptors to queue head // - QueueHead->NextPointer = m_TransferDescriptors[0]->PhysicalAddr; - - DPRINT("QueueHead %p Addr %x\n", QueueHead, QueueHead->PhysicalAddr); - DPRINT("NumDescriptors %lu\n", NumTransferDescriptors); - DPRINT("QueueHead AlternateNextPointer %x\n", QueueHead->AlternateNextPointer); - DPRINT("QueueHead NextPointer %x\n", QueueHead->NextPointer); - DPRINT("m_DescriptorSetupPacket HiPart %x LoPart %x\n", m_DescriptorSetupPacket.HighPart, m_DescriptorSetupPacket.LowPart); - - - DPRINT("TransferDescriptor 0 Addr %x\n", m_TransferDescriptors[0]->PhysicalAddr); - DPRINT("TransferDescriptor 0 Next %x\n", m_TransferDescriptors[0]->NextPointer); - DPRINT("TransferDescriptor 0 AlternativeNext %x\n", m_TransferDescriptors[0]->AlternateNextPointer); - DPRINT("TransferDescriptor 0 Buffer Pointer %x\n", m_TransferDescriptors[0]->BufferPointer[0]); - DPRINT("TransferDescriptor 0 TotalBytesToTransfer 0x%x\n", m_TransferDescriptors[0]->Token.Bits.TotalBytesToTransfer); - - DPRINT("TransferDescriptor 1 Addr %x\n", m_TransferDescriptors[1]->PhysicalAddr); - DPRINT("TransferDescriptor 1 Next %x\n", m_TransferDescriptors[1]->NextPointer); - DPRINT("TransferDescriptor 1 AlternativeNext %x\n", m_TransferDescriptors[1]->AlternateNextPointer); - DPRINT("TransferDescriptor 1 Buffer Pointer %x\n", m_TransferDescriptors[1]->BufferPointer[0]); - DPRINT("TransferDescriptor 1 TotalBytesToTransfer 0x%x\n", m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer); - - if (NumTransferDescriptors == 3) - { - DPRINT("TransferDescriptor 2 Addr %x\n", m_TransferDescriptors[2]->PhysicalAddr); - DPRINT("TransferDescriptor 2 Next %x\n", m_TransferDescriptors[2]->NextPointer); - DPRINT("TransferDescriptor 2 AlternativeNext %x\n", m_TransferDescriptors[2]->AlternateNextPointer); - DPRINT("TransferDescriptor 2 Buffer Pointer %x\n", m_TransferDescriptors[2]->BufferPointer[0]); - DPRINT("TransferDescriptor 2 TotalBytesToTransfer 0x%x\n", m_TransferDescriptors[2]->Token.Bits.TotalBytesToTransfer); - } - + QueueHead->NextPointer = SetupDescriptor->PhysicalAddr; // // store result // *OutHead = QueueHead; + // + // displays the current request + // + //DumpQueueHead(QueueHead); + + DPRINT1("BuildControlTransferQueueHead done\n"); // // done // return STATUS_SUCCESS; } +VOID +CUSBRequest::DumpQueueHead( + IN PQUEUE_HEAD QueueHead) +{ + PLIST_ENTRY Entry; + PQUEUE_TRANSFER_DESCRIPTOR Descriptor; + ULONG Index = 0; + + DPRINT1("QueueHead %p Addr %x\n", QueueHead, QueueHead->PhysicalAddr); + DPRINT1("QueueHead AlternateNextPointer %x\n", QueueHead->AlternateNextPointer); + DPRINT1("QueueHead NextPointer %x\n", QueueHead->NextPointer); + + DPRINT1("QueueHead HubAddr %x\n", QueueHead->EndPointCharacteristics.ControlEndPointFlag); + DPRINT1("QueueHead DeviceAddress %x\n", QueueHead->EndPointCharacteristics.DeviceAddress); + DPRINT1("QueueHead EndPointNumber %x\n", QueueHead->EndPointCharacteristics.EndPointNumber); + DPRINT1("QueueHead EndPointSpeed %x\n", QueueHead->EndPointCharacteristics.EndPointSpeed); + DPRINT1("QueueHead HeadOfReclamation %x\n", QueueHead->EndPointCharacteristics.HeadOfReclamation); + DPRINT1("QueueHead InactiveOnNextTransaction %x\n", QueueHead->EndPointCharacteristics.InactiveOnNextTransaction); + DPRINT1("QueueHead MaximumPacketLength %x\n", QueueHead->EndPointCharacteristics.MaximumPacketLength); + DPRINT1("QueueHead NakCountReload %x\n", QueueHead->EndPointCharacteristics.NakCountReload); + DPRINT1("QueueHead QEDTDataToggleControl %x\n", QueueHead->EndPointCharacteristics.QEDTDataToggleControl); + DPRINT1("QueueHead HubAddr %x\n", QueueHead->EndPointCapabilities.HubAddr); + DPRINT1("QueueHead InterruptScheduleMask %x\n", QueueHead->EndPointCapabilities.InterruptScheduleMask); + DPRINT1("QueueHead NumberOfTransactionPerFrame %x\n", QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame); + DPRINT1("QueueHead PortNumber %x\n", QueueHead->EndPointCapabilities.PortNumber); + DPRINT1("QueueHead SplitCompletionMask %x\n", QueueHead->EndPointCapabilities.SplitCompletionMask); + + Entry = QueueHead->TransferDescriptorListHead.Flink; + while(Entry != &QueueHead->TransferDescriptorListHead) + { + // + // get transfer descriptor + // + Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)CONTAINING_RECORD(Entry, QUEUE_TRANSFER_DESCRIPTOR, DescriptorEntry); + + DPRINT1("TransferDescriptor %lu Addr %x\n", Index, Descriptor->PhysicalAddr); + DPRINT1("TransferDescriptor %lu Next %x\n", Index, Descriptor->NextPointer); + DPRINT1("TransferDescriptor %lu AlternateNextPointer %x\n", Index, Descriptor->AlternateNextPointer); + DPRINT1("TransferDescriptor %lu Active %lu\n", Index, Descriptor->Token.Bits.Active); + DPRINT1("TransferDescriptor %lu BabbleDetected %lu\n", Index, Descriptor->Token.Bits.BabbleDetected); + DPRINT1("TransferDescriptor %lu CurrentPage %lu\n", Index, Descriptor->Token.Bits.CurrentPage); + DPRINT1("TransferDescriptor %lu DataBufferError %lu\n", Index, Descriptor->Token.Bits.DataBufferError); + DPRINT1("TransferDescriptor %lu DataToggle %lu\n", Index, Descriptor->Token.Bits.DataToggle); + DPRINT1("TransferDescriptor %lu ErrorCounter %lu\n", Index, Descriptor->Token.Bits.ErrorCounter); + DPRINT1("TransferDescriptor %lu Halted %lu\n", Index, Descriptor->Token.Bits.Halted); + DPRINT1("TransferDescriptor %lu InterruptOnComplete %x\n", Index, Descriptor->Token.Bits.InterruptOnComplete); + DPRINT1("TransferDescriptor %lu MissedMicroFrame %lu\n", Index, Descriptor->Token.Bits.MissedMicroFrame); + DPRINT1("TransferDescriptor %lu PIDCode %lu\n", Index, Descriptor->Token.Bits.PIDCode); + DPRINT1("TransferDescriptor %lu PingState %lu\n", Index, Descriptor->Token.Bits.PingState); + DPRINT1("TransferDescriptor %lu SplitTransactionState %lu\n", Index, Descriptor->Token.Bits.SplitTransactionState); + DPRINT1("TransferDescriptor %lu TotalBytesToTransfer %lu\n", Index, Descriptor->Token.Bits.TotalBytesToTransfer); + DPRINT1("TransferDescriptor %lu TransactionError %lu\n", Index, Descriptor->Token.Bits.TransactionError); + + DPRINT1("TransferDescriptor %lu Buffer Pointer 0 %x\n", Index, Descriptor->BufferPointer[0]); + DPRINT1("TransferDescriptor %lu Buffer Pointer 1 %x\n", Index, Descriptor->BufferPointer[1]); + DPRINT1("TransferDescriptor %lu Buffer Pointer 2 %x\n", Index, Descriptor->BufferPointer[2]); + DPRINT1("TransferDescriptor %lu Buffer Pointer 3 %x\n", Index, Descriptor->BufferPointer[3]); + DPRINT1("TransferDescriptor %lu Buffer Pointer 4 %x\n", Index, Descriptor->BufferPointer[4]); + Entry = Entry->Flink; + Index++; + } +} + + //---------------------------------------------------------------------------------------- NTSTATUS CUSBRequest::BuildBulkTransferQueueHead( @@ -801,11 +1092,9 @@ CUSBRequest::BuildBulkTransferQueueHead( { NTSTATUS Status; PQUEUE_HEAD QueueHead; - ULONG TransferDescriptorCount, Index; - ULONG BytesAvailable, BufferIndex; PVOID Base; - ULONG PageOffset, CurrentTransferBufferLength; - UCHAR DataToggle; + ULONG ChainDescriptorLength; + PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor, LastDescriptor; // // Allocate the queue head @@ -826,280 +1115,82 @@ CUSBRequest::BuildBulkTransferQueueHead( PC_ASSERT(QueueHead); PC_ASSERT(m_TransferBufferLength); - // - // Max default of 3 descriptors - // - TransferDescriptorCount = 3; - - // - // get virtual base of mdl - // - Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority); + if (!m_Base) + { + // + // get virtual base of mdl + // + m_Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority); + } // // Increase the size of last transfer, 0 in case this is the first // - Base = (PVOID)((ULONG_PTR)Base + m_TransferBufferLengthCompleted); + Base = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted); PC_ASSERT(m_EndpointDescriptor); PC_ASSERT(Base); // - // Get the offset from page size + // sanity check // - PageOffset = BYTE_OFFSET(Base); + ASSERT(m_EndpointDescriptor); // - // PageOffset should only be > 0 if this is the first transfer for this requests + // build bulk transfer descriptor chain // - if ((PageOffset != 0) && (m_TransferBufferLengthCompleted != 0)) - { - ASSERT(FALSE); - } + Status = BuildTransferDescriptorChain(QueueHead, + Base, + m_TransferBufferLength - m_TransferBufferLengthCompleted, + InternalGetPidDirection(), + m_EndpointDescriptor->DataToggle, + &FirstDescriptor, + &LastDescriptor, + &m_EndpointDescriptor->DataToggle, + &ChainDescriptorLength); // - // Calculate the size of this transfer + // FIXME: handle errors // - 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); + ASSERT(ChainDescriptorLength == m_TransferBufferLength); // - // Add current transfer length to transfer length completed + // move to next offset // - m_TransferBufferLengthCompleted += CurrentTransferBufferLength; - BytesAvailable = CurrentTransferBufferLength; + m_TransferBufferLengthCompleted += ChainDescriptorLength; - DPRINT1("BuildBulkTransferQueueHead\n"); - DPRINT("CurrentTransferBufferLength %x, m_TransferBufferLengthCompleted %x\n", CurrentTransferBufferLength, m_TransferBufferLengthCompleted); - - DPRINT("EndPointAddress %x\n", m_EndpointDescriptor->bEndpointAddress); - DPRINT("EndPointDirection %x\n", USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress)); - - DPRINT("Request %p Base Address %p TransferBytesLength %lu MDL %p\n", this, Base, BytesAvailable, m_TransferBufferMDL); - DPRINT("InternalGetPidDirection() %d EndPointAddress %x\n", InternalGetPidDirection(), m_EndpointDescriptor->bEndpointAddress & 0x0F); - DPRINT("Irp %p QueueHead %p\n", m_Irp, QueueHead); - - //PC_ASSERT(InternalGetPidDirection() == USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress)); + ASSERT(Status == STATUS_SUCCESS); // - // DataToggle - // - DataToggle = FALSE; - - // - // Allocated transfer descriptors - // - for (Index = 0; Index < TransferDescriptorCount; Index++) - { - Status = CreateDescriptor(&m_TransferDescriptors[Index]); - if (!NT_SUCCESS(Status)) - { - // - // Failed to allocate transfer descriptors - // - - // - // Free QueueHead - // - FreeQueueHead(QueueHead); - - // - // Free Descriptors - // FIXME: Implement FreeDescriptors - // - return Status; - } - - // - // sanity check - // - PC_ASSERT(BytesAvailable); - - // - // now setup transfer buffers - // - for(BufferIndex = 0; BufferIndex < 5; BufferIndex++) - { - // - // If this is the first buffer of the first descriptor and there is a PageOffset - // - if ((BufferIndex == 0) && (PageOffset != 0) && (Index == 0)) - { - // - // use physical address - // - m_TransferDescriptors[Index]->BufferPointer[0] = MmGetPhysicalAddress(Base).LowPart; - - // - // move to next page - // - Base = (PVOID)ROUND_TO_PAGES(Base); - - // - // increment transfer bytes - // - if (CurrentTransferBufferLength > PAGE_SIZE - PageOffset) - m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = PAGE_SIZE - PageOffset; - else - m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer = CurrentTransferBufferLength; - - // - // decrement available byte count - // - BytesAvailable -= m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer; - - DPRINT1("TransferDescriptor %p Index %lu BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], Index, m_TransferDescriptors[Index]->BufferPointer[BufferIndex], - BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable); - } - else - { - // - // the following pages always start on byte zero of each page - // - PC_ASSERT(((ULONG_PTR)Base & (PAGE_SIZE-1)) == 0); - - if (BytesAvailable >= PAGE_SIZE) - { - // - // store address - // - m_TransferDescriptors[Index]->BufferPointer[BufferIndex] = MmGetPhysicalAddress(Base).LowPart; - - // - // move to next page - // - Base = (PVOID)((ULONG_PTR)Base + PAGE_SIZE); - - // - // increment transfer descriptor bytes - // - m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer += PAGE_SIZE; - - // - // decrement available byte count - // - BytesAvailable -= PAGE_SIZE; - - DPRINT1("TransferDescriptor %p Index %lu BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], Index, m_TransferDescriptors[Index]->BufferPointer[BufferIndex], - BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable); - } - else - { - PC_ASSERT(BytesAvailable); - - if (BytesAvailable) - { - // - // store address - // - m_TransferDescriptors[Index]->BufferPointer[BufferIndex] = MmGetPhysicalAddress(Base).LowPart; - - // - // increment transfer descriptor bytes - // - m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer += BytesAvailable; - - // - // decrement available byte count - // - BytesAvailable -= BytesAvailable; - - // - // done as this is the last partial or full page - // - } - DPRINT1("TransferDescriptor %p Index %lu BufferPointer %p BufferIndex %lu TotalBytes %lu Remaining %lu\n", m_TransferDescriptors[Index], Index, m_TransferDescriptors[Index]->BufferPointer[BufferIndex], - BufferIndex, m_TransferDescriptors[Index]->Token.Bits.TotalBytesToTransfer, BytesAvailable); - - break; - } - } - - // - // Check if all bytes have been consumed - // - if (BytesAvailable == 0) - break; - } - - // - // Go ahead and link descriptors - // - if (Index > 0) - { - m_TransferDescriptors[Index - 1]->NextPointer = m_TransferDescriptors[Index]->PhysicalAddr; - } - - - // - // status descriptor - // - m_TransferDescriptors[Index]->Token.Bits.InterruptOnComplete = TRUE; - - // - // FIXME: need status descriptor? - // - - // - // setup direction - // - m_TransferDescriptors[Index]->Token.Bits.PIDCode = InternalGetPidDirection(); - - // - // set data toggle - // - m_TransferDescriptors[Index]->Token.Bits.DataToggle = DataToggle; - DataToggle = !DataToggle; - - // - // Check if all bytes have been consumed - // - if (BytesAvailable == 0) - break; - } - - // - // all bytes should have been consumed - // - PC_ASSERT(BytesAvailable == 0); - - // - // Initialize the QueueHead + // init queue head // QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress(); + QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0x0F; + QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize; + QueueHead->NextPointer = FirstDescriptor->PhysicalAddr; + QueueHead->CurrentLinkPointer = FirstDescriptor->PhysicalAddr; + QueueHead->AlternateNextPointer = TERMINATE_POINTER; - if (m_EndpointDescriptor) - { - // - // Set endpoint address and max packet length - // - QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->bEndpointAddress & 0x0F; - QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->wMaxPacketSize; - } + ASSERT(QueueHead->EndPointCharacteristics.DeviceAddress); + ASSERT(QueueHead->EndPointCharacteristics.EndPointNumber); + ASSERT(QueueHead->EndPointCharacteristics.MaximumPacketLength); + ASSERT(QueueHead->NextPointer); // - // store number of transactions + // interrupt on last descriptor // - QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = min(Index, 1); - - // - // link descriptor with queue head - // - QueueHead->NextPointer = m_TransferDescriptors[0]->PhysicalAddr; + LastDescriptor->Token.Bits.InterruptOnComplete = TRUE; // // store result // *OutHead = QueueHead; + // + // dump status + // + //DumpQueueHead(QueueHead); + // // done // @@ -1176,6 +1267,7 @@ CUSBRequest::CreateQueueHead( QueueHead->HorizontalLinkPointer = TERMINATE_POINTER; QueueHead->AlternateNextPointer = TERMINATE_POINTER; QueueHead->NextPointer = TERMINATE_POINTER; + InitializeListHead(&QueueHead->TransferDescriptorListHead); // // 1 for non high speed, 0 for high speed device @@ -1536,61 +1628,42 @@ VOID CUSBRequest::FreeQueueHead( IN struct _QUEUE_HEAD * QueueHead) { - LONG DescriptorCount; + PLIST_ENTRY Entry; + PQUEUE_TRANSFER_DESCRIPTOR Descriptor; // - // FIXME: support chained queue heads + // sanity checks // - //PC_ASSERT(QueueHead == m_QueueHead); + ASSERT(m_DmaManager); + ASSERT(QueueHead); + ASSERT(!IsListEmpty(&QueueHead->TransferDescriptorListHead)); - // - // release queue head - // - m_DmaManager->Release(QueueHead, sizeof(QUEUE_HEAD)); - - // - // nullify pointer - // - m_QueueHead = 0; - - // - // release transfer descriptors - // - for (DescriptorCount = 0; DescriptorCount < 3; DescriptorCount++) + do { - if (m_TransferDescriptors[DescriptorCount]) - { - // - // Calculate Total Bytes Transferred - // FIXME: Is this the correct method of determine bytes transferred? - // - if (USB_ENDPOINT_TYPE_BULK == GetTransferType()) - { - // - // sanity check - // - ASSERT(m_EndpointDescriptor); + // + // get transfer descriptors + // + Entry = RemoveHeadList(&QueueHead->TransferDescriptorListHead); + ASSERT(Entry); - if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress)) - { - DPRINT("m_TotalBytesTransferred %x, %x - %x\n", - m_TotalBytesTransferred, - m_TransferDescriptors[DescriptorCount]->TotalBytesToTransfer, - m_TransferDescriptors[DescriptorCount]->Token.Bits.TotalBytesToTransfer); + // + // obtain descriptor from entry + // + Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)CONTAINING_RECORD(Entry, QUEUE_TRANSFER_DESCRIPTOR, DescriptorEntry); + ASSERT(Descriptor); - m_TotalBytesTransferred += - m_TransferDescriptors[DescriptorCount]->TotalBytesToTransfer - - m_TransferDescriptors[DescriptorCount]->Token.Bits.TotalBytesToTransfer; - } - } + // + // add transfer count + // + m_TotalBytesTransferred += (Descriptor->TotalBytesToTransfer - Descriptor->Token.Bits.TotalBytesToTransfer); + DPRINT("TotalBytes Transferred in Descriptor %p Phys Addr %x TotalBytesSoftware %lu Length %lu\n", Descriptor, Descriptor->PhysicalAddr, Descriptor->TotalBytesToTransfer, Descriptor->TotalBytesToTransfer - Descriptor->Token.Bits.TotalBytesToTransfer); - // - // release transfer descriptors - // - m_DmaManager->Release(m_TransferDescriptors[DescriptorCount], sizeof(QUEUE_TRANSFER_DESCRIPTOR)); - m_TransferDescriptors[DescriptorCount] = 0; - } - } + // + // release transfer descriptors + // + m_DmaManager->Release(Descriptor, sizeof(QUEUE_TRANSFER_DESCRIPTOR)); + + }while(!IsListEmpty(&QueueHead->TransferDescriptorListHead)); if (m_DescriptorPacket) { @@ -1598,8 +1671,18 @@ CUSBRequest::FreeQueueHead( // release packet descriptor // m_DmaManager->Release(m_DescriptorPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); - m_DescriptorPacket = 0; } + + // + // release queue head + // + m_DmaManager->Release(QueueHead, sizeof(QUEUE_HEAD)); + + // + // nullify pointers + // + m_QueueHead = 0; + m_DescriptorPacket = 0; } //----------------------------------------------------------------------------------------- @@ -1607,7 +1690,8 @@ BOOLEAN CUSBRequest::IsQueueHeadComplete( struct _QUEUE_HEAD * QueueHead) { - ULONG Index; + PLIST_ENTRY Entry; + PQUEUE_TRANSFER_DESCRIPTOR Descriptor; // // first check - is the queue head currently active @@ -1617,39 +1701,50 @@ CUSBRequest::IsQueueHeadComplete( // // queue head is active (currently processed) // - ASSERT(QueueHead->Token.Bits.Halted == FALSE); - //return FALSE; + return FALSE; } - // - // FIXME: support chained queue heads - // - for(Index = 0; Index < 3; Index++) + if (QueueHead->Token.Bits.Halted) { // - // check transfer descriptors for completion + // error occured // - if (m_TransferDescriptors[Index]) + DPRINT1("Found halted queue head %p\n", QueueHead); + DumpQueueHead(QueueHead); + ASSERT(FALSE); + return TRUE; + } + + // + // loop list and see if there are any active descriptors + // + Entry = QueueHead->TransferDescriptorListHead.Flink; + while(Entry != &QueueHead->TransferDescriptorListHead) + { + // + // obtain descriptor from entry + // + Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)CONTAINING_RECORD(Entry, QUEUE_TRANSFER_DESCRIPTOR, DescriptorEntry); + ASSERT(Descriptor); + if (Descriptor->Token.Bits.Active) { // - // check for serious error + // descriptor is still active // - DPRINT("Descriptor Addr %x\n", m_TransferDescriptors[Index]->PhysicalAddr); - DPRINT("Descriptor BabbleDetected %x\n", m_TransferDescriptors[Index]->Token.Bits.BabbleDetected); - DPRINT("Descriptor DataBufferError %x\n", m_TransferDescriptors[Index]->Token.Bits.DataBufferError); - DPRINT("Descriptor DataToggle %x\n", m_TransferDescriptors[Index]->Token.Bits.DataToggle); - DPRINT("Descriptor ErrorCounter %x\n", m_TransferDescriptors[Index]->Token.Bits.ErrorCounter); - DPRINT("Descriptor TransactionError %x\n", m_TransferDescriptors[Index]->Token.Bits.TransactionError); - - - // - // the transfer descriptor should be in the same state as the queue head - // - //PC_ASSERT(m_TransferDescriptors[Index]->Token.Bits.Active == 0); + return FALSE; } - } - //ASSERT(FALSE); + // + // move to next entry + // + Entry = Entry->Flink; + } + + DPRINT("QueueHead %p Addr %x is complete\n", QueueHead, QueueHead->PhysicalAddr); + + // + // no active descriptors found, queue head is finished + // return TRUE; } @@ -1682,8 +1777,7 @@ CUSBRequest::InternalCalculateTransferLength() // sanity check // ASSERT(m_EndpointDescriptor); - - if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->bEndpointAddress)) + if (USB_ENDPOINT_DIRECTION_IN(m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress)) { // // bulk in request diff --git a/drivers/usb/usbehci/usbehci.h b/drivers/usb/usbehci/usbehci.h index a4d18965d38..8b05ef37f19 100644 --- a/drivers/usb/usbehci/usbehci.h +++ b/drivers/usb/usbehci/usbehci.h @@ -39,6 +39,28 @@ #define C_PORT_OVER_CURRENT 19 #define C_PORT_RESET 20 +typedef struct _USB_ENDPOINT +{ + USB_ENDPOINT_DESCRIPTOR EndPointDescriptor; + UCHAR HubAddress; + UCHAR HubPort; + UCHAR DataToggle; +} USB_ENDPOINT, *PUSB_ENDPOINT; + +typedef struct _USB_INTERFACE +{ + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USB_ENDPOINT *EndPoints; +} USB_INTERFACE, *PUSB_INTERFACE; + +typedef struct _USB_CONFIGURATION +{ + USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + USB_INTERFACE *Interfaces; +} USB_CONFIGURATION, *PUSB_CONFIGURATION; + + + typedef struct { BOOLEAN IsFDO; // is device a FDO or PDO