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/hardware.cpp?rev=55787&r1=55786&r2=55787&view=diff
==============================================================================
--- 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/hardware.h?rev=55787&r1=55786&r2=55787&view=diff
==============================================================================
--- 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/interfaces.h?rev=55787&r1=55786&r2=55787&view=diff
==============================================================================
--- 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_device.cpp?rev=55787&r1=55786&r2=55787&view=diff
==============================================================================
--- 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_queue.cpp?rev=55787&r1=55786&r2=55787&view=diff
==============================================================================
--- 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_request.cpp?rev=55787&r1=55786&r2=55787&view=diff
==============================================================================
--- 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


Reply via email to