diff --git a/reactos/drivers/usb/usbuhci/hardware.cpp b/reactos/drivers/usb/usbuhci/hardware.cpp index d245483c6c1..8eb19a65a40 100644 --- a/reactos/drivers/usb/usbuhci/hardware.cpp +++ b/reactos/drivers/usb/usbuhci/hardware.cpp @@ -73,8 +73,9 @@ public: NTSTATUS GetPortStatus(ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange); NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status); NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature); - VOID SetStatusChangeEndpointCallBack(PVOID CallBack, PVOID Context); + VOID GetQueueHead(ULONG QueueHeadIndex, PUHCI_QUEUE_HEAD *OutQueueHead); + KIRQL AcquireDeviceLock(void); VOID ReleaseDeviceLock(KIRQL OldLevel); @@ -616,7 +617,7 @@ CUSBHardwareDevice::InitializeController() // // link queue heads // - m_QueueHead[Index-1]->LinkPhysical = m_QueueHead[Index]->LinkPhysical | QH_NEXT_IS_QH; + m_QueueHead[Index-1]->LinkPhysical = m_QueueHead[Index]->PhysicalAddress | QH_NEXT_IS_QH; m_QueueHead[Index-1]->NextLogicalDescriptor = m_QueueHead[Index]; } } @@ -1218,6 +1219,21 @@ CUSBHardwareDevice::ReadRegister32( return READ_PORT_ULONG((PULONG)((ULONG)m_Base + Register)); } +VOID +CUSBHardwareDevice::GetQueueHead( + IN ULONG QueueHeadIndex, + OUT PUHCI_QUEUE_HEAD *OutQueueHead) +{ + // + // sanity check + // + ASSERT(QueueHeadIndex < 5); + + // + // store queue head + // + *OutQueueHead = m_QueueHead[QueueHeadIndex]; +} VOID NTAPI diff --git a/reactos/drivers/usb/usbuhci/hardware.h b/reactos/drivers/usb/usbuhci/hardware.h index 434963c0e97..c2fb3cdab6d 100644 --- a/reactos/drivers/usb/usbuhci/hardware.h +++ b/reactos/drivers/usb/usbuhci/hardware.h @@ -163,7 +163,7 @@ UHCI_TRANSFER_DESCRIPTOR_LENGTH(PUHCI_TRANSFER_DESCRIPTOR Descriptor) } // Represents a Queue Head (QH) -typedef struct +typedef struct _UHCI_QUEUE_HEAD { // hardware part ULONG LinkPhysical; // address @@ -172,6 +172,8 @@ typedef struct // Software part ULONG PhysicalAddress; PVOID NextLogicalDescriptor; + PVOID Request; + PVOID NextElementDescriptor; }UHCI_QUEUE_HEAD, *PUHCI_QUEUE_HEAD; #define QH_TERMINATE 0x01 diff --git a/reactos/drivers/usb/usbuhci/interfaces.h b/reactos/drivers/usb/usbuhci/interfaces.h index 7c8f152d8f8..c86e9501922 100644 --- a/reactos/drivers/usb/usbuhci/interfaces.h +++ b/reactos/drivers/usb/usbuhci/interfaces.h @@ -107,7 +107,7 @@ DECLARE_INTERFACE_(IHCDController, IUnknown) typedef IHCDController *PHCDCONTROLLER; -struct _UHCI_TRANSFER_DESCRIPTOR; +struct _UHCI_QUEUE_HEAD; //========================================================================================= // // class IUSBHardwareDevice @@ -251,6 +251,15 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown) // virtual VOID SetStatusChangeEndpointCallBack(PVOID CallBack,PVOID Context) = 0; +//----------------------------------------------------------------------------------------- +// +// GetQueueHead +// +// Description: gets a queue head with the specified queue head index +// + virtual VOID GetQueueHead(ULONG QueueHeadIndex, struct _UHCI_QUEUE_HEAD **OutQueueHead) = 0; + + //----------------------------------------------------------------------------------------- // // AcquireDeviceLock @@ -350,6 +359,7 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, + IN USB_DEVICE_SPEED DeviceSpeed, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer) = 0; @@ -362,7 +372,8 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) // The irp contains an URB block which contains all necessary information virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, - IN OUT PIRP Irp) = 0; + IN OUT PIRP Irp, + IN USB_DEVICE_SPEED DeviceSpeed) = 0; //----------------------------------------------------------------------------------------- // @@ -390,7 +401,7 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) // // Description: returns the general transfer descriptor - virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_TRANSFER_DESCRIPTOR ** OutDescriptor) = 0; + virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_QUEUE_HEAD ** OutDescriptor) = 0; //----------------------------------------------------------------------------------------- // @@ -418,6 +429,14 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) virtual UCHAR GetInterval() = 0; +//----------------------------------------------------------------------------------------- +// +// GetDeviceSpeed +// +// Description: returns device speed + + virtual USB_DEVICE_SPEED GetDeviceSpeed() = 0; + }; diff --git a/reactos/drivers/usb/usbuhci/usb_device.cpp b/reactos/drivers/usb/usbuhci/usb_device.cpp index 4aafd342f7a..057f792af3e 100644 --- a/reactos/drivers/usb/usbuhci/usb_device.cpp +++ b/reactos/drivers/usb/usbuhci/usb_device.cpp @@ -462,7 +462,7 @@ CUSBDevice::CommitIrp( // // initialize request // - Status = Request->InitializeWithIrp(m_DmaManager, Irp); + Status = Request->InitializeWithIrp(m_DmaManager, Irp, GetSpeed()); // // mark irp as pending @@ -550,7 +550,7 @@ CUSBDevice::CommitSetupPacket( // // initialize request // - Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, m_DeviceAddress, EndpointDescriptor, BufferLength, Mdl); + Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, m_DeviceAddress, GetSpeed(), EndpointDescriptor, BufferLength, Mdl); if (!NT_SUCCESS(Status)) { // diff --git a/reactos/drivers/usb/usbuhci/usb_queue.cpp b/reactos/drivers/usb/usbuhci/usb_queue.cpp index e7f88c1b249..784240c8c24 100644 --- a/reactos/drivers/usb/usbuhci/usb_queue.cpp +++ b/reactos/drivers/usb/usbuhci/usb_queue.cpp @@ -40,6 +40,9 @@ public: virtual NTSTATUS CancelRequests(); virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest); + // local + VOID LinkQueueHead(PUHCI_QUEUE_HEAD QueueHead, PUHCI_QUEUE_HEAD NextQueueHead); + // constructor / destructor CUSBQueue(IUnknown *OuterUnknown){} virtual ~CUSBQueue(){} @@ -104,11 +107,95 @@ NTSTATUS CUSBQueue::AddUSBRequest( IUSBRequest * Request) { + PUHCI_QUEUE_HEAD NewQueueHead, QueueHead = NULL; + NTSTATUS Status; + DPRINT("CUSBQueue::AddUSBRequest\n"); - ASSERT(FALSE); + + // + // 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; + } + + if (Request->GetTransferType() == USB_ENDPOINT_TYPE_CONTROL) + { + // + // get device speed + // + if (Request->GetDeviceSpeed() == UsbLowSpeed) + { + // + // use low speed queue + // + m_Hardware->GetQueueHead(UHCI_LOW_SPEED_CONTROL_QUEUE, &QueueHead); + } + else + { + // + // use full speed queue + // + m_Hardware->GetQueueHead(UHCI_FULL_SPEED_CONTROL_QUEUE, &QueueHead); + } + } + else if (Request->GetTransferType() == USB_ENDPOINT_TYPE_BULK) + { + // + // use full speed queue + // + m_Hardware->GetQueueHead(UHCI_BULK_QUEUE, &QueueHead); + } + else if (Request->GetTransferType() == USB_ENDPOINT_TYPE_INTERRUPT) + { + // + // use full speed queue + // + m_Hardware->GetQueueHead(UHCI_INTERRUPT_QUEUE, &QueueHead); + } + else if (Request->GetTransferType() == USB_ENDPOINT_TYPE_INTERRUPT) + { + // + // use full speed queue + // + m_Hardware->GetQueueHead(UHCI_INTERRUPT_QUEUE, &QueueHead); + } + + // + // FIXME support isochronous + // + ASSERT(QueueHead); + + // + // add reference + // + Request->AddRef(); + + // + // now link the new queue head + // + LinkQueueHead(QueueHead, NewQueueHead); return STATUS_SUCCESS; } +VOID +CUSBQueue::LinkQueueHead( + IN PUHCI_QUEUE_HEAD QueueHead, + IN PUHCI_QUEUE_HEAD NextQueueHead) +{ + NextQueueHead->LinkPhysical = QueueHead->LinkPhysical; + NextQueueHead->NextLogicalDescriptor = QueueHead->NextLogicalDescriptor; + + QueueHead->LinkPhysical = NextQueueHead->PhysicalAddress | QH_NEXT_IS_QH; + QueueHead->NextLogicalDescriptor = (PVOID)NextQueueHead; +} + NTSTATUS CUSBQueue::CancelRequests() { diff --git a/reactos/drivers/usb/usbuhci/usb_request.cpp b/reactos/drivers/usb/usbuhci/usb_request.cpp index 7185d881aec..9562df5f21a 100644 --- a/reactos/drivers/usb/usbuhci/usb_request.cpp +++ b/reactos/drivers/usb/usbuhci/usb_request.cpp @@ -36,15 +36,16 @@ 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 InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp); + virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN USB_DEVICE_SPEED DeviceSpeed, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer); + virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp, IN USB_DEVICE_SPEED DeviceSpeed); virtual BOOLEAN IsRequestComplete(); virtual ULONG GetTransferType(); - virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_TRANSFER_DESCRIPTOR ** OutEndpointDescriptor); + virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_QUEUE_HEAD ** OutQueueHead); virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode); virtual BOOLEAN IsRequestInitialized(); virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead); virtual UCHAR GetInterval(); + virtual USB_DEVICE_SPEED GetDeviceSpeed(); // local functions @@ -55,6 +56,13 @@ public: NTSTATUS BuildSetupPacketFromURB(); UCHAR GetEndpointAddress(); USHORT GetMaxPacketSize(); + NTSTATUS CreateDescriptor(PUHCI_TRANSFER_DESCRIPTOR *OutDescriptor, IN UCHAR PidCode, ULONG BufferLength); + NTSTATUS BuildControlTransferDescriptor(IN PUHCI_QUEUE_HEAD * OutQueueHead); + NTSTATUS BuildQueueHead(OUT PUHCI_QUEUE_HEAD *OutQueueHead); + VOID FreeDescriptor(IN PUHCI_TRANSFER_DESCRIPTOR Descriptor); + NTSTATUS BuildTransferDescriptorChain(IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, IN UCHAR InitialDataToggle, OUT PUHCI_TRANSFER_DESCRIPTOR * OutFirstDescriptor, OUT PUHCI_TRANSFER_DESCRIPTOR * OutLastDescriptor, OUT PULONG OutTransferBufferOffset, OUT PUCHAR OutDataToggle); + + // constructor / destructor CUSBRequest(IUnknown *OuterUnknown){} @@ -125,6 +133,11 @@ protected: NTSTATUS m_NtStatusCode; ULONG m_UrbStatusCode; + // + // store device speed + // + USB_DEVICE_SPEED m_DeviceSpeed; + }; //---------------------------------------------------------------------------------------- @@ -143,6 +156,7 @@ CUSBRequest::InitializeWithSetupPacket( IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, + IN USB_DEVICE_SPEED DeviceSpeed, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer) @@ -163,6 +177,7 @@ CUSBRequest::InitializeWithSetupPacket( m_DeviceAddress = DeviceAddress; m_EndpointDescriptor = EndpointDescriptor; m_TotalBytesTransferred = 0; + m_DeviceSpeed = DeviceSpeed; // // Set Length Completed to 0 @@ -195,7 +210,8 @@ CUSBRequest::InitializeWithSetupPacket( NTSTATUS CUSBRequest::InitializeWithIrp( IN PDMAMEMORYMANAGER DmaManager, - IN OUT PIRP Irp) + IN OUT PIRP Irp, + IN USB_DEVICE_SPEED DeviceSpeed) { PIO_STACK_LOCATION IoStack; PURB Urb; @@ -208,6 +224,7 @@ CUSBRequest::InitializeWithIrp( m_DmaManager = DmaManager; m_TotalBytesTransferred = 0; + m_DeviceSpeed = DeviceSpeed; // // get current irp stack location @@ -514,13 +531,21 @@ CUSBRequest::InternalGetTransferType() UCHAR CUSBRequest::InternalGetPidDirection() { - ASSERT(m_Irp); - ASSERT(m_EndpointDescriptor); - - // - // end point is defined in the low byte of bEndpointAddress - // - return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7; + if (m_EndpointDescriptor) + { + // + // end point direction is highest bit in bEndpointAddress + // + return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7; + } + else + { + // + // request arrives on the control pipe, extract direction from setup packet + // + ASSERT(m_SetupPacket); + return (m_SetupPacket->bmRequestType.B >> 7); + } } @@ -578,13 +603,35 @@ CUSBRequest::GetDeviceAddress() //---------------------------------------------------------------------------------------- NTSTATUS CUSBRequest::GetEndpointDescriptor( - struct _UHCI_TRANSFER_DESCRIPTOR ** OutDescriptor) + struct _UHCI_QUEUE_HEAD ** OutQueueHead) { - ASSERT(FALSE); + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + if (InternalGetTransferType() == USB_ENDPOINT_TYPE_CONTROL) + { + // + // build queue head + // + Status = BuildControlTransferDescriptor(OutQueueHead); + } + + if (!NT_SUCCESS(Status)) + { + // + // failed + // + return Status; + } + + // + // store result + // + (*OutQueueHead)->Request = PVOID(this); + // // done // - return STATUS_NOT_IMPLEMENTED; + return STATUS_SUCCESS; } //---------------------------------------------------------------------------------------- @@ -647,8 +694,442 @@ CUSBRequest::IsQueueHeadComplete( UNIMPLEMENTED return TRUE; } +//----------------------------------------------------------------------------------------- +NTSTATUS +CUSBRequest::CreateDescriptor( + OUT PUHCI_TRANSFER_DESCRIPTOR *OutDescriptor, + IN UCHAR PidCode, + ULONG BufferLength) +{ + PUHCI_TRANSFER_DESCRIPTOR Descriptor; + PHYSICAL_ADDRESS Address; + NTSTATUS Status; + // + // allocate descriptor + // + Status = m_DmaManager->Allocate(sizeof(UHCI_TRANSFER_DESCRIPTOR), (PVOID*)&Descriptor, &Address); + if (!NT_SUCCESS(Status)) + { + DPRINT1("[USBUHCI] Failed to allocate descriptor\n"); + return Status; + } + // + // init descriptor + // + Descriptor->PhysicalAddress = Address; + Descriptor->Status = TD_STATUS_ACTIVE; + + if (InternalGetTransferType() == USB_ENDPOINT_TYPE_ISOCHRONOUS) + { + // + // isochronous transfer descriptor + // + Descriptor->Status |= TD_CONTROL_ISOCHRONOUS; + } + else + { + // + // error count + // + Descriptor->Status |= TD_CONTROL_3_ERRORS; + + if (PidCode == TD_TOKEN_IN && (InternalGetTransferType() != USB_ENDPOINT_TYPE_CONTROL)) + { + // + // enable short packet detect for bulk & interrupt + // + Descriptor->Status |= TD_CONTROL_SPD; + } + } + + // + // is it low speed device + // + if (m_DeviceSpeed == UsbLowSpeed) + { + // + // low speed device + // + Descriptor->Status |= TD_CONTROL_LOWSPEED; + } + + // + // store buffer size + // + Descriptor->BufferSize = BufferLength; + + // + // is there a buffer + // + if(BufferLength) + { + // + // store buffer length + // + Descriptor->Token = (BufferLength - 1) << TD_TOKEN_MAXLEN_SHIFT; + } + else + { + // + // no buffer magic constant + // + Descriptor->Token = TD_TOKEN_NULL_DATA; + } + + // + // store address & endpoint number + // + Descriptor->Token |= GetEndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT; + Descriptor->Token |= GetDeviceAddress() << 8 | PidCode; + + if (BufferLength) + { + // + // allocate buffer for descriptor + // + Status = m_DmaManager->Allocate(BufferLength, (PVOID*)&Descriptor->BufferLogical, &Address); + if (!NT_SUCCESS(Status)) + { + DPRINT1("[USBUHCI] Failed to allocate descriptor buffer length %lu\n", BufferLength); + m_DmaManager->Release(Descriptor, sizeof(UHCI_TRANSFER_DESCRIPTOR)); + return Status; + } + + // + // store address + // + Descriptor->BufferPhysical = Address.LowPart; + } + + // + // done + // + *OutDescriptor = Descriptor; + return STATUS_SUCCESS; +} + +NTSTATUS +CUSBRequest::BuildTransferDescriptorChain( + IN PVOID TransferBuffer, + IN ULONG TransferBufferLength, + IN UCHAR PidCode, + IN UCHAR InitialDataToggle, + OUT PUHCI_TRANSFER_DESCRIPTOR * OutFirstDescriptor, + OUT PUHCI_TRANSFER_DESCRIPTOR * OutLastDescriptor, + OUT PULONG OutTransferBufferOffset, + OUT PUCHAR OutDataToggle) +{ + PUHCI_TRANSFER_DESCRIPTOR FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL; + UCHAR TransferBufferOffset = 0; + NTSTATUS Status; + ULONG MaxPacketSize, CurrentBufferSize; + + // + // FIXME FIXME FIXME FIXME FIXME + // + MaxPacketSize = 64; + + do + { + // + // determine current packet size + // + CurrentBufferSize = min(MaxPacketSize, TransferBufferLength - TransferBufferOffset); + + // + // allocate descriptor + // + Status = CreateDescriptor(&CurrentDescriptor, PidCode, CurrentBufferSize); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate queue head + // + DPRINT1("[UHCI] Failed to create descriptor\n"); + ASSERT(FALSE); + return Status; + } + + if (PidCode == TD_TOKEN_OUT) + { + // + // copy buffer + // + RtlCopyMemory(CurrentDescriptor->BufferLogical, TransferBuffer, CurrentBufferSize); + } + + if (!FirstDescriptor) + { + // + // first descriptor + // + FirstDescriptor = CurrentDescriptor; + } + else + { + // + // link descriptor + // + LastDescriptor->LinkPhysical = CurrentDescriptor->PhysicalAddress.LowPart | TD_DEPTH_FIRST; + LastDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor; + } + + if (InitialDataToggle) + { + // + // apply data toggle + // + CurrentDescriptor->Token |= TD_TOKEN_DATA1; + } + + // + // re-run + // + LastDescriptor = CurrentDescriptor; + TransferBufferOffset += CurrentBufferSize; + InitialDataToggle = !InitialDataToggle; + + }while(TransferBufferOffset < TransferBufferLength); + + if (OutTransferBufferOffset) + { + // + // store transfer buffer length + // + *OutTransferBufferOffset = TransferBufferOffset; + } + + if (OutFirstDescriptor) + { + // + // store first descriptor + // + *OutFirstDescriptor = FirstDescriptor; + } + + if (OutLastDescriptor) + { + // + // store last descriptor + // + *OutLastDescriptor = CurrentDescriptor; + } + + if (OutDataToggle) + { + // + // store data toggle + // + *OutDataToggle = InitialDataToggle; + } + + // + // done + // + return STATUS_SUCCESS; +} + +NTSTATUS +CUSBRequest::BuildQueueHead( + OUT PUHCI_QUEUE_HEAD *OutQueueHead) +{ + PUHCI_QUEUE_HEAD QueueHead; + NTSTATUS Status; + PHYSICAL_ADDRESS Address; + + // + // allocate queue head + // + Status = m_DmaManager->Allocate(sizeof(UHCI_QUEUE_HEAD), (PVOID*)&QueueHead, &Address); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate queue head + // + DPRINT1("[UHCI] Failed to create queue head\n"); + return Status; + } + + // + // store address + // + QueueHead->PhysicalAddress = Address.LowPart; + QueueHead->ElementPhysical = Address.LowPart; + + // + // store result + // + *OutQueueHead = QueueHead; + return STATUS_SUCCESS; +} + +VOID +CUSBRequest::FreeDescriptor( + IN PUHCI_TRANSFER_DESCRIPTOR Descriptor) +{ + if (Descriptor->BufferLogical) + { + // + // free buffer + // + m_DmaManager->Release(Descriptor->BufferLogical, Descriptor->BufferSize); + } + + // + // free descriptors + // + m_DmaManager->Release(Descriptor, sizeof(UHCI_TRANSFER_DESCRIPTOR)); +} + +NTSTATUS +CUSBRequest::BuildControlTransferDescriptor( + IN PUHCI_QUEUE_HEAD * OutQueueHead) +{ + PUHCI_TRANSFER_DESCRIPTOR SetupDescriptor, StatusDescriptor, FirstDescriptor, LastDescriptor; + PUHCI_QUEUE_HEAD QueueHead; + BOOLEAN Direction; + NTSTATUS Status; + ULONG ChainDescriptorLength; + + // + // create queue head + // + Status = BuildQueueHead(&QueueHead); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate descriptor + // + DPRINT1("[UHCI] Failed to create queue head\n"); + return Status; + } + + // + // get direction + // + Direction = InternalGetPidDirection(); + + // + // build setup descriptor + // + Status = CreateDescriptor(&SetupDescriptor, + TD_TOKEN_SETUP, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate descriptor + // + DPRINT1("[UHCI] Failed to create setup descriptor\n"); + m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD)); + return Status; + } + + // + // build status descriptor + // + Status = CreateDescriptor(&StatusDescriptor, + Direction ? TD_TOKEN_OUT : TD_TOKEN_IN, + 0); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate descriptor + // + DPRINT1("[UHCI] Failed to create setup descriptor\n"); + FreeDescriptor(SetupDescriptor); + m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD)); + return Status; + } + + 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); + } + + // + // init status descriptor + // + StatusDescriptor->Status |= TD_CONTROL_IOC; + StatusDescriptor->Token |= TD_TOKEN_DATA1; + StatusDescriptor->LinkPhysical = TD_TERMINATE; + StatusDescriptor->NextLogicalDescriptor = NULL; + + if (m_TransferBufferLength) + { + // + // create descriptor chain + // + Status = BuildTransferDescriptorChain(MmGetMdlVirtualAddress(m_TransferBufferMDL), + m_TransferBufferLength, + Direction ? TD_TOKEN_IN : TD_TOKEN_OUT, + FALSE, + &FirstDescriptor, + &LastDescriptor, + &ChainDescriptorLength, + NULL); + if (!NT_SUCCESS(Status)) + { + // + // failed to allocate descriptor + // + DPRINT1("[UHCI] Failed to create descriptor chain\n"); + FreeDescriptor(SetupDescriptor); + FreeDescriptor(StatusDescriptor); + m_DmaManager->Release(QueueHead, sizeof(UHCI_QUEUE_HEAD)); + return Status; + } + + // + // link setup descriptor to first data descriptor + // + SetupDescriptor->LinkPhysical = FirstDescriptor->PhysicalAddress.LowPart | TD_DEPTH_FIRST; + SetupDescriptor->NextLogicalDescriptor = (PVOID)FirstDescriptor; + + // + // link last data descriptor to status descriptor + // + LastDescriptor->LinkPhysical = StatusDescriptor->PhysicalAddress.LowPart | TD_DEPTH_FIRST; + LastDescriptor->NextLogicalDescriptor = (PVOID)StatusDescriptor; + } + else + { + // + // directly link setup to status descriptor + // + SetupDescriptor->LinkPhysical = StatusDescriptor->PhysicalAddress.LowPart | TD_DEPTH_FIRST; + SetupDescriptor->NextLogicalDescriptor = (PVOID)StatusDescriptor; + } + + // + // link queue head with setup descriptor + // + QueueHead->NextElementDescriptor = (PVOID)SetupDescriptor; + QueueHead->ElementPhysical = SetupDescriptor->PhysicalAddress.LowPart; + + // + // store result + // + *OutQueueHead = QueueHead; + return STATUS_SUCCESS; +} +USB_DEVICE_SPEED +CUSBRequest::GetDeviceSpeed() +{ + return m_DeviceSpeed; +} //----------------------------------------------------------------------------------------- NTSTATUS