mirror of
https://github.com/reactos/reactos.git
synced 2025-05-18 16:51:18 +00:00
[USBUHCI]
- Implement function to retrieve queue head for the specified transfer type - Pass device speed to IUSBRequest initialization routines - Implementing inserting the new queue head into the required queue head - Implement support for control transfers, not yet used svn path=/trunk/; revision=55787
This commit is contained in:
parent
a14929eb93
commit
d8b2ccec60
6 changed files with 628 additions and 23 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
//
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue