[USBOHCI]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Sat, 18 Feb 2012 23:23:13 +0000 (23:23 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Sat, 18 Feb 2012 23:23:13 +0000 (23:23 +0000)
- Don't preserve command status values when notifying controller of a new bulk / control endpoint
- Abort pipe & reset data toggle in the sync reset routine
- Allocate interface descriptors and endpoint handles when creating the configuration descriptor
- Implement routine for allocating chained descriptors
- Implement data toggle for bulk&interrupt transfers
- Mass storage devices should now work in real hardware with OHCI controller
- Tested in real hardware with NEC Corporation USB [1033:0035] (rev 43)

svn path=/trunk/; revision=55687

reactos/drivers/usb/usbohci/hardware.cpp
reactos/drivers/usb/usbohci/hardware.h
reactos/drivers/usb/usbohci/hub_controller.cpp
reactos/drivers/usb/usbohci/interfaces.h
reactos/drivers/usb/usbohci/usb_device.cpp
reactos/drivers/usb/usbohci/usb_queue.cpp
reactos/drivers/usb/usbohci/usb_request.cpp
reactos/drivers/usb/usbohci/usbohci.h

index 8df2a76..332e5b5 100644 (file)
@@ -732,21 +732,19 @@ VOID
 CUSBHardwareDevice::HeadEndpointDescriptorModified(
     ULONG Type)
 {
-    ULONG Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET));
-
     if (Type == USB_ENDPOINT_TYPE_CONTROL)
     {
         //
         // notify controller
         //
-        WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Value | OHCI_CONTROL_LIST_FILLED);
+        WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), OHCI_CONTROL_LIST_FILLED);
     }
     else if (Type == USB_ENDPOINT_TYPE_BULK)
     {
         //
         // notify controller
         //
-        WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Value | OHCI_BULK_LIST_FILLED);
+        WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), OHCI_BULK_LIST_FILLED);
     }
 }
 
@@ -1579,7 +1577,7 @@ OhciDefferedRoutine(
     CStatus = (ULONG) SystemArgument1;
     DoneHead = (ULONG)SystemArgument2;
 
-    DPRINT("OhciDefferedRoutine Status %x\n", CStatus);
+    DPRINT("OhciDefferedRoutine Status %x DoneHead %x\n", CStatus, DoneHead);
 
     if (CStatus & OHCI_WRITEBACK_DONE_HEAD)
     {
index ec9a3cd..2964582 100644 (file)
@@ -224,6 +224,7 @@ typedef struct _OHCI_ENDPOINT_DESCRIPTOR
     PVOID HeadLogicalDescriptor;
     PVOID NextDescriptor;
     PVOID Request;
+    LIST_ENTRY DescriptorListEntry;
 }OHCI_ENDPOINT_DESCRIPTOR, *POHCI_ENDPOINT_DESCRIPTOR;
 
 
@@ -242,7 +243,9 @@ typedef struct _OHCI_ENDPOINT_DESCRIPTOR
 #define OHCI_ENDPOINT_ISOCHRONOUS_FORMAT        0x00008000
 #define        OHCI_ENDPOINT_HEAD_MASK                 0xfffffffc
 #define        OHCI_ENDPOINT_HALTED                    0x00000001
+#define        OHCI_ENDPOINT_TOGGLE_CARRY              0x00000002
 #define        OHCI_ENDPOINT_DIRECTION_DESCRIPTOR      0x00000000
+
 //
 // Maximum port count set by OHCI
 //
index 1888564..35a96e2 100644 (file)
@@ -1710,7 +1710,7 @@ CHubController::HandleSyncResetAndClearStall(
     IN OUT PURB Urb)
 {
     NTSTATUS Status = STATUS_SUCCESS;
-    PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+    PUSB_ENDPOINT EndpointDescriptor;
     ULONG Type;
 
     //
@@ -1736,12 +1736,24 @@ CHubController::HandleSyncResetAndClearStall(
     //
     // get endpoint descriptor
     //
-    EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle;
+    EndpointDescriptor = (PUSB_ENDPOINT)Urb->UrbPipeRequest.PipeHandle;
+
+    //
+    // abort pipe
+    //
+    Status = HandleAbortPipe(Irp, Urb);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // abort pipe failed
+        //
+        DPRINT1("[USBOHCI] AbortPipe failed with %x\n", Status);
+    }
 
     //
     // get type
     //
-    Type = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
+    Type = (EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
     if (Type != USB_ENDPOINT_TYPE_ISOCHRONOUS)
     {
         //
@@ -1752,8 +1764,9 @@ CHubController::HandleSyncResetAndClearStall(
     DPRINT1("URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL Status %x\n", Status);
 
     //
-    // FIXME reset data toggle
+    // reset data toggle
     //
+    EndpointDescriptor->DataToggle = 0;
 
     //
     // done
index c8b50ff..b60321d 100644 (file)
@@ -372,6 +372,8 @@ DECLARE_INTERFACE_(IDMAMemoryManager, IUnknown)
 
 typedef IDMAMemoryManager *PDMAMEMORYMANAGER;
 
+struct _USB_ENDPOINT;
+
 
 //=========================================================================================
 //
@@ -401,7 +403,7 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
     virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager,
                                                IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
                                                IN UCHAR DeviceAddress,
-                                               IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
+                                               IN OPTIONAL struct _USB_ENDPOINT* EndpointDescriptor,
                                                IN USB_DEVICE_SPEED DeviceSpeed,
                                                IN OUT ULONG TransferBufferLength,
                                                IN OUT PMDL TransferBuffer) = 0;
@@ -470,7 +472,7 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
 //
 // Description: notifies request that the endpoint descriptor is complete
 
-    virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor) = 0;
+    virtual VOID CompletionCallback() = 0;
 
 //-----------------------------------------------------------------------------------------
 //
index 09482f9..838f4e6 100644 (file)
@@ -54,10 +54,11 @@ public:
     virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, IN OUT PUSBD_INTERFACE_INFORMATION Interface);
     virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor);
 
+
     // local function
     virtual NTSTATUS CommitIrp(PIRP Irp);
-    virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl);
-    virtual NTSTATUS CreateConfigurationDescriptor(ULONG ConfigurationIndex);
+    virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor, IN ULONG BufferLength, IN OUT PMDL Mdl);
+    virtual NTSTATUS CreateConfigurationDescriptor(UCHAR ConfigurationIndex);
     virtual NTSTATUS CreateDeviceDescriptor();
     virtual VOID DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor);
     virtual VOID DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor);
@@ -80,9 +81,8 @@ protected:
     ULONG m_PortStatus;
     PUSBQUEUE m_Queue;
     PDMAMEMORYMANAGER m_DmaManager;
-    PUSB_CONFIGURATION_DESCRIPTOR *m_ConfigurationDescriptors;
-    LIST_ENTRY m_IrpListHead;
 
+    PUSB_CONFIGURATION m_ConfigurationDescriptors;
 };
 
 //----------------------------------------------------------------------------------------
@@ -120,11 +120,6 @@ CUSBDevice::Initialize(
     //
     KeInitializeSpinLock(&m_Lock);
 
-    //
-    // initialize irp list
-    //
-    InitializeListHead(&m_IrpListHead);
-
     //
     // no device address has been set yet
     //
@@ -276,6 +271,7 @@ CUSBDevice::GetType()
 
     DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor.bcdUSB);
     //PC_ASSERT(FALSE);
+
     return Usb11Device;
 }
 
@@ -306,7 +302,7 @@ CUSBDevice::SetDeviceAddress(
     PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
     NTSTATUS Status;
     UCHAR OldAddress;
-    ULONG Index;
+    UCHAR Index;
 
     DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress);
 
@@ -388,12 +384,12 @@ CUSBDevice::SetDeviceAddress(
     //
     // allocate configuration descriptor
     //
-    m_ConfigurationDescriptors = (PUSB_CONFIGURATION_DESCRIPTOR*) ExAllocatePoolWithTag(NonPagedPool, sizeof(PUSB_CONFIGURATION_DESCRIPTOR) * m_DeviceDescriptor.bNumConfigurations, TAG_USBOHCI);
+    m_ConfigurationDescriptors = (PUSB_CONFIGURATION) ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations, TAG_USBOHCI);
 
     //
     // zero configuration descriptor
     //
-    RtlZeroMemory(m_ConfigurationDescriptors, sizeof(PUSB_CONFIGURATION_DESCRIPTOR) * m_DeviceDescriptor.bNumConfigurations);
+    RtlZeroMemory(m_ConfigurationDescriptors, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations);
 
     //
     // retrieve the configuration descriptors
@@ -525,7 +521,7 @@ CUSBDevice::SubmitIrp(
 NTSTATUS
 CUSBDevice::CommitSetupPacket(
     IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet,
-    IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
+    IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor,
     IN ULONG BufferLength, 
     IN OUT PMDL Mdl)
 {
@@ -662,19 +658,15 @@ CUSBDevice::CreateDeviceDescriptor()
 
     if (NT_SUCCESS(Status))
     {
-        //
-        // copy back device descriptor
-        //
-        RtlCopyMemory(&m_DeviceDescriptor, DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
-
         //
         // informal dbg print
         //
+        RtlCopyMemory(&m_DeviceDescriptor, DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
         DumpDeviceDescriptor(&m_DeviceDescriptor);
     }
 
     //
-    // free item
+    // free buffer
     //
     ExFreePool(DeviceDescriptor);
 
@@ -688,13 +680,16 @@ CUSBDevice::CreateDeviceDescriptor()
 //----------------------------------------------------------------------------------------
 NTSTATUS
 CUSBDevice::CreateConfigurationDescriptor(
-    ULONG Index)
+    UCHAR Index)
 {
     PVOID Buffer;
     USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
     NTSTATUS Status;
     PMDL Mdl;
+    ULONG InterfaceIndex, EndPointIndex;
     PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+    PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
 
 
     //
@@ -714,11 +709,6 @@ CUSBDevice::CreateConfigurationDescriptor(
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    //
-    // zero buffer
-    //
-    RtlZeroMemory(Buffer, PAGE_SIZE);
-
     //
     // build setup packet
     //
@@ -727,15 +717,11 @@ CUSBDevice::CreateConfigurationDescriptor(
     CtrlSetup.bmRequestType._BM.Reserved = 0;
     CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
     CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
-    CtrlSetup.wValue.LowByte = 0;
+    CtrlSetup.wValue.LowByte = Index;
     CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
     CtrlSetup.wIndex.W = 0;
     CtrlSetup.wLength = PAGE_SIZE;
 
-    //
-    // FIXME: where put configuration index?
-    //
-
     //
     // now build MDL describing the buffer
     //
@@ -791,9 +777,124 @@ CUSBDevice::CreateConfigurationDescriptor(
     PC_ASSERT(ConfigurationDescriptor->bNumInterfaces);
 
     //
-    // store configuration descriptor
+    // request is complete, initialize configuration descriptor
+    //
+    m_ConfigurationDescriptors[Index].ConfigurationDescriptor = ConfigurationDescriptor;
+
+    //
+    // now allocate interface descriptors
+    //
+    m_ConfigurationDescriptors[Index].Interfaces = (PUSB_INTERFACE)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces, TAG_USBOHCI);
+    if (!m_ConfigurationDescriptors[Index].Interfaces)
+    {
+        //
+        // failed to allocate interface descriptors
+        //
+        ExFreePool(Buffer);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // zero interface descriptor
+    //
+    RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces);
+
+    //
+    // get first interface descriptor
+    //
+    InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)(ConfigurationDescriptor + 1);
+
+    //
+    // setup interface descriptors
     //
-    m_ConfigurationDescriptors[Index] = ConfigurationDescriptor;
+    for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
+    {
+        while(InterfaceDescriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE && InterfaceDescriptor->bLength != sizeof(USB_INTERFACE_DESCRIPTOR))
+        {
+            //
+            // move to next descriptor
+            //
+            ASSERT(InterfaceDescriptor->bLength);
+            InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
+        }
+
+        //
+        // sanity checks
+        //
+        ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+        ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+        ASSERT(InterfaceDescriptor->bNumEndpoints);
+
+        //
+        // copy current interface descriptor
+        //
+        RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].InterfaceDescriptor, InterfaceDescriptor, InterfaceDescriptor->bLength);
+
+        //
+        // allocate end point descriptors
+        //
+        m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints = (PUSB_ENDPOINT)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints, TAG_USBOHCI);
+        if (!m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints)
+        {
+            //
+            // failed to allocate endpoint
+            //
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            break;
+        }
+
+        //
+        // zero memory
+        //
+        RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints);
+
+        //
+        // initialize end point descriptors
+        //
+        EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)(InterfaceDescriptor + 1);
+
+        for(EndPointIndex = 0; EndPointIndex < InterfaceDescriptor->bNumEndpoints; EndPointIndex++)
+        {
+            //
+            // skip other descriptors
+            //
+            while(EndPointDescriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE && EndPointDescriptor->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR))
+            {
+                //
+                // assert when next interface descriptor is reached before the next endpoint
+                //
+                ASSERT(EndPointDescriptor->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE);
+                ASSERT(EndPointDescriptor->bLength);
+
+                DPRINT1("InterfaceDescriptor  bNumEndpoints %x EndpointIndex %x Skipping Descriptor Type %x\n", InterfaceDescriptor->bNumEndpoints, EndPointIndex, EndPointDescriptor->bDescriptorType);
+                //
+                // move to next descriptor
+                //
+                EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndPointDescriptor + EndPointDescriptor->bLength);
+            }
+
+            //
+            // sanity check
+            //
+            ASSERT(EndPointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
+            ASSERT(EndPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
+
+            //
+            // copy endpoint descriptor
+            //
+            RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints[EndPointIndex].EndPointDescriptor, EndPointDescriptor, EndPointDescriptor->bLength);
+
+            //
+            // move to next offset
+            //
+            EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndPointDescriptor + EndPointDescriptor->bLength);
+        }
+
+        //
+        // update interface descriptor offset
+        //
+        InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)EndPointDescriptor;
+    }
 
     //
     // done
@@ -827,8 +928,8 @@ CUSBDevice::GetConfigurationDescriptors(
     //
     // copy configuration descriptor
     //
-    RtlCopyMemory(ConfigDescriptorBuffer, m_ConfigurationDescriptors[0], min(m_ConfigurationDescriptors[0]->wTotalLength, BufferLength));
-    *OutBufferLength = m_ConfigurationDescriptors[0]->wTotalLength;
+    RtlCopyMemory(ConfigDescriptorBuffer, m_ConfigurationDescriptors[0].ConfigurationDescriptor, min(m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength, BufferLength));
+    *OutBufferLength = m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength;
 }
 
 //----------------------------------------------------------------------------------------
@@ -839,11 +940,7 @@ CUSBDevice::GetConfigurationDescriptorsLength()
     // FIXME: support multiple configurations
     //
     PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
-
-    ASSERT(m_ConfigurationDescriptors[0]);
-    ASSERT(m_ConfigurationDescriptors[0]->wTotalLength);
-
-    return m_ConfigurationDescriptors[0]->wTotalLength;
+    return m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength;
 }
 //----------------------------------------------------------------------------------------
 VOID
@@ -897,7 +994,12 @@ CUSBDevice::SubmitSetupPacket(
         //
         Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
         if (!Mdl)
+        {
+            //
+            // no memory
+            //
             return STATUS_INSUFFICIENT_RESOURCES;
+        }
 
         //
         // HACK HACK HACK: assume the buffer is build from non paged pool
@@ -934,88 +1036,93 @@ CUSBDevice::SelectConfiguration(
     ULONG InterfaceIndex, PipeIndex;
     USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
     NTSTATUS Status;
-    PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigurationDescriptor;
-    PUSB_INTERFACE_DESCRIPTOR CurrentInterfaceDescriptor;
-    PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
-    PVOID StartPosition;
 
     //
-    // FIXME: support multiple configurations
+    // sanity checks
     //
-    ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
-    ASSERT(m_ConfigurationDescriptors[0]);
-    CurrentConfigurationDescriptor = m_ConfigurationDescriptors[0];
+    ASSERT(ConfigurationDescriptor->iConfiguration < m_DeviceDescriptor.bNumConfigurations);
+    ASSERT(ConfigurationDescriptor->iConfiguration == m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].ConfigurationDescriptor->iConfiguration);
 
     //
     // sanity check
     //
-    PC_ASSERT(ConfigurationDescriptor->iConfiguration == CurrentConfigurationDescriptor->iConfiguration);
-    PC_ASSERT(ConfigurationDescriptor->bNumInterfaces <= CurrentConfigurationDescriptor->bNumInterfaces);
-    DPRINT1("CUSBDevice::SelectConfiguration NumInterfaces %lu\n", ConfigurationDescriptor->bNumInterfaces);
+    ASSERT(ConfigurationDescriptor->bNumInterfaces <= m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].ConfigurationDescriptor->bNumInterfaces);
 
+    //
+    // now build setup packet
+    //
+    RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
+    CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
+    CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue;
 
     //
-    // copy interface info and pipe info
+    // select configuration
     //
-    for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
+    Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
+
+    //
+    // informal debug print
+    //
+    DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status);
+    if (!NT_SUCCESS(Status))
     {
         //
-        // find interface descriptor
+        // failed
         //
-        CurrentInterfaceDescriptor = USBD_ParseConfigurationDescriptor(CurrentConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
+        return Status;
+    }
+
+    //
+    // store configuration device index
+    //
+    m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration;
 
+    //
+    // store configuration handle
+    //
+    *ConfigurationHandle = &m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration];
+
+    //
+    // copy interface info and pipe info
+    //
+    for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
+    {
         //
-        // sanity check
+        // sanity check: is the info pre-layed out
         //
-        ASSERT(CurrentInterfaceDescriptor);
-        ASSERT(CurrentInterfaceDescriptor->bLength != 0);
-        ASSERT(InterfaceInfo->NumberOfPipes == CurrentInterfaceDescriptor->bNumEndpoints);
-        ASSERT(InterfaceInfo->Length != 0);
+        PC_ASSERT(InterfaceInfo->NumberOfPipes == m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints);
+        PC_ASSERT(InterfaceInfo->Length != 0);
 #ifdef _MSC_VER
         PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
 #endif
 
-        DPRINT1("CUSBDevice::SelectConfiguration InterfaceNumber %lu AlternativeSetting %lu bNumEndpoints %lu\n", InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting, CurrentInterfaceDescriptor->bNumEndpoints);
-
         //
         // copy interface info
         //
-        InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)CurrentInterfaceDescriptor;
-        InterfaceInfo->Class = CurrentInterfaceDescriptor->bInterfaceClass;
-        InterfaceInfo->SubClass = CurrentInterfaceDescriptor->bInterfaceSubClass;
-        InterfaceInfo->Protocol = CurrentInterfaceDescriptor->bInterfaceProtocol;
+        InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)&m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex];
+        InterfaceInfo->Class = m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceClass;
+        InterfaceInfo->SubClass = m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceSubClass;
+        InterfaceInfo->Protocol = m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceProtocol;
         InterfaceInfo->Reserved = 0;
 
         //
         // copy endpoint info
         //
-        StartPosition = CurrentInterfaceDescriptor;
         for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
         {
-            //
-            // find corresponding endpoint descriptor
-            //
-            CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(CurrentConfigurationDescriptor, CurrentConfigurationDescriptor->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
-
-            //
-            // sanity checks
-            //
-            ASSERT(CurrentEndpointDescriptor);
-            ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
-
             //
             // copy pipe info
             //
-            InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
-            InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
-            InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
-            InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
-            InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
+            InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.wMaxPacketSize;
+            InterfaceInfo->Pipes[PipeIndex].EndpointAddress = m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress;
+            InterfaceInfo->Pipes[PipeIndex].Interval = m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bInterval;
+            InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bmAttributes;
+            InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)&m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor;
 
             //
-            // move start position beyond the current endpoint descriptor
+            // data toggle is reset on configuration requests
             //
-            StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
+            m_ConfigurationDescriptors[ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceIndex].EndPoints[PipeIndex].DataToggle = FALSE;
         }
 
         //
@@ -1024,36 +1131,6 @@ CUSBDevice::SelectConfiguration(
         InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
     }
 
-    //
-    // now build setup packet
-    //
-    RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
-    CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
-    CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue;
-
-    //
-    // select configuration
-    //
-    Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
-
-    //
-    // informal debug print
-    //
-    DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status);
-
-    if (NT_SUCCESS(Status))
-    {
-        //
-        // store configuration device index
-        //
-        m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration;
-
-        //
-        // store configuration handle
-        //
-        *ConfigurationHandle = m_ConfigurationDescriptors[0];
-    }
-
     //
     // done
     //
@@ -1066,49 +1143,31 @@ CUSBDevice::SelectInterface(
     IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
     IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
 {
-    PUSB_CONFIGURATION_DESCRIPTOR Configuration;
+    PUSB_CONFIGURATION Configuration;
     ULONG PipeIndex;
     USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
     NTSTATUS Status;
-    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
-    PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
-    PVOID StartPosition;
-
-    //
-    // FIXME support multiple configurations
-    //
-    PC_ASSERT(m_ConfigurationDescriptors[0] == (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle);
 
     //
     // get configuration struct
     //
-    Configuration = (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle;
-
-    //
-    // sanity checks
-    //
-    PC_ASSERT(Configuration->bNumInterfaces > InterfaceInfo->InterfaceNumber);
-#ifdef _MSC_VER
-    //PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
-#endif
-
-    //
-    // FIXME: check bandwidth
-    //
+    Configuration = (PUSB_CONFIGURATION)ConfigurationHandle;
 
     //
-    // find interface number
+    // sanity check
     //
-    InterfaceDescriptor = USBD_ParseConfigurationDescriptor(Configuration, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
-    ASSERT(InterfaceDescriptor);
+    ASSERT(Configuration->ConfigurationDescriptor->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE);
+    ASSERT(Configuration->ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
+    ASSERT(Configuration->ConfigurationDescriptor->iConfiguration < m_DeviceDescriptor.bNumConfigurations);
+    ASSERT(&m_ConfigurationDescriptors[Configuration->ConfigurationDescriptor->iConfiguration] == Configuration);
 
     //
     // initialize setup packet
     //
     RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
     CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
-    CtrlSetup.wValue.W = InterfaceDescriptor->bAlternateSetting;
-    CtrlSetup.wIndex.W = InterfaceDescriptor->bInterfaceNumber;
+    CtrlSetup.wValue.W = Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bAlternateSetting;
+    CtrlSetup.wIndex.W = Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bInterfaceNumber;
     CtrlSetup.bmRequestType.B = 0x01;
 
     //
@@ -1120,55 +1179,58 @@ CUSBDevice::SelectInterface(
     // informal debug print
     //
     DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status);
-    DPRINT1("CUSBDevice::SelectInterface bInterfaceNumber %u bAlternateSetting %u NumberOfPipes %u Length %lu\n", 
-            InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceInfo->NumberOfPipes, InterfaceInfo->Length);
-    InterfaceInfo->InterfaceHandle =  InterfaceDescriptor;
-    InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to select interface
+        //
+        return Status;
+    }
+
+
+    //
+    // sanity checks
+    //
+    PC_ASSERT(Configuration->ConfigurationDescriptor->bNumInterfaces > InterfaceInfo->InterfaceNumber);
+    PC_ASSERT(Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bNumEndpoints == InterfaceInfo->NumberOfPipes);
+#ifdef _MSC_VER
+    PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
+#endif
 
     //
-    // are there end points
+    // copy pipe handles
     //
-    if (InterfaceDescriptor->bNumEndpoints)
+    for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
     {
         //
-        // sanity check
+        // copy pipe handle
         //
-        ASSERT(InterfaceInfo->Length == sizeof(USBD_INTERFACE_INFORMATION) + (InterfaceDescriptor->bNumEndpoints > 1 ? sizeof(USBD_PIPE_INFORMATION) * (InterfaceDescriptor->bNumEndpoints - 1) : 0));
+        DPRINT1("PipeIndex %lu\n", PipeIndex);
+        DPRINT1("EndpointAddress %x\n", InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
+        DPRINT1("Interval %d\n", InterfaceInfo->Pipes[PipeIndex].Interval);
+        DPRINT1("MaximumPacketSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize);
+        DPRINT1("MaximumTransferSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumTransferSize);
+        DPRINT1("PipeFlags %d\n", InterfaceInfo->Pipes[PipeIndex].PipeFlags);
+        DPRINT1("PipeType %dd\n", InterfaceInfo->Pipes[PipeIndex].PipeType);
+        DPRINT1("UsbEndPoint %x\n", Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress);
+        PC_ASSERT(Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress == InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
+
+        InterfaceInfo->Pipes[PipeIndex].PipeHandle = &Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor;
 
         //
-        // store number of pipes
+        // data toggle is reset on select interface requests
         //
-        InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
+        m_ConfigurationDescriptors[Configuration->ConfigurationDescriptor->iConfiguration].Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].DataToggle = FALSE;
 
-        StartPosition = InterfaceDescriptor;
-        for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
+        if (Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bmAttributes & (USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_TYPE_INTERRUPT))
         {
             //
-            // find corresponding endpoint descriptor
-            //
-            CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(Configuration, Configuration->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
-
+            // FIXME: check if enough bandwidth is available
             //
-            // sanity checks
-            //
-            ASSERT(CurrentEndpointDescriptor);
-            ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
-
-            //
-            // copy pipe info
-            //
-            InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
-            InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
-            InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
-            InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
-            InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
-
-            //
-            // move start position beyond the current endpoint descriptor
-            //
-            StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
         }
     }
+
+
     //
     // done
     //
@@ -1191,6 +1253,7 @@ CUSBDevice::AbortPipe(
     return m_Queue->AbortDevicePipe(m_DeviceAddress, EndpointDescriptor);
 }
 
+
 //----------------------------------------------------------------------------------------
 NTSTATUS
 CreateUSBDevice(
index a5a79c2..500c81a 100644 (file)
@@ -53,6 +53,8 @@ public:
     POHCI_ENDPOINT_DESCRIPTOR FindInterruptEndpointDescriptor(UCHAR InterruptInterval);
     VOID PrintEndpointList(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
     VOID LinkEndpoint(POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
+    VOID AddEndpointDescriptor(IN POHCI_ENDPOINT_DESCRIPTOR Descriptor);
+
 
     // constructor / destructor
     CUSBQueue(IUnknown *OuterUnknown){}
@@ -66,6 +68,7 @@ protected:
     POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor;                          // control head descriptor
     POHCI_ENDPOINT_DESCRIPTOR m_IsoHeadEndpointDescriptor;                              // isochronous head descriptor
     POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints;
+    LIST_ENTRY m_PendingRequestList;                                                    // pending request list
 };
 
 //=================================================================================================
@@ -119,6 +122,12 @@ CUSBQueue::Initialize(
     //
     KeInitializeSpinLock(&m_Lock);
 
+    //
+    // init list
+    //
+    InitializeListHead(&m_PendingRequestList);
+
+
     //
     // store hardware
     //
@@ -164,53 +173,29 @@ CUSBQueue::LinkEndpoint(
 
 }
 
-NTSTATUS
-CUSBQueue::AddUSBRequest(
-    IUSBRequest * Request)
+VOID
+CUSBQueue::AddEndpointDescriptor(
+    IN POHCI_ENDPOINT_DESCRIPTOR Descriptor)
 {
-    NTSTATUS Status;
+    IUSBRequest *Request;
     ULONG Type;
     POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor;
-    POHCI_ENDPOINT_DESCRIPTOR Descriptor;
     POHCI_ISO_TD CurrentDescriptor;
     ULONG FrameNumber;
     USHORT Frame;
 
-    DPRINT("CUSBQueue::AddUSBRequest\n");
 
     //
     // sanity check
     //
-    ASSERT(Request != NULL);
+    ASSERT(Descriptor->Request);
+    Request = (IUSBRequest*)Descriptor->Request;
 
     //
     // get request type
     //
     Type = Request->GetTransferType();
 
-    //
-    // add extra reference which is released when the request is completed
-    //
-    Request->AddRef();
-
-    //
-    // get transfer descriptors
-    //
-    Status = Request->GetEndpointDescriptor(&Descriptor);
-    if (!NT_SUCCESS(Status))
-    {
-        //
-        // failed to get transfer descriptor
-        //
-        DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status);
-
-        //
-        // release reference
-        //
-        Request->Release();
-        return Status;
-    }
-
     //
     // check type
     //
@@ -294,8 +279,8 @@ CUSBQueue::AddUSBRequest(
         //
         // bad request type
         //
-        Request->Release();
-        return STATUS_INVALID_PARAMETER;
+        ASSERT(FALSE);
+        return;
     }
 
     //
@@ -315,7 +300,50 @@ CUSBQueue::AddUSBRequest(
         //
         m_Hardware->HeadEndpointDescriptorModified(Type);
     }
+}
+
+
+NTSTATUS
+CUSBQueue::AddUSBRequest(
+    IUSBRequest * Request)
+{
+    NTSTATUS Status;
+    IN POHCI_ENDPOINT_DESCRIPTOR Descriptor;
+
+    DPRINT("CUSBQueue::AddUSBRequest\n");
+
+    //
+    // sanity check
+    //
+    ASSERT(Request != NULL);
+
+    //
+    // add extra reference which is released when the request is completed
+    //
+    Request->AddRef();
+
+    //
+    // get transfer descriptors
+    //
+    Status = Request->GetEndpointDescriptor(&Descriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to get transfer descriptor
+        //
+        DPRINT1("CUSBQueue::AddUSBRequest GetEndpointDescriptor failed with %x\n", Status);
+
+        //
+        // release reference
+        //
+        Request->Release();
+        return Status;
+    }
 
+    //
+    // add the request
+    //
+    AddEndpointDescriptor(Descriptor);
     return STATUS_SUCCESS;
 }
 
@@ -562,6 +590,9 @@ CUSBQueue::CleanupEndpointDescriptor(
     POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor)
 {
     PUSBREQUEST Request;
+    POHCI_ENDPOINT_DESCRIPTOR NewEndpointDescriptor;
+    USBD_STATUS UrbStatus;
+    KIRQL OldLevel;
 
     //
     // FIXME: verify unlinking process
@@ -576,21 +607,90 @@ CUSBQueue::CleanupEndpointDescriptor(
     ASSERT(Request);
 
     //
-    // notify of completion
+    // check for errors
+    //
+    if (EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED)
+    {
+        //
+        // the real error will processed by IUSBRequest
+        //
+        UrbStatus = USBD_STATUS_STALL_PID;
+    }
+    else
+    {
+        //
+        // well done ;)
+        //
+        UrbStatus = USBD_STATUS_SUCCESS;
+    }
+
+    //
+    // Check if the transfer was completed and if UrbStatus is ok
     //
-    Request->CompletionCallback(EndpointDescriptor);
+    if ((Request->IsRequestComplete() == FALSE) && (UrbStatus == USBD_STATUS_SUCCESS))
+    {
+        //
+        // request is incomplete, get new queue head
+        //
+        if (Request->GetEndpointDescriptor(&NewEndpointDescriptor) == STATUS_SUCCESS)
+        {
+            //
+            // notify of completion
+            //
+            Request->FreeEndpointDescriptor(EndpointDescriptor);
+
+            //
+            // first acquire request lock
+            //
+            KeAcquireSpinLock(&m_Lock, &OldLevel);
+
+            //
+            // add to pending list
+            //
+            InsertTailList(&m_PendingRequestList, &NewEndpointDescriptor->DescriptorListEntry);
+
+            //
+            // release queue head
+            //
+            KeReleaseSpinLock(&m_Lock, OldLevel);
+
+            //
+            // Done for now
+            //
+            return;
+        }
+        DPRINT1("Unable to create a new QueueHead\n");
+        //ASSERT(FALSE);
+
+        //
+        // Else there was a problem
+        // FIXME: Find better return
+        UrbStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (UrbStatus != USBD_STATUS_SUCCESS)
+    {
+        DPRINT1("URB failed with status 0x%x\n", UrbStatus);
+        //PC_ASSERT(FALSE);
+    }
 
     //
     // free endpoint descriptor
     //
     Request->FreeEndpointDescriptor(EndpointDescriptor);
 
+    //
+    // notify of completion
+    //
+    Request->CompletionCallback();
+
+
     //
     // release request
     //
     Request->Release();
-
 }
+
 VOID
 CUSBQueue::PrintEndpointList(
     POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
@@ -618,6 +718,7 @@ CUSBQueue::TransferDescriptorCompletionCallback(
     ULONG TransferDescriptorLogicalAddress)
 {
     POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, PreviousEndpointDescriptor;
+    PLIST_ENTRY Entry;
     NTSTATUS Status;
 
     DPRINT("CUSBQueue::TransferDescriptorCompletionCallback transfer descriptor %x\n", TransferDescriptorLogicalAddress);
@@ -697,15 +798,41 @@ CUSBQueue::TransferDescriptorCompletionCallback(
         //
         // no more completed descriptors found
         //
-        return;
+        break;
 
     }while(TRUE);
 
+
+    //
+    // acquire spin lock
+    //
+    KeAcquireSpinLockAtDpcLevel(&m_Lock);
+
+    //
+    // is there a pending list item
+    //
+    if (!IsListEmpty(&m_PendingRequestList))
+    {
+        //
+        // get list entry
+        //
+        Entry = RemoveHeadList(&m_PendingRequestList);
+
+        //
+        // get entry
+        //
+        EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CONTAINING_RECORD(Entry, OHCI_ENDPOINT_DESCRIPTOR, DescriptorListEntry);
+
+        //
+        // add entry
+        //
+        AddEndpointDescriptor(EndpointDescriptor);
+    }
+
     //
-    // hardware reported dead endpoint completed
+    // release lock
     //
-    DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback invalid transfer descriptor %x\n", TransferDescriptorLogicalAddress);
-    ASSERT(FALSE);
+    KeReleaseSpinLockFromDpcLevel(&m_Lock);
 }
 
 POHCI_ENDPOINT_DESCRIPTOR
@@ -789,8 +916,12 @@ CUSBQueue::AbortDevicePipe(
         HeadDescriptor = FindInterruptEndpointDescriptor(EndpointDescriptor->bInterval);
         ASSERT(HeadDescriptor);
     }
-    else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
+    else
     {
+        //
+        // IMPLEMENT me
+        //
+        ASSERT(Type == USB_ENDPOINT_TYPE_ISOCHRONOUS);
         UNIMPLEMENTED
         return STATUS_NOT_IMPLEMENTED;
     }
index 2ebc80f..cbee88a 100644 (file)
@@ -36,7 +36,7 @@ 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 USB_DEVICE_SPEED DeviceSpeed, 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 OPTIONAL struct _USB_ENDPOINT* EndpointDescriptor, IN USB_DEVICE_SPEED DeviceSpeed, 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();
@@ -44,7 +44,7 @@ public:
     virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode);
     virtual BOOLEAN IsRequestInitialized();
     virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
-    virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
+    virtual VOID CompletionCallback();
     virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
     virtual UCHAR GetInterval();
 
@@ -65,6 +65,8 @@ public:
     USHORT GetMaxPacketSize();
     VOID CheckError(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
     VOID DumpEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR *Descriptor);
+    NTSTATUS BuildTransferDescriptorChain(IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, OUT POHCI_GENERAL_TD * OutFirstDescriptor, OUT POHCI_GENERAL_TD * OutLastDescriptor, OUT PULONG OutTransferBufferOffset);
+    VOID InitDescriptor(IN POHCI_GENERAL_TD CurrentDescriptor, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode);
 
 
     // constructor / destructor
@@ -120,9 +122,9 @@ protected:
     UCHAR m_DeviceAddress;
 
     //
-    // store end point address
+    // store endpoint descriptor
     //
-    PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor;
+    PUSB_ENDPOINT m_EndpointDescriptor;
 
     //
     // allocated setup packet from the DMA pool
@@ -145,6 +147,11 @@ protected:
     // store urb
     //
     PURB m_Urb;
+
+    //
+    // base buffer
+    //
+    PVOID m_Base;
 };
 
 //----------------------------------------------------------------------------------------
@@ -163,7 +170,7 @@ CUSBRequest::InitializeWithSetupPacket(
     IN PDMAMEMORYMANAGER DmaManager,
     IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
     IN UCHAR DeviceAddress,
-    IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
+    IN OPTIONAL struct _USB_ENDPOINT* EndpointDescriptor,
     IN USB_DEVICE_SPEED DeviceSpeed,
     IN OUT ULONG TransferBufferLength,
     IN OUT PMDL TransferBuffer)
@@ -331,7 +338,7 @@ CUSBRequest::InitializeWithIrp(
             //
             // get endpoint descriptor
             //
-            m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)m_Urb->UrbIsochronousTransfer.PipeHandle;
+            m_EndpointDescriptor = (PUSB_ENDPOINT)m_Urb->UrbIsochronousTransfer.PipeHandle;
 
             //
             // completed initialization
@@ -406,7 +413,7 @@ CUSBRequest::InitializeWithIrp(
                 //
                 // get endpoint descriptor
                 //
-                m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)m_Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+                m_EndpointDescriptor = (PUSB_ENDPOINT)m_Urb->UrbBulkOrInterruptTransfer.PipeHandle;
 
             }
             break;
@@ -459,11 +466,21 @@ CUSBRequest::GetMaxPacketSize()
 {
     if (!m_EndpointDescriptor)
     {
-        //
-        // FIXME: use DeviceDescriptor.bMaxPacketSize0
-        // control pipe request
-        //
-        return 8;
+        if (m_DeviceSpeed == UsbLowSpeed)
+        {
+            //
+            // control pipes use 8 bytes packets
+            //
+            return 8;
+        }
+        else
+        {
+            //
+            // must be full speed
+            //
+            ASSERT(m_DeviceSpeed == UsbFullSpeed);
+            return 64;
+        }
     }
 
     ASSERT(m_Irp);
@@ -472,19 +489,19 @@ CUSBRequest::GetMaxPacketSize()
     //
     // return max packet size
     //
-    return m_EndpointDescriptor->wMaxPacketSize;
+    return m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
 }
 
 UCHAR
 CUSBRequest::GetInterval()
 {
     ASSERT(m_EndpointDescriptor);
-    ASSERT((m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
+    ASSERT((m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
 
     //
     // return interrupt interval
     //
-    return m_EndpointDescriptor->bInterval;
+    return m_EndpointDescriptor->EndPointDescriptor.bInterval;
 }
 
 UCHAR
@@ -504,7 +521,7 @@ CUSBRequest::GetEndpointAddress()
     //
     // endpoint number is between 1-15
     //
-    return (m_EndpointDescriptor->bEndpointAddress & 0xF);
+    return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0xF);
 }
 
 //----------------------------------------------------------------------------------------
@@ -523,7 +540,7 @@ CUSBRequest::InternalGetTransferType()
         //
         // end point is defined in the low byte of bmAttributes
         //
-        TransferType = (m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
+        TransferType = (m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK);
     }
     else
     {
@@ -547,7 +564,7 @@ CUSBRequest::InternalGetPidDirection()
         //
         // end point direction is highest bit in bEndpointAddress
         //
-        return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
+        return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
     }
     else
     {
@@ -967,7 +984,7 @@ CUSBRequest::AllocateEndpointDescriptor(
     Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
     Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
 
-    DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
+    DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %lu\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
 
     //
     // is there an endpoint descriptor
@@ -977,7 +994,7 @@ CUSBRequest::AllocateEndpointDescriptor(
         //
         // check direction
         //
-        if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->bEndpointAddress))
+        if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress))
         {
             //
             // direction out
@@ -1041,137 +1058,127 @@ CUSBRequest::AllocateEndpointDescriptor(
     return STATUS_SUCCESS;
 }
 
-NTSTATUS
-CUSBRequest::BuildBulkInterruptEndpoint(
-    POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
+VOID
+CUSBRequest::InitDescriptor(
+    IN POHCI_GENERAL_TD CurrentDescriptor,
+    IN PVOID TransferBuffer,
+    IN ULONG TransferBufferLength,
+    IN UCHAR PidDirection)
 {
-    POHCI_GENERAL_TD FirstDescriptor, PreviousDescriptor = NULL, CurrentDescriptor, LastDescriptor;
-    POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
-    ULONG BufferSize, CurrentSize, Direction, MaxLengthInPage;
-    NTSTATUS Status;
-    PVOID Buffer;
+    ULONG Direction;
 
-    //
-    // allocate endpoint descriptor
-    //
-    Status = AllocateEndpointDescriptor(&EndpointDescriptor);
-    if (!NT_SUCCESS(Status))
+    if (PidDirection)
     {
         //
-        // failed to create setup descriptor
+        // input direction
         //
-        return Status;
+        Direction = OHCI_TD_DIRECTION_PID_IN;
     }
-
-    //
-    // allocate transfer descriptor for last descriptor
-    //
-    Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0);
-    if (!NT_SUCCESS(Status))
+    else
     {
         //
-        // failed to create transfer descriptor
+        // output direction
         //
-        m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
-        return Status;
+        Direction = OHCI_TD_DIRECTION_PID_OUT;
     }
 
+
     //
-    // get buffer size
+    // initialize descriptor
     //
-    BufferSize = m_TransferBufferLength;
-    ASSERT(BufferSize);
-    ASSERT(m_TransferBufferMDL);
+    CurrentDescriptor->Flags = Direction | OHCI_TD_BUFFER_ROUNDING | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY;
 
     //
-    // get buffer
+    // store physical address of buffer
     //
-    Buffer = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
-    ASSERT(Buffer);
+    CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(TransferBuffer).LowPart;
+    CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + TransferBufferLength - 1; 
 
-    if (InternalGetPidDirection())
-    {
-        //
-        // input direction
-        //
-        Direction = OHCI_TD_DIRECTION_PID_IN;
-    }
-    else
-    {
-        //
-        // output direction
-        //
-        Direction = OHCI_TD_DIRECTION_PID_OUT;
-    }
+    DPRINT("CurrentDescriptor %p Addr %x  TransferBufferLength %lu\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, TransferBufferLength);
+}
+
+NTSTATUS
+CUSBRequest::BuildTransferDescriptorChain(
+    IN PVOID TransferBuffer,
+    IN ULONG TransferBufferLength,
+    IN UCHAR PidDirection,
+    OUT POHCI_GENERAL_TD * OutFirstDescriptor,
+    OUT POHCI_GENERAL_TD * OutLastDescriptor,
+    OUT PULONG OutTransferBufferOffset)
+{
+    POHCI_GENERAL_TD FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL;
+    NTSTATUS Status;
+    ULONG MaxLengthInPage, TransferBufferOffset  = 0;
+    ULONG MaxPacketSize = 0, TransferSize, CurrentSize;
+
+    //
+    // for now use one page as maximum size
+    //
+    MaxPacketSize = PAGE_SIZE;
 
     do
     {
         //
-        // get current buffersize
+        // allocate transfer descriptor
         //
-        CurrentSize = min(8192, BufferSize);
+        Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0);
+        if (!NT_SUCCESS(Status))
+        {
+            //
+            // failed to allocate transfer descriptor
+            //
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        if (MaxPacketSize)
+        {
+            //
+            // transfer size is minimum available buffer or endpoint size
+            //
+            TransferSize = min(TransferBufferLength - TransferBufferOffset, MaxPacketSize);
+        }
+        else
+        {
+            //
+            // use available buffer
+            //
+            TransferSize = TransferBufferLength - TransferBufferOffset;
+        }
 
         //
         // get page offset
         //
-        MaxLengthInPage = PAGE_SIZE - BYTE_OFFSET(Buffer);
+        MaxLengthInPage = PAGE_SIZE - BYTE_OFFSET(TransferBuffer);
 
         //
         // get minimum from current page size
         //
-        CurrentSize = min(CurrentSize, MaxLengthInPage);
+        CurrentSize = min(TransferSize, MaxLengthInPage);
         ASSERT(CurrentSize);
 
         //
-        // allocate transfer descriptor
+        // now init the descriptor
         //
-        Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0);
-        if (!NT_SUCCESS(Status))
-        {
-            //
-            // failed to create transfer descriptor
-            // TODO: cleanup
-            //
-            ASSERT(FALSE);
-            m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
-            FreeDescriptor(LastDescriptor);
-            return Status;
-        }
+        InitDescriptor(CurrentDescriptor, 
+                       (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset),
+                       CurrentSize,
+                       PidDirection);
 
         //
-        // initialize descriptor
+        // adjust offset
         //
-        CurrentDescriptor->Flags = Direction | OHCI_TD_BUFFER_ROUNDING | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY;
-
-        //
-        // store physical address of buffer
-        //
-        CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(Buffer).LowPart;
-        CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + CurrentSize - 1; 
-
-#if 0
-        if (m_Urb != NULL)
-        {
-            if (m_Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
-            {
-                //
-                // indicate short packet support
-                //
-                CurrentDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
-            }
-        }
-#endif
+        TransferBufferOffset += CurrentSize;
 
         //
         // is there a previous descriptor
         //
-        if (PreviousDescriptor)
+        if (LastDescriptor)
         {
             //
             // link descriptors
             //
-            PreviousDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor;
-            PreviousDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
+            LastDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor;
+            LastDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
         }
         else
         {
@@ -1181,24 +1188,115 @@ CUSBRequest::BuildBulkInterruptEndpoint(
             FirstDescriptor = CurrentDescriptor;
         }
 
-        DPRINT("PreviousDescriptor %p CurrentDescriptor %p Logical %x  Buffer Logical %p Physical %x Last Physical %x CurrentSize %lu\n", PreviousDescriptor, CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, CurrentDescriptor->BufferLogical, CurrentDescriptor->BufferPhysical, CurrentDescriptor->LastPhysicalByteAddress, CurrentSize);
+        if(TransferBufferLength == TransferBufferOffset)
+        {
+            //
+            // end reached
+            //
+            break;
+        }
+
+    }while(TRUE);
 
+    if (OutFirstDescriptor)
+    {
         //
-        //  set previous descriptor
+        // store first descriptor
         //
-        PreviousDescriptor = CurrentDescriptor;
+        *OutFirstDescriptor = FirstDescriptor;
+    }
 
+    if (OutLastDescriptor)
+    {
         //
-        // subtract buffer size
+        // store last descriptor
         //
-        BufferSize -= CurrentSize;
+        *OutLastDescriptor = CurrentDescriptor;
+    }
+
+    if (OutTransferBufferOffset)
+    {
+        //
+        // store offset
+        //
+        *OutTransferBufferOffset = TransferBufferOffset;
+    }
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+CUSBRequest::BuildBulkInterruptEndpoint(
+    POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
+{
+    POHCI_GENERAL_TD FirstDescriptor, LastDescriptor;
+    POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+    NTSTATUS Status;
+    PVOID Base;
+    ULONG ChainDescriptorLength;
+
+    //
+    // sanity check
+    //
+    ASSERT(m_EndpointDescriptor);
+
+    //
+    // allocate endpoint descriptor
+    //
+    Status = AllocateEndpointDescriptor(&EndpointDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to create setup descriptor
+        //
+        return Status;
+    }
 
+    ASSERT(m_TransferBufferMDL);
+
+    if (m_Base == NULL)
+    {
         //
-        // increment buffer offset
+        // get buffer
         //
-        Buffer = (PVOID)((ULONG_PTR)Buffer + CurrentSize);
+        m_Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
+    }
+
+    //
+    // Increase the size of last transfer, 0 in case this is the first
+    //
+    Base = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted);
+
+    //
+    // sanity checks
+    //
+    ASSERT(m_EndpointDescriptor);
+    ASSERT(Base);
+
+    //
+    // use 2 * PAGE_SIZE at max for each new request
+    //
+    ULONG MaxTransferLength = min(1 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted);
+    DPRINT("m_TransferBufferLength %lu m_TransferBufferLengthCompleted %lu DataToggle %x\n", m_TransferBufferLength, m_TransferBufferLengthCompleted, m_EndpointDescriptor->DataToggle);
 
-    }while(BufferSize);
+    //
+    // build bulk transfer descriptor chain
+    //
+    Status = BuildTransferDescriptorChain(Base,
+                                          MaxTransferLength,
+                                          InternalGetPidDirection(),
+                                          &FirstDescriptor,
+                                          &LastDescriptor,
+                                          &ChainDescriptorLength);
+
+    //
+    // move to next offset
+    //
+    m_TransferBufferLengthCompleted += ChainDescriptorLength;
 
     //
     // first descriptor has no carry bit
@@ -1206,33 +1304,33 @@ CUSBRequest::BuildBulkInterruptEndpoint(
     FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY;
 
     //
-    // fixme: toggle
+    // apply data toggle
     //
-    FirstDescriptor->Flags |= OHCI_TD_TOGGLE_0;
+    FirstDescriptor->Flags |= (m_EndpointDescriptor->DataToggle ? OHCI_TD_TOGGLE_1 : OHCI_TD_TOGGLE_0);
 
     //
     // clear interrupt mask for last transfer descriptor
     //
-    CurrentDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
+    LastDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
 
-    //
-    // fire interrupt as soon transfer is finished
-    //
-    CurrentDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
 
     //
-    // link last data descriptor to last descriptor
+    // fire interrupt as soon transfer is finished
     //
-    CurrentDescriptor->NextLogicalDescriptor = LastDescriptor;
-    CurrentDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
+    LastDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
 
     //
     // now link descriptor to endpoint
     //
     EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
-    EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
+    EndpointDescriptor->TailPhysicalDescriptor = (FirstDescriptor == LastDescriptor ? 0 : LastDescriptor->PhysicalAddress.LowPart);
     EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
 
+    //
+    // dump descriptor list
+    //
+    //DumpEndpointDescriptor(EndpointDescriptor);
+
     //
     // store result
     //
@@ -1567,6 +1665,12 @@ CUSBRequest::FreeEndpointDescriptor(
 
     DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
 
+    //
+    // check for errors
+    //
+    CheckError(OutDescriptor);
+
+
     if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
     {
         //
@@ -1686,6 +1790,14 @@ CUSBRequest::CheckError(
         //
         TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
 
+        if (m_EndpointDescriptor != NULL)
+        {
+            //
+            // update data toggle
+            //
+            m_EndpointDescriptor->DataToggle = (OutDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_TOGGLE_CARRY);
+        }
+
         while(TransferDescriptor)
         {
             //
@@ -1776,21 +1888,18 @@ CUSBRequest::CheckError(
             TransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
         }
     }
+
+
+
 }
 
 VOID
-CUSBRequest::CompletionCallback(
-    struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
+CUSBRequest::CompletionCallback()
 {
     PIO_STACK_LOCATION IoStack;
     PURB Urb;
 
-    DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
-
-    //
-    // check for errors
-    //
-    CheckError(OutDescriptor);
+    DPRINT("CUSBRequest::CompletionCallback\n");
 
     if (m_Irp)
     {
@@ -1826,12 +1935,11 @@ CUSBRequest::CompletionCallback(
         }
 
         //
-        // FIXME: support status and calculate length
+        // FIXME calculate length
         //
 
         //
-        // FIXME: check if the transfer was split
-        // if yes dont complete irp yet
+        // complete request
         //
         IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
     }
index 6eab4ba..5773215 100644 (file)
@@ -108,4 +108,26 @@ NTSTATUS CreateUSBQueue(PUSBQUEUE *OutUsbQueue);
 //
 NTSTATUS InternalCreateUSBRequest(PUSBREQUEST *OutRequest);
 
+
+typedef struct _USB_ENDPOINT
+{
+    USB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
+    UCHAR HubAddress;
+    UCHAR HubPort;
+    UCHAR DataToggle;
+} USB_ENDPOINT, *PUSB_ENDPOINT;
+
+typedef struct _USB_INTERFACE
+{
+    USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+    USB_ENDPOINT *EndPoints;
+} USB_INTERFACE, *PUSB_INTERFACE;
+
+typedef struct _USB_CONFIGURATION
+{
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
+    USB_INTERFACE *Interfaces;
+} USB_CONFIGURATION, *PUSB_CONFIGURATION;
+
+
 #endif