From f75cb3d51dc10edc9ef1c66a9a33ceb917594831 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Mon, 23 May 2011 17:42:52 +0000 Subject: [PATCH] [USBOHCI] - Start implementing control transfers - Move initialization of usb queue after the bulk / control head endpoints have been created - Add interface functions to retrieve bulk / control head endpoint descriptors - Add macros for setting transfer descriptors field (taken from Haiku) - Partly implement IUSBQueue::AddUSBRequest for control / bulk transfers - Create endpoint descriptor for control request and link setup descriptor to it - Link setup descriptors to data descriptor / status descriptor - WIP (needs fixes) svn path=/branches/usb-bringup/; revision=51864 --- drivers/usb/usbohci/hardware.cpp | 64 ++++- drivers/usb/usbohci/hardware.h | 67 ++++- drivers/usb/usbohci/interfaces.h | 39 ++- drivers/usb/usbohci/usb_queue.cpp | 85 +++++- drivers/usb/usbohci/usb_request.cpp | 404 ++++++++++++++++++++++++++++ 5 files changed, 633 insertions(+), 26 deletions(-) diff --git a/drivers/usb/usbohci/hardware.cpp b/drivers/usb/usbohci/hardware.cpp index c162721165a..acfc5ad5177 100644 --- a/drivers/usb/usbohci/hardware.cpp +++ b/drivers/usb/usbohci/hardware.cpp @@ -59,6 +59,10 @@ public: NTSTATUS PnpStop(void); NTSTATUS HandlePower(PIRP Irp); NTSTATUS GetDeviceDetails(PUSHORT VendorId, PUSHORT DeviceId, PULONG NumberOfPorts, PULONG Speed); + NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor); + NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor); + VOID HeadEndpointDescriptorModified(ULONG HeadType); + NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager); NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue); @@ -359,16 +363,6 @@ CUSBHardwareDevice::PnpStart( return Status; } - // - // Initialize the UsbQueue now that we have an AdapterObject. - // - Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to Initialize the UsbQueue\n"); - return Status; - } - // // initializes the controller // @@ -380,6 +374,16 @@ CUSBHardwareDevice::PnpStart( return Status; } + // + // Initialize the UsbQueue now that we have an AdapterObject. + // + Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to Initialize the UsbQueue\n"); + return Status; + } + // // Stop the controller before modifying schedules @@ -631,6 +635,42 @@ CUSBHardwareDevice::AllocateEndpointDescriptor( return STATUS_SUCCESS; } +NTSTATUS +CUSBHardwareDevice::GetBulkHeadEndpointDescriptor( + struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) +{ + *OutDescriptor = m_BulkEndpointDescriptor; + return STATUS_SUCCESS; +} + +VOID +CUSBHardwareDevice::HeadEndpointDescriptorModified( + ULONG Type) +{ + if (Type == USB_ENDPOINT_TYPE_CONTROL) + { + // + // notify controller + // + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), OHCI_CONTROL_LIST_FILLED); + } + else if (Type == USB_ENDPOINT_TYPE_BULK) + { + // + // notify controller + // + WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), OHCI_BULK_LIST_FILLED); + } +} + +NTSTATUS +CUSBHardwareDevice::GetControlHeadEndpointDescriptor( + struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) +{ + *OutDescriptor = m_ControlEndpointDescriptor; + return STATUS_SUCCESS; +} + NTSTATUS CUSBHardwareDevice::InitializeController() { @@ -1128,7 +1168,7 @@ InterruptServiceRoutine( // head completed // DPRINT1("InterruptServiceRoutine> Done Head completion\n"); - + ASSERT(FALSE); // // FIXME: handle event // @@ -1148,9 +1188,11 @@ InterruptServiceRoutine( if (Status & OHCI_UNRECOVERABLE_ERROR) { DPRINT1("InterruptServiceRoutine> Controller error\n"); + // // halt controller // + ASSERT(FALSE); WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET); } diff --git a/drivers/usb/usbohci/hardware.h b/drivers/usb/usbohci/hardware.h index e569b8f8ee0..4391d6b0b98 100644 --- a/drivers/usb/usbohci/hardware.h +++ b/drivers/usb/usbohci/hardware.h @@ -192,7 +192,7 @@ typedef struct #define OHCI_PAGE_OFFSET(x) ((x) & 0xfff) -typedef struct +typedef struct _OHCI_ENDPOINT_DESCRIPTOR { // Hardware part ULONG Flags; @@ -202,10 +202,19 @@ typedef struct // Software part PHYSICAL_ADDRESS PhysicalAddress; + PVOID Request; + PVOID NextDescriptor; }OHCI_ENDPOINT_DESCRIPTOR, *POHCI_ENDPOINT_DESCRIPTOR; #define OHCI_ENDPOINT_SKIP 0x00004000 +#define OHCI_ENDPOINT_SET_DEVICE_ADDRESS(s) (s) +#define OHCI_ENDPOINT_GET_ENDPOINT_NUMBER(s) (((s) >> 7) & 0xf) +#define OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(s) ((s) << 7) +#define OHCI_ENDPOINT_GET_MAX_PACKET_SIZE(s) (((s) >> 16) & 0x07ff) +#define OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(s) ((s) << 16) +#define OHCI_ENDPOINT_LOW_SPEED 0x00002000 +#define OHCI_ENDPOINT_FULL_SPEED 0x00000000 // // Maximum port count set by OHCI @@ -220,15 +229,51 @@ typedef struct }OHCI_PORT_STATUS; -typedef struct { +typedef struct +{ // Hardware part 16 bytes - uint32 flags; // Flags field - uint32 buffer_physical; // Physical buffer pointer - uint32 next_physical_descriptor; // Physical pointer next descriptor - uint32 last_physical_byte_address; // Physical pointer to buffer end + ULONG Flags; // Flags field + ULONG BufferPhysical; // Physical buffer pointer + ULONG NextPhysicalDescriptor; // Physical pointer next descriptor + ULONG LastPhysicalByteAddress; // Physical pointer to buffer end // Software part - addr_t physical_address; // Physical address of this descriptor - size_t buffer_size; // Size of the buffer - void *buffer_logical; // Logical pointer to the buffer - void *next_logical_descriptor; // Logical pointer next descriptor -} ohci_general_td; \ No newline at end of file + PHYSICAL_ADDRESS PhysicalAddress; // Physical address of this descriptor + ULONG BufferSize; // Size of the buffer + PVOID BufferLogical; // Logical pointer to the buffer + PVOID Request; // pointer to IUSBRequest +}OHCI_GENERAL_TD, *POHCI_GENERAL_TD; + + +#define OHCI_TD_BUFFER_ROUNDING 0x00040000 +#define OHCI_TD_DIRECTION_PID_MASK 0x00180000 +#define OHCI_TD_DIRECTION_PID_SETUP 0x00000000 +#define OHCI_TD_DIRECTION_PID_OUT 0x00080000 +#define OHCI_TD_DIRECTION_PID_IN 0x00100000 +#define OHCI_TD_GET_DELAY_INTERRUPT(x) (((x) >> 21) & 7) +#define OHCI_TD_SET_DELAY_INTERRUPT(x) ((x) << 21) +#define OHCI_TD_INTERRUPT_MASK 0x00e00000 +#define OHCI_TD_TOGGLE_CARRY 0x00000000 +#define OHCI_TD_TOGGLE_0 0x02000000 +#define OHCI_TD_TOGGLE_1 0x03000000 +#define OHCI_TD_TOGGLE_MASK 0x03000000 +#define OHCI_TD_GET_ERROR_COUNT(x) (((x) >> 26) & 3) +#define OHCI_TD_GET_CONDITION_CODE(x) ((x) >> 28) +#define OHCI_TD_SET_CONDITION_CODE(x) ((x) << 28) +#define OHCI_TD_CONDITION_CODE_MASK 0xf0000000 + +#define OHCI_TD_INTERRUPT_IMMEDIATE 0x00 +#define OHCI_TD_INTERRUPT_NONE 0x07 + +#define OHCI_TD_CONDITION_NO_ERROR 0x00 +#define OHCI_TD_CONDITION_CRC_ERROR 0x01 +#define OHCI_TD_CONDITION_BIT_STUFFING 0x02 +#define OHCI_TD_CONDITION_TOGGLE_MISMATCH 0x03 +#define OHCI_TD_CONDITION_STALL 0x04 +#define OHCI_TD_CONDITION_NO_RESPONSE 0x05 +#define OHCI_TD_CONDITION_PID_CHECK_FAILURE 0x06 +#define OHCI_TD_CONDITION_UNEXPECTED_PID 0x07 +#define OHCI_TD_CONDITION_DATA_OVERRUN 0x08 +#define OHCI_TD_CONDITION_DATA_UNDERRUN 0x09 +#define OHCI_TD_CONDITION_BUFFER_OVERRUN 0x0c +#define OHCI_TD_CONDITION_BUFFER_UNDERRUN 0x0d +#define OHCI_TD_CONDITION_NOT_ACCESSED 0x0f diff --git a/drivers/usb/usbohci/interfaces.h b/drivers/usb/usbohci/interfaces.h index ac781d949d9..a22a9bd143a 100644 --- a/drivers/usb/usbohci/interfaces.h +++ b/drivers/usb/usbohci/interfaces.h @@ -107,7 +107,7 @@ DECLARE_INTERFACE_(IHCDController, IUnknown) typedef IHCDController *PHCDCONTROLLER; - +struct _OHCI_ENDPOINT_DESCRIPTOR; //========================================================================================= // // class IUSBHardwareDevice @@ -172,6 +172,33 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown) virtual NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue) = 0; +//----------------------------------------------------------------------------------------- +// +// GetBulkHeadEndpointDescriptor +// +// Description: returns the bulk head endpoint descriptor + + virtual NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0; + +//----------------------------------------------------------------------------------------- +// +// GetControlHeadEndpointDescriptor +// +// Description: returns the control head endpoint descriptor + + virtual NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0; + +//----------------------------------------------------------------------------------------- +// +// HeadEndpointDescriptorModified +// +// Description: notifies the hardware that an endpoint descriptor was added to head endpoint descriptor + + virtual VOID HeadEndpointDescriptorModified(ULONG HeadType) = 0; + + + + //----------------------------------------------------------------------------------------- // // GetDMA @@ -334,8 +361,6 @@ typedef IDMAMemoryManager *PDMAMEMORYMANAGER; // CancelCallback routine is invoked. // -struct _QUEUE_HEAD; - DECLARE_INTERFACE_(IUSBRequest, IUnknown) { DEFINE_ABSTRACT_UNKNOWN() @@ -385,6 +410,14 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) virtual ULONG GetTransferType() = 0; +//----------------------------------------------------------------------------------------- +// +// GetEndpointDescriptor +// +// Description: returns the general transfer descriptor + + virtual NTSTATUS GetEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0; + //----------------------------------------------------------------------------------------- // // GetResultStatus diff --git a/drivers/usb/usbohci/usb_queue.cpp b/drivers/usb/usbohci/usb_queue.cpp index 9509a34bbb9..d5f0d5f0e74 100644 --- a/drivers/usb/usbohci/usb_queue.cpp +++ b/drivers/usb/usbohci/usb_queue.cpp @@ -46,6 +46,9 @@ public: protected: LONG m_Ref; // reference count KSPIN_LOCK m_Lock; // list lock + PUSBHARDWAREDEVICE m_Hardware; // hardware + POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor + POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor }; //================================================================================================= @@ -74,7 +77,26 @@ CUSBQueue::Initialize( IN PDMAMEMORYMANAGER MemManager, IN OPTIONAL PKSPIN_LOCK Lock) { - UNIMPLEMENTED + // + // get bulk endpoint descriptor + // + Hardware->GetBulkHeadEndpointDescriptor(&m_BulkHeadEndpointDescriptor); + + // + // get control endpoint descriptor + // + Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor); + + // + // initialize spinlock + // + KeInitializeSpinLock(&m_Lock); + + // + // store hardware + // + m_Hardware = Hardware; + return STATUS_SUCCESS; } @@ -96,6 +118,10 @@ CUSBQueue::AddUSBRequest( NTSTATUS Status; ULONG Type; KIRQL OldLevel; + POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor; + POHCI_ENDPOINT_DESCRIPTOR Descriptor; + + DPRINT1("CUSBQueue::AddUSBRequest\n"); // // sanity check @@ -143,6 +169,63 @@ CUSBQueue::AddUSBRequest( // Request->AddRef(); + // + // get transfer descriptors + // + Status = Request->GetEndpointDescriptor(&Descriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to get transfer descriptor + // + DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status); + + // + // release reference + // + Request->Release(); + return Status; + } + + // + // check type + // + if (Type == USB_ENDPOINT_TYPE_BULK) + { + // + // get head descriptor + // + HeadDescriptor = m_BulkHeadEndpointDescriptor; + } + else if (Type == USB_ENDPOINT_TYPE_CONTROL) + { + // + // get head descriptor + // + HeadDescriptor = m_ControlHeadEndpointDescriptor; + } + + // + // link endpoints + // + Descriptor->NextPhysicalEndpoint = HeadDescriptor->NextPhysicalEndpoint; + Descriptor->NextDescriptor = HeadDescriptor->NextDescriptor; + + HeadDescriptor->NextPhysicalEndpoint = Descriptor->PhysicalAddress.LowPart; + HeadDescriptor->NextDescriptor = Descriptor; + + // + // set descriptor active + // + Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP; + + // + // notify hardware of our request + // + m_Hardware->HeadEndpointDescriptorModified(Type); + + DPRINT1("Request added to queue\n"); + return STATUS_SUCCESS; } diff --git a/drivers/usb/usbohci/usb_request.cpp b/drivers/usb/usbohci/usb_request.cpp index 5ede8db513c..42b04789c74 100644 --- a/drivers/usb/usbohci/usb_request.cpp +++ b/drivers/usb/usbohci/usb_request.cpp @@ -40,6 +40,7 @@ public: virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp); virtual BOOLEAN IsRequestComplete(); virtual ULONG GetTransferType(); + virtual NTSTATUS GetEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutEndpointDescriptor); virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode); virtual BOOLEAN IsRequestInitialized(); virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead); @@ -51,6 +52,12 @@ public: UCHAR GetDeviceAddress(); NTSTATUS BuildSetupPacket(); NTSTATUS BuildSetupPacketFromURB(); + NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); + NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize); + VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor); + NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor); + UCHAR GetEndpointAddress(); + USHORT GetMaxPacketSize(); // constructor / destructor CUSBRequest(IUnknown *OuterUnknown){} @@ -348,6 +355,46 @@ CUSBRequest::GetTransferType() return InternalGetTransferType(); } +USHORT +CUSBRequest::GetMaxPacketSize() +{ + if (!m_EndpointDescriptor) + { + // + // control request + // + return 0; + } + + ASSERT(m_Irp); + ASSERT(m_EndpointDescriptor); + + // + // return max packet size + // + return m_EndpointDescriptor->wMaxPacketSize; +} + +UCHAR +CUSBRequest::GetEndpointAddress() +{ + if (!m_EndpointDescriptor) + { + // + // control request + // + return 0; + } + + ASSERT(m_Irp); + ASSERT(m_EndpointDescriptor); + + // + // endpoint number is between 1-15 + // + return (m_EndpointDescriptor->bEndpointAddress & 0xF); +} + //---------------------------------------------------------------------------------------- ULONG CUSBRequest::InternalGetTransferType() @@ -444,9 +491,366 @@ CUSBRequest::GetDeviceAddress() return 0; } +VOID +CUSBRequest::FreeDescriptor( + POHCI_GENERAL_TD Descriptor) +{ + if (Descriptor->BufferSize) + { + // + // free buffer + // + m_DmaManager->Release(Descriptor->BufferLogical, Descriptor->BufferSize); + } + // + // release descriptor + // + m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD)); +} +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBRequest::CreateGeneralTransferDescriptor( + POHCI_GENERAL_TD* OutDescriptor, + ULONG BufferSize) +{ + POHCI_GENERAL_TD Descriptor; + PHYSICAL_ADDRESS DescriptorAddress; + NTSTATUS Status; + // + // allocate transfer descriptor + // + Status = m_DmaManager->Allocate(sizeof(OHCI_GENERAL_TD), (PVOID*)&Descriptor, &DescriptorAddress); + if (!NT_SUCCESS(Status)) + { + // + // no memory + // + return Status; + } + + // + // initialize descriptor, hardware part + // + Descriptor->Flags = 0; + Descriptor->BufferPhysical = 0; + Descriptor->NextPhysicalDescriptor = 0; + Descriptor->LastPhysicalByteAddress = 0; + + // + // software part + // + Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart; + Descriptor->BufferSize = BufferSize; + + if (BufferSize > 0) + { + // + // allocate buffer from dma + // + Status = m_DmaManager->Allocate(BufferSize, &Descriptor->BufferLogical, &DescriptorAddress); + if (!NT_SUCCESS(Status)) + { + // + // no memory + // + m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD)); + return Status; + } + + // + // set physical address of buffer + // + Descriptor->BufferPhysical = DescriptorAddress.LowPart; + Descriptor->LastPhysicalByteAddress = Descriptor->BufferPhysical + BufferSize - 1; + } + + // + // store result + // + *OutDescriptor = Descriptor; + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +CUSBRequest::AllocateEndpointDescriptor( + OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor) +{ + POHCI_ENDPOINT_DESCRIPTOR Descriptor; + PHYSICAL_ADDRESS DescriptorAddress; + NTSTATUS Status; + + // + // allocate descriptor + // + Status = m_DmaManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR), (PVOID*)&Descriptor, &DescriptorAddress); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate descriptor + // + return Status; + } + + // + // intialize descriptor + // + Descriptor->Flags = OHCI_ENDPOINT_SKIP; + + // + // append device address and endpoint number + // + Descriptor->Flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(m_DeviceAddress); + Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress()); + Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize()); + + // + // FIXME: detect type + // + Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED; + + Descriptor->HeadPhysicalDescriptor = 0; + Descriptor->NextPhysicalEndpoint = 0; + Descriptor->TailPhysicalDescriptor = 0; + Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart; + + // + // store result + // + *OutDescriptor = Descriptor; + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +CUSBRequest::BuildControlTransferDescriptor( + POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor) +{ + POHCI_GENERAL_TD SetupDescriptor, StatusDescriptor, DataDescriptor = NULL; + POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor; + NTSTATUS Status; + + DPRINT1("CUSBRequest::BuildControlTransferDescriptor\n"); + + // + // allocate endpoint descriptor + // + Status = AllocateEndpointDescriptor(&EndpointDescriptor); + if (!NT_SUCCESS(Status)) + { + // + // failed to create setup descriptor + // + return Status; + } + + // + // first allocate setup descriptor + // + Status = CreateGeneralTransferDescriptor(&SetupDescriptor, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + if (!NT_SUCCESS(Status)) + { + // + // failed to create setup descriptor + // + m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); + return Status; + } + + // + // now create the status descriptor + // + Status = CreateGeneralTransferDescriptor(&StatusDescriptor, 0); + if (!NT_SUCCESS(Status)) + { + // + // failed to create status descriptor + // + FreeDescriptor(SetupDescriptor); + m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); + return Status; + } + + if (m_TransferBufferLength) + { + // + // FIXME: support more than one data descriptor + // + ASSERT(m_TransferBufferLength < 8192); + + // + // now create the data descriptor + // + Status = CreateGeneralTransferDescriptor(&DataDescriptor, 0); + if (!NT_SUCCESS(Status)) + { + // + // failed to create status descriptor + // + m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); + FreeDescriptor(SetupDescriptor); + FreeDescriptor(StatusDescriptor); + return Status; + } + + // + // initialize data descriptor + // + DataDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY | OHCI_TD_DIRECTION_PID_IN; + + // + // store physical address of buffer + // + DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart; + DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1; + } + + // + // initialize setup descriptor + // + SetupDescriptor->Flags = OHCI_TD_DIRECTION_PID_SETUP | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_0 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE); + + if (m_SetupPacket) + { + // + // copy setup packet + // + RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + } + else + { + // + // generate setup packet from urb + // + ASSERT(FALSE); + } + + // + // initialize status descriptor + // + StatusDescriptor->Flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE); + if (m_TransferBufferLength == 0) + { + // + // input direction is flipped for the status descriptor + // + StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN; + } + else + { + // + // output direction is flipped for the status descriptor + // + StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_OUT; + } + + // + // now link the descriptors + // + if (m_TransferBufferLength) + { + // + // link setup descriptor to data descriptor + // + SetupDescriptor->NextPhysicalDescriptor = DataDescriptor->PhysicalAddress.LowPart; + + // + // FIXME: should link to last data descriptor to status descriptor + // + DataDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart; + } + else + { + // + // link setup descriptor to status descriptor + // + SetupDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart; + } + + // + // now link descriptor to endpoint + // + EndpointDescriptor->HeadPhysicalDescriptor = SetupDescriptor->PhysicalAddress.LowPart; + EndpointDescriptor->TailPhysicalDescriptor = SetupDescriptor->PhysicalAddress.LowPart; + DPRINT1("CUSBRequest::BuildControlTransferDescriptor done\n"); + + // + // store result + // + *OutEndpointDescriptor = EndpointDescriptor; + + // + // done + // + return STATUS_SUCCESS; +} + +//---------------------------------------------------------------------------------------- +NTSTATUS +CUSBRequest::GetEndpointDescriptor( + struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) +{ + ULONG TransferType; + NTSTATUS Status; + + // + // get transfer type + // + TransferType = InternalGetTransferType(); + + // + // build request depending on type + // + switch(TransferType) + { + case USB_ENDPOINT_TYPE_CONTROL: + Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor); + break; + case USB_ENDPOINT_TYPE_BULK: + DPRINT1("USB_ENDPOINT_TYPE_BULK not implemented\n"); + Status = STATUS_NOT_IMPLEMENTED; //BuildBulkTransferQueueHead(OutDescriptor); + break; + case USB_ENDPOINT_TYPE_INTERRUPT: + DPRINT1("USB_ENDPOINT_TYPE_INTERRUPT not implemented\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + case USB_ENDPOINT_TYPE_ISOCHRONOUS: + DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + default: + PC_ASSERT(FALSE); + Status = STATUS_NOT_IMPLEMENTED; + break; + } + + if (NT_SUCCESS(Status)) + { + // + // store queue head + // + //m_QueueHead = *OutDescriptor; + + // + // store request object + // + (*OutDescriptor)->Request = PVOID(this); + } + + // + // done + // + return Status; +} //---------------------------------------------------------------------------------------- VOID