mirror of
https://github.com/reactos/reactos.git
synced 2025-05-20 09:36:16 +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 GetPortStatus(ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange);
|
||||||
NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status);
|
NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status);
|
||||||
NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature);
|
NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature);
|
||||||
|
|
||||||
VOID SetStatusChangeEndpointCallBack(PVOID CallBack, PVOID Context);
|
VOID SetStatusChangeEndpointCallBack(PVOID CallBack, PVOID Context);
|
||||||
|
VOID GetQueueHead(ULONG QueueHeadIndex, PUHCI_QUEUE_HEAD *OutQueueHead);
|
||||||
|
|
||||||
|
|
||||||
KIRQL AcquireDeviceLock(void);
|
KIRQL AcquireDeviceLock(void);
|
||||||
VOID ReleaseDeviceLock(KIRQL OldLevel);
|
VOID ReleaseDeviceLock(KIRQL OldLevel);
|
||||||
|
@ -616,7 +617,7 @@ CUSBHardwareDevice::InitializeController()
|
||||||
//
|
//
|
||||||
// link queue heads
|
// 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];
|
m_QueueHead[Index-1]->NextLogicalDescriptor = m_QueueHead[Index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1218,6 +1219,21 @@ CUSBHardwareDevice::ReadRegister32(
|
||||||
return READ_PORT_ULONG((PULONG)((ULONG)m_Base + Register));
|
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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
|
|
|
@ -163,7 +163,7 @@ UHCI_TRANSFER_DESCRIPTOR_LENGTH(PUHCI_TRANSFER_DESCRIPTOR Descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a Queue Head (QH)
|
// Represents a Queue Head (QH)
|
||||||
typedef struct
|
typedef struct _UHCI_QUEUE_HEAD
|
||||||
{
|
{
|
||||||
// hardware part
|
// hardware part
|
||||||
ULONG LinkPhysical; // address
|
ULONG LinkPhysical; // address
|
||||||
|
@ -172,6 +172,8 @@ typedef struct
|
||||||
// Software part
|
// Software part
|
||||||
ULONG PhysicalAddress;
|
ULONG PhysicalAddress;
|
||||||
PVOID NextLogicalDescriptor;
|
PVOID NextLogicalDescriptor;
|
||||||
|
PVOID Request;
|
||||||
|
PVOID NextElementDescriptor;
|
||||||
}UHCI_QUEUE_HEAD, *PUHCI_QUEUE_HEAD;
|
}UHCI_QUEUE_HEAD, *PUHCI_QUEUE_HEAD;
|
||||||
|
|
||||||
#define QH_TERMINATE 0x01
|
#define QH_TERMINATE 0x01
|
||||||
|
|
|
@ -107,7 +107,7 @@ DECLARE_INTERFACE_(IHCDController, IUnknown)
|
||||||
|
|
||||||
typedef IHCDController *PHCDCONTROLLER;
|
typedef IHCDController *PHCDCONTROLLER;
|
||||||
|
|
||||||
struct _UHCI_TRANSFER_DESCRIPTOR;
|
struct _UHCI_QUEUE_HEAD;
|
||||||
//=========================================================================================
|
//=========================================================================================
|
||||||
//
|
//
|
||||||
// class IUSBHardwareDevice
|
// class IUSBHardwareDevice
|
||||||
|
@ -251,6 +251,15 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
|
||||||
//
|
//
|
||||||
virtual VOID SetStatusChangeEndpointCallBack(PVOID CallBack,PVOID Context) = 0;
|
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
|
// AcquireDeviceLock
|
||||||
|
@ -350,6 +359,7 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
||||||
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager,
|
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager,
|
||||||
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
||||||
IN UCHAR DeviceAddress,
|
IN UCHAR DeviceAddress,
|
||||||
|
IN USB_DEVICE_SPEED DeviceSpeed,
|
||||||
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
|
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
|
||||||
IN OUT ULONG TransferBufferLength,
|
IN OUT ULONG TransferBufferLength,
|
||||||
IN OUT PMDL TransferBuffer) = 0;
|
IN OUT PMDL TransferBuffer) = 0;
|
||||||
|
@ -362,7 +372,8 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
||||||
// The irp contains an URB block which contains all necessary information
|
// The irp contains an URB block which contains all necessary information
|
||||||
|
|
||||||
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager,
|
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
|
// 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;
|
virtual UCHAR GetInterval() = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetDeviceSpeed
|
||||||
|
//
|
||||||
|
// Description: returns device speed
|
||||||
|
|
||||||
|
virtual USB_DEVICE_SPEED GetDeviceSpeed() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -462,7 +462,7 @@ CUSBDevice::CommitIrp(
|
||||||
//
|
//
|
||||||
// initialize request
|
// initialize request
|
||||||
//
|
//
|
||||||
Status = Request->InitializeWithIrp(m_DmaManager, Irp);
|
Status = Request->InitializeWithIrp(m_DmaManager, Irp, GetSpeed());
|
||||||
|
|
||||||
//
|
//
|
||||||
// mark irp as pending
|
// mark irp as pending
|
||||||
|
@ -550,7 +550,7 @@ CUSBDevice::CommitSetupPacket(
|
||||||
//
|
//
|
||||||
// initialize request
|
// 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))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
|
|
@ -40,6 +40,9 @@ public:
|
||||||
virtual NTSTATUS CancelRequests();
|
virtual NTSTATUS CancelRequests();
|
||||||
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
|
||||||
|
|
||||||
|
// local
|
||||||
|
VOID LinkQueueHead(PUHCI_QUEUE_HEAD QueueHead, PUHCI_QUEUE_HEAD NextQueueHead);
|
||||||
|
|
||||||
// constructor / destructor
|
// constructor / destructor
|
||||||
CUSBQueue(IUnknown *OuterUnknown){}
|
CUSBQueue(IUnknown *OuterUnknown){}
|
||||||
virtual ~CUSBQueue(){}
|
virtual ~CUSBQueue(){}
|
||||||
|
@ -104,11 +107,95 @@ NTSTATUS
|
||||||
CUSBQueue::AddUSBRequest(
|
CUSBQueue::AddUSBRequest(
|
||||||
IUSBRequest * Request)
|
IUSBRequest * Request)
|
||||||
{
|
{
|
||||||
|
PUHCI_QUEUE_HEAD NewQueueHead, QueueHead = NULL;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
DPRINT("CUSBQueue::AddUSBRequest\n");
|
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;
|
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
|
NTSTATUS
|
||||||
CUSBQueue::CancelRequests()
|
CUSBQueue::CancelRequests()
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,15 +36,16 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// IUSBRequest interface functions
|
// 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 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);
|
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp, IN USB_DEVICE_SPEED DeviceSpeed);
|
||||||
virtual BOOLEAN IsRequestComplete();
|
virtual BOOLEAN IsRequestComplete();
|
||||||
virtual ULONG GetTransferType();
|
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 VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode);
|
||||||
virtual BOOLEAN IsRequestInitialized();
|
virtual BOOLEAN IsRequestInitialized();
|
||||||
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
||||||
virtual UCHAR GetInterval();
|
virtual UCHAR GetInterval();
|
||||||
|
virtual USB_DEVICE_SPEED GetDeviceSpeed();
|
||||||
|
|
||||||
|
|
||||||
// local functions
|
// local functions
|
||||||
|
@ -55,6 +56,13 @@ public:
|
||||||
NTSTATUS BuildSetupPacketFromURB();
|
NTSTATUS BuildSetupPacketFromURB();
|
||||||
UCHAR GetEndpointAddress();
|
UCHAR GetEndpointAddress();
|
||||||
USHORT GetMaxPacketSize();
|
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
|
// constructor / destructor
|
||||||
CUSBRequest(IUnknown *OuterUnknown){}
|
CUSBRequest(IUnknown *OuterUnknown){}
|
||||||
|
@ -125,6 +133,11 @@ protected:
|
||||||
NTSTATUS m_NtStatusCode;
|
NTSTATUS m_NtStatusCode;
|
||||||
ULONG m_UrbStatusCode;
|
ULONG m_UrbStatusCode;
|
||||||
|
|
||||||
|
//
|
||||||
|
// store device speed
|
||||||
|
//
|
||||||
|
USB_DEVICE_SPEED m_DeviceSpeed;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------
|
||||||
|
@ -143,6 +156,7 @@ CUSBRequest::InitializeWithSetupPacket(
|
||||||
IN PDMAMEMORYMANAGER DmaManager,
|
IN PDMAMEMORYMANAGER DmaManager,
|
||||||
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
|
||||||
IN UCHAR DeviceAddress,
|
IN UCHAR DeviceAddress,
|
||||||
|
IN USB_DEVICE_SPEED DeviceSpeed,
|
||||||
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
|
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
|
||||||
IN OUT ULONG TransferBufferLength,
|
IN OUT ULONG TransferBufferLength,
|
||||||
IN OUT PMDL TransferBuffer)
|
IN OUT PMDL TransferBuffer)
|
||||||
|
@ -163,6 +177,7 @@ CUSBRequest::InitializeWithSetupPacket(
|
||||||
m_DeviceAddress = DeviceAddress;
|
m_DeviceAddress = DeviceAddress;
|
||||||
m_EndpointDescriptor = EndpointDescriptor;
|
m_EndpointDescriptor = EndpointDescriptor;
|
||||||
m_TotalBytesTransferred = 0;
|
m_TotalBytesTransferred = 0;
|
||||||
|
m_DeviceSpeed = DeviceSpeed;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Set Length Completed to 0
|
// Set Length Completed to 0
|
||||||
|
@ -195,7 +210,8 @@ CUSBRequest::InitializeWithSetupPacket(
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CUSBRequest::InitializeWithIrp(
|
CUSBRequest::InitializeWithIrp(
|
||||||
IN PDMAMEMORYMANAGER DmaManager,
|
IN PDMAMEMORYMANAGER DmaManager,
|
||||||
IN OUT PIRP Irp)
|
IN OUT PIRP Irp,
|
||||||
|
IN USB_DEVICE_SPEED DeviceSpeed)
|
||||||
{
|
{
|
||||||
PIO_STACK_LOCATION IoStack;
|
PIO_STACK_LOCATION IoStack;
|
||||||
PURB Urb;
|
PURB Urb;
|
||||||
|
@ -208,6 +224,7 @@ CUSBRequest::InitializeWithIrp(
|
||||||
|
|
||||||
m_DmaManager = DmaManager;
|
m_DmaManager = DmaManager;
|
||||||
m_TotalBytesTransferred = 0;
|
m_TotalBytesTransferred = 0;
|
||||||
|
m_DeviceSpeed = DeviceSpeed;
|
||||||
|
|
||||||
//
|
//
|
||||||
// get current irp stack location
|
// get current irp stack location
|
||||||
|
@ -514,13 +531,21 @@ CUSBRequest::InternalGetTransferType()
|
||||||
UCHAR
|
UCHAR
|
||||||
CUSBRequest::InternalGetPidDirection()
|
CUSBRequest::InternalGetPidDirection()
|
||||||
{
|
{
|
||||||
ASSERT(m_Irp);
|
if (m_EndpointDescriptor)
|
||||||
ASSERT(m_EndpointDescriptor);
|
{
|
||||||
|
//
|
||||||
//
|
// end point direction is highest bit in bEndpointAddress
|
||||||
// end point is defined in the low byte of bEndpointAddress
|
//
|
||||||
//
|
return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
|
||||||
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
|
NTSTATUS
|
||||||
CUSBRequest::GetEndpointDescriptor(
|
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
|
// done
|
||||||
//
|
//
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------
|
||||||
|
@ -647,8 +694,442 @@ CUSBRequest::IsQueueHeadComplete(
|
||||||
UNIMPLEMENTED
|
UNIMPLEMENTED
|
||||||
return TRUE;
|
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
|
NTSTATUS
|
||||||
|
|
Loading…
Reference in a new issue