Author: janderwald
Date: Tue Feb 21 18:19:24 2012
New Revision: 55787
URL:
http://svn.reactos.org/svn/reactos?rev=55787&view=rev
Log:
[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
Modified:
trunk/reactos/drivers/usb/usbuhci/hardware.cpp
trunk/reactos/drivers/usb/usbuhci/hardware.h
trunk/reactos/drivers/usb/usbuhci/interfaces.h
trunk/reactos/drivers/usb/usbuhci/usb_device.cpp
trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp
trunk/reactos/drivers/usb/usbuhci/usb_request.cpp
Modified: trunk/reactos/drivers/usb/usbuhci/hardware.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/hardwa…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/hardware.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/hardware.cpp [iso-8859-1] Tue Feb 21 18:19:24 2012
@@ -73,8 +73,9 @@
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 @@
//
// 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 @@
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
Modified: trunk/reactos/drivers/usb/usbuhci/hardware.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/hardwa…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/hardware.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/hardware.h [iso-8859-1] Tue Feb 21 18:19:24 2012
@@ -163,7 +163,7 @@
}
// Represents a Queue Head (QH)
-typedef struct
+typedef struct _UHCI_QUEUE_HEAD
{
// hardware part
ULONG LinkPhysical; // address
@@ -172,6 +172,8 @@
// Software part
ULONG PhysicalAddress;
PVOID NextLogicalDescriptor;
+ PVOID Request;
+ PVOID NextElementDescriptor;
}UHCI_QUEUE_HEAD, *PUHCI_QUEUE_HEAD;
#define QH_TERMINATE 0x01
Modified: trunk/reactos/drivers/usb/usbuhci/interfaces.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/interf…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/interfaces.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/interfaces.h [iso-8859-1] Tue Feb 21 18:19:24 2012
@@ -107,7 +107,7 @@
typedef IHCDController *PHCDCONTROLLER;
-struct _UHCI_TRANSFER_DESCRIPTOR;
+struct _UHCI_QUEUE_HEAD;
//=========================================================================================
//
// class IUSBHardwareDevice
@@ -250,6 +250,15 @@
// Description: Used to callback to the hub controller when SCE detected
//
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;
+
//-----------------------------------------------------------------------------------------
//
@@ -350,6 +359,7 @@
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 @@
// 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 @@
//
// Description: returns the general transfer descriptor
- virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_TRANSFER_DESCRIPTOR **
OutDescriptor) = 0;
+ virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_QUEUE_HEAD ** OutDescriptor) =
0;
//-----------------------------------------------------------------------------------------
//
@@ -417,6 +428,14 @@
// Description: returns interval of the iso / interrupt
virtual UCHAR GetInterval() = 0;
+
+//-----------------------------------------------------------------------------------------
+//
+// GetDeviceSpeed
+//
+// Description: returns device speed
+
+ virtual USB_DEVICE_SPEED GetDeviceSpeed() = 0;
};
Modified: trunk/reactos/drivers/usb/usbuhci/usb_device.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/usb_de…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/usb_device.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/usb_device.cpp [iso-8859-1] Tue Feb 21 18:19:24
2012
@@ -462,7 +462,7 @@
//
// initialize request
//
- Status = Request->InitializeWithIrp(m_DmaManager, Irp);
+ Status = Request->InitializeWithIrp(m_DmaManager, Irp, GetSpeed());
//
// mark irp as pending
@@ -550,7 +550,7 @@
//
// 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))
{
//
Modified: trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/usb_qu…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/usb_queue.cpp [iso-8859-1] Tue Feb 21 18:19:24 2012
@@ -40,6 +40,9 @@
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,9 +107,93 @@
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
Modified: trunk/reactos/drivers/usb/usbuhci/usb_request.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbuhci/usb_re…
==============================================================================
--- trunk/reactos/drivers/usb/usbuhci/usb_request.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbuhci/usb_request.cpp [iso-8859-1] Tue Feb 21 18:19:24
2012
@@ -36,15 +36,16 @@
}
// 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 @@
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){}
@@ -124,6 +132,11 @@
//
NTSTATUS m_NtStatusCode;
ULONG m_UrbStatusCode;
+
+ //
+ // store device speed
+ //
+ USB_DEVICE_SPEED m_DeviceSpeed;
};
@@ -143,6 +156,7 @@
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 @@
m_DeviceAddress = DeviceAddress;
m_EndpointDescriptor = EndpointDescriptor;
m_TotalBytesTransferred = 0;
+ m_DeviceSpeed = DeviceSpeed;
//
// Set Length Completed to 0
@@ -195,7 +210,8 @@
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 @@
m_DmaManager = DmaManager;
m_TotalBytesTransferred = 0;
+ m_DeviceSpeed = DeviceSpeed;
//
// get current irp stack location
@@ -514,13 +531,21 @@
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 @@
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::GetEndpointDescriptor(
- struct _UHCI_TRANSFER_DESCRIPTOR ** OutDescriptor)
-{
- ASSERT(FALSE);
+ struct _UHCI_QUEUE_HEAD ** OutQueueHead)
+{
+ 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 @@
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