[USBPORT]
authorThomas Faber <thomas.faber@reactos.org>
Fri, 8 Sep 2017 07:17:34 +0000 (07:17 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Fri, 8 Sep 2017 07:17:34 +0000 (07:17 +0000)
- Begin implementing split transfers. Patch by Vadim Galyant.

svn path=/trunk/; revision=75783

reactos/drivers/usb/usbport/CMakeLists.txt
reactos/drivers/usb/usbport/endpoint.c
reactos/drivers/usb/usbport/queue.c
reactos/drivers/usb/usbport/trfsplit.c [new file with mode: 0644]
reactos/drivers/usb/usbport/usbport.c
reactos/drivers/usb/usbport/usbport.h
reactos/sdk/include/reactos/drivers/usbport/usbmport.h

index 52db934..6f0d188 100644 (file)
@@ -12,6 +12,7 @@ list(APPEND SOURCE
     power.c
     queue.c
     roothub.c
+    trfsplit.c
     urb.c
     usb2.c
     usbport.c
index b0ec684..2931794 100644 (file)
@@ -1279,8 +1279,7 @@ USBPORT_DmaEndpointPaused(IN PDEVICE_OBJECT FdoDevice,
 
             if (Transfer->Flags & TRANSFER_FLAG_SPLITED)
             {
-                DPRINT1("USBPORT_DmaEndpointActive: FIXME call USBPORT_CancelSplitTransfer\n");
-                ASSERT(FALSE); //USBPORT_CancelSplitTransfer();
+                USBPORT_CancelSplitTransfer(Transfer);
             }
             else
             {
index 9cdebbc..ab16801 100644 (file)
@@ -529,6 +529,8 @@ USBPORT_CancelActiveTransferIrp(IN PDEVICE_OBJECT DeviceObject,
     PUSBPORT_TRANSFER Transfer;
     PUSBPORT_ENDPOINT Endpoint;
     PIRP irp;
+    PUSBPORT_TRANSFER SplitTransfer;
+    PLIST_ENTRY Entry;
     KIRQL OldIrql;
 
     DPRINT_CORE("USBPORT_CancelActiveTransferIrp: Irp - %p\n", Irp);
@@ -543,30 +545,52 @@ USBPORT_CancelActiveTransferIrp(IN PDEVICE_OBJECT DeviceObject,
 
     irp = USBPORT_FindActiveTransferIrp(FdoDevice, Irp);
 
-    if (irp)
+    if (!irp)
     {
-        Urb = URB_FROM_IRP(irp);
-        Transfer = Urb->UrbControlTransfer.hca.Reserved8[0];
-        Endpoint = Transfer->Endpoint;
+        KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql);
+        return;
+    }
 
-        DPRINT_CORE("USBPORT_CancelActiveTransferIrp: irp - %p, Urb - %p, Transfer - %p\n",
-                    irp,
-                    Urb,
-                    Transfer);
+    Urb = URB_FROM_IRP(irp);
+    Transfer = Urb->UrbControlTransfer.hca.Reserved8[0];
+    Endpoint = Transfer->Endpoint;
 
-        KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock);
-        Transfer->Flags |= TRANSFER_FLAG_CANCELED;
-        KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
+    DPRINT_CORE("USBPORT_CancelActiveTransferIrp: irp - %p, Urb - %p, Transfer - %p\n",
+                irp,
+                Urb,
+                Transfer);
 
-        KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql);
+    KeAcquireSpinLockAtDpcLevel(&Endpoint->EndpointSpinLock);
 
-        USBPORT_InvalidateEndpointHandler(FdoDevice,
-                                          Endpoint,
-                                          INVALIDATE_ENDPOINT_WORKER_THREAD);
-        return;
+    Transfer->Flags |= TRANSFER_FLAG_CANCELED;
+
+    if (Transfer->Flags & TRANSFER_FLAG_PARENT)
+    {
+        KeAcquireSpinLockAtDpcLevel(&Transfer->TransferSpinLock);
+
+        Entry = Transfer->SplitTransfersList.Flink;
+
+        while (Entry && Entry != &Transfer->SplitTransfersList)
+        {
+            SplitTransfer = CONTAINING_RECORD(Entry,
+                                              USBPORT_TRANSFER,
+                                              SplitLink);
+
+            SplitTransfer->Flags |= TRANSFER_FLAG_CANCELED;
+
+            Entry = Entry->Flink;
+        }
+
+        KeReleaseSpinLockFromDpcLevel(&Transfer->TransferSpinLock);
     }
 
+    KeReleaseSpinLockFromDpcLevel(&Endpoint->EndpointSpinLock);
     KeReleaseSpinLock(&FdoExtension->FlushTransferSpinLock, OldIrql);
+
+    USBPORT_InvalidateEndpointHandler(FdoDevice,
+                                      Endpoint,
+                                      INVALIDATE_ENDPOINT_WORKER_THREAD);
+    return;
 }
 
 VOID
diff --git a/reactos/drivers/usb/usbport/trfsplit.c b/reactos/drivers/usb/usbport/trfsplit.c
new file mode 100644 (file)
index 0000000..5f129b8
--- /dev/null
@@ -0,0 +1,329 @@
+#include "usbport.h"
+
+#define NDEBUG
+#include <debug.h>
+
+ULONG
+NTAPI
+USBPORT_MakeSplitTransfer(IN PDEVICE_OBJECT FdoDevice,
+                          IN PUSBPORT_TRANSFER Transfer,
+                          IN PUSBPORT_TRANSFER SplitTransfer,
+                          IN ULONG MaxTransferSize,
+                          IN PULONG SgIdx,
+                          IN PULONG SgOffset,
+                          IN ULONG TransferRemainLen,
+                          IN ULONG TransferOffset)
+{
+    PUSBPORT_SCATTER_GATHER_LIST SplitSgList;
+    PUSBPORT_SCATTER_GATHER_ELEMENT Element0;
+    PUSBPORT_SCATTER_GATHER_ELEMENT Element1;
+    SIZE_T SgLength;
+    SIZE_T SgRemainLen;
+
+    DPRINT("USBPORT_MakeSplitTransfer: ... \n");
+
+    SplitSgList = &SplitTransfer->SgList;
+    Element0 = &SplitSgList->SgElement[0];
+
+    SgLength = Transfer->SgList.SgElement[*SgIdx].SgTransferLength - *SgOffset;
+
+    if (SgLength > MaxTransferSize)
+    {
+        /* SgLength > MaxTransferSize */
+        SplitTransfer->SgList.SgElementCount = 1;
+
+        Element0->SgOffset = 0;
+        Element0->SgTransferLength = MaxTransferSize;
+        Element0->SgPhysicalAddress.LowPart = Transfer->SgList.SgElement[*SgIdx].SgPhysicalAddress.LowPart + *SgOffset;
+
+        SplitTransfer->TransferParameters.IsTransferSplited = TRUE;
+        SplitTransfer->TransferParameters.TransferBufferLength = MaxTransferSize;
+
+        SplitTransfer->SgList.CurrentVa = Transfer->SgList.CurrentVa + TransferOffset;
+        SplitTransfer->SgList.MappedSystemVa = (PVOID)((ULONG_PTR)Transfer->SgList.MappedSystemVa + TransferOffset);
+
+        SplitTransfer->Flags |= TRANSFER_FLAG_SPLITED;
+
+        *SgOffset += MaxTransferSize;
+        TransferRemainLen -= MaxTransferSize;
+        return TransferRemainLen;
+    }
+
+    /* SgLength <= MaxTransferSize */
+    SplitTransfer->SgList.SgElementCount = 1;
+    TransferRemainLen -= SgLength;
+
+    Element0->SgOffset = 0;
+    Element0->SgTransferLength = SgLength;
+    Element0->SgPhysicalAddress.LowPart = Transfer->SgList.SgElement[*SgIdx].SgPhysicalAddress.LowPart + *SgOffset;
+
+    SplitTransfer->TransferParameters.TransferBufferLength = SgLength;
+    SplitTransfer->TransferParameters.IsTransferSplited = TRUE;
+
+    SplitTransfer->SgList.CurrentVa = Transfer->SgList.CurrentVa + TransferOffset;
+    SplitTransfer->SgList.MappedSystemVa = (PVOID)((ULONG_PTR)Transfer->SgList.MappedSystemVa + TransferOffset);
+
+    SplitTransfer->Flags |= TRANSFER_FLAG_SPLITED;
+
+    *SgOffset += SgLength;
+
+    SgRemainLen = MaxTransferSize - SgLength;
+
+    if (SgRemainLen > TransferRemainLen)
+    {
+        SgRemainLen = TransferRemainLen;
+    }
+
+    if (!SgRemainLen)
+    {
+        /* SgLength == MaxTransferSize */
+        ++*SgIdx;
+        *SgOffset = 0;
+        return TransferRemainLen;
+    }
+
+    /* SgLength < MaxTransferSize */
+
+    DPRINT1("MakeSplitTransfer: SgRemainLen - %x\n", SgRemainLen);
+    DPRINT1("MakeSplitTransfer: SgIdx - %x\n", *SgIdx);
+    ++*SgIdx;
+
+    *SgOffset = 0;
+    SplitTransfer->SgList.SgElementCount++;
+
+    Element1 = &SplitSgList->SgElement[1];
+
+    Element1->SgOffset = SgRemainLen;
+    Element1->SgTransferLength = Element0->SgTransferLength;
+    Element1->SgPhysicalAddress.LowPart = Transfer->SgList.SgElement[*SgIdx].SgPhysicalAddress.LowPart + *SgOffset;
+
+    SplitTransfer->TransferParameters.TransferBufferLength += SgRemainLen;
+
+    *SgOffset += SgRemainLen;
+    TransferRemainLen -= SgRemainLen;
+
+    return TransferRemainLen;
+}
+
+VOID
+NTAPI
+USBPORT_SplitBulkInterruptTransfer(IN PDEVICE_OBJECT FdoDevice,
+                                   IN PUSBPORT_ENDPOINT Endpoint,
+                                   IN PUSBPORT_TRANSFER Transfer,
+                                   IN PLIST_ENTRY List)
+{
+    PUSBPORT_TRANSFER SplitTransfer;
+    LIST_ENTRY tmplist;
+    ULONG NeedSplits;
+    SIZE_T TransferBufferLength;
+    SIZE_T MaxTransferSize;
+    SIZE_T TransferOffset = 0;
+    SIZE_T RemainLength;
+    ULONG ix;
+    ULONG SgIdx = 0;
+    ULONG SgOffset = 0;
+
+    DPRINT("USBPORT_SplitBulkInterruptTransfer: ... \n");
+
+    MaxTransferSize = Endpoint->EndpointProperties.TotalMaxPacketSize *
+                      (Endpoint->EndpointProperties.MaxTransferSize /
+                       Endpoint->EndpointProperties.TotalMaxPacketSize);
+
+    if (Endpoint->EndpointProperties.MaxTransferSize > PAGE_SIZE)
+    {
+        KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0);
+    }
+
+    TransferBufferLength = Transfer->TransferParameters.TransferBufferLength;
+    Transfer->Flags |= TRANSFER_FLAG_PARENT;
+
+    NeedSplits = TransferBufferLength / MaxTransferSize + 1;
+
+    InitializeListHead(&tmplist);
+
+    DPRINT1("USBPORT_SplitBulkInterruptTransfer: TransferBufferLength - %x, NeedSplits - %x\n",
+            TransferBufferLength, NeedSplits);
+
+    if (!NeedSplits)
+    {
+        DPRINT1("USBPORT_SplitBulkInterruptTransfer: DbgBreakPoint \n");
+        DbgBreakPoint();
+        goto Exit;
+    }
+
+    for (ix = 0; ix < NeedSplits; ++ix)
+    {
+        SplitTransfer = ExAllocatePoolWithTag(NonPagedPool,
+                                              Transfer->FullTransferLength,
+                                              USB_PORT_TAG);
+
+        if (!SplitTransfer)
+        {
+            DPRINT1("USBPORT_SplitBulkInterruptTransfer: DbgBreakPoint \n");
+            DbgBreakPoint();
+            goto Exit;
+        }
+
+        RtlCopyMemory(SplitTransfer, Transfer, Transfer->FullTransferLength);
+
+        SplitTransfer->MiniportTransfer = (PVOID)((ULONG_PTR)SplitTransfer +
+                                          SplitTransfer->PortTransferLength);
+
+        InsertTailList(&tmplist, &SplitTransfer->TransferLink);
+    }
+
+    if (Transfer->TransferParameters.TransferBufferLength == 0)
+    {
+        goto Exit;
+    }
+
+    RemainLength = Transfer->TransferParameters.TransferBufferLength;
+
+    do
+    {
+        SplitTransfer = CONTAINING_RECORD(tmplist.Flink,
+                                          USBPORT_TRANSFER,
+                                          TransferLink);
+
+        RemoveHeadList(&tmplist);
+
+        RemainLength = USBPORT_MakeSplitTransfer(FdoDevice,
+                                                 Transfer,
+                                                 SplitTransfer,
+                                                 MaxTransferSize,
+                                                 &SgIdx,
+                                                 &SgOffset,
+                                                 RemainLength,
+                                                 TransferOffset);
+
+        TransferOffset += SplitTransfer->TransferParameters.TransferBufferLength;
+
+        InsertTailList(List, &SplitTransfer->TransferLink);
+        InsertTailList(&Transfer->SplitTransfersList,&SplitTransfer->SplitLink);
+    }
+    while (RemainLength != 0);
+
+Exit:
+
+    while (!IsListEmpty(&tmplist))
+    {
+        DPRINT1("USBPORT_SplitBulkInterruptTransfer: ... \n");
+
+        SplitTransfer = CONTAINING_RECORD(tmplist.Flink,
+                                          USBPORT_TRANSFER,
+                                          TransferLink);
+        RemoveHeadList(&tmplist);
+
+        ExFreePoolWithTag(SplitTransfer, USB_PORT_TAG);
+    }
+
+    return;
+}
+
+VOID
+NTAPI
+USBPORT_SplitTransfer(IN PDEVICE_OBJECT FdoDevice,
+                      IN PUSBPORT_ENDPOINT Endpoint,
+                      IN PUSBPORT_TRANSFER Transfer,
+                      IN PLIST_ENTRY List)
+{
+    ULONG TransferType;
+
+    DPRINT("USBPORT_SplitTransfer ... \n");
+
+    InitializeListHead(List);
+    InitializeListHead(&Transfer->SplitTransfersList);
+
+    Transfer->USBDStatus = USBD_STATUS_SUCCESS;
+
+    if (Transfer->TransferParameters.TransferBufferLength >
+        Endpoint->EndpointProperties.MaxTransferSize)
+    {
+        TransferType = Endpoint->EndpointProperties.TransferType;
+
+        if (TransferType == USBPORT_TRANSFER_TYPE_BULK ||
+            TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
+        {
+            USBPORT_SplitBulkInterruptTransfer(FdoDevice,
+                                               Endpoint,
+                                               Transfer,
+                                               List);
+        }
+        else if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS ||
+                 TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
+        {
+            KeBugCheckEx(BUGCODE_USB_DRIVER, 1, 0, 0, 0);
+        }
+        else
+        {
+            DPRINT1("USBPORT_SplitTransfer: Unknown TransferType - %x\n",
+                    TransferType);
+        }
+    }
+    else
+    {
+        InsertTailList(List, &Transfer->TransferLink);
+    }
+}
+
+VOID
+NTAPI
+USBPORT_DoneSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer)
+{
+    PUSBPORT_TRANSFER ParentTransfer;
+    KIRQL OldIrql;
+
+    DPRINT("USBPORT_DoneSplitTransfer: ... \n");
+
+    ParentTransfer = SplitTransfer->ParentTransfer;
+    ParentTransfer->CompletedTransferLen += SplitTransfer->CompletedTransferLen;
+
+    if (SplitTransfer->USBDStatus != USBD_STATUS_SUCCESS)
+    {
+        DPRINT1("USBPORT_DoneSplitTransfer: SplitTransfer->USBDStatus - %X\n",
+                SplitTransfer->USBDStatus);
+
+        ParentTransfer->USBDStatus = SplitTransfer->USBDStatus;
+    }
+
+    KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql);
+
+    RemoveEntryList(&SplitTransfer->SplitLink);
+    ExFreePoolWithTag(SplitTransfer, USB_PORT_TAG);
+
+    if (IsListEmpty(&ParentTransfer->SplitTransfersList))
+    {
+        KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
+        USBPORT_DoneTransfer(ParentTransfer);
+    }
+    else
+    {
+        KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
+    }
+}
+
+VOID
+NTAPI
+USBPORT_CancelSplitTransfer(IN PUSBPORT_TRANSFER SplitTransfer)
+{
+    PUSBPORT_TRANSFER ParentTransfer;
+    PUSBPORT_ENDPOINT Endpoint;
+    KIRQL OldIrql;
+
+    DPRINT("USBPORT_CancelSplitTransfer \n");
+
+    Endpoint = SplitTransfer->Endpoint;
+    ParentTransfer = SplitTransfer->ParentTransfer;
+    ParentTransfer->CompletedTransferLen += SplitTransfer->CompletedTransferLen;
+
+    KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql);
+    RemoveEntryList(&SplitTransfer->SplitLink);
+    KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
+
+    ExFreePool(SplitTransfer);
+
+    if (IsListEmpty(&ParentTransfer->SplitTransfersList))
+    {
+        InsertTailList(&Endpoint->CancelList, &ParentTransfer->TransferLink);
+    }
+}
index cae479b..29ab313 100644 (file)
@@ -789,7 +789,7 @@ USBPORT_FlushDoneTransfers(IN PDEVICE_OBJECT FdoDevice)
 
             if ((Transfer->Flags & TRANSFER_FLAG_SPLITED))
             {
-                ASSERT(FALSE);// USBPORT_DoneSplitTransfer(Transfer);
+                USBPORT_DoneSplitTransfer(Transfer);
             }
             else
             {
@@ -1946,8 +1946,11 @@ USBPORT_MiniportCompleteTransfer(IN PVOID MiniPortExtension,
                                  IN ULONG TransferLength)
 {
     PUSBPORT_TRANSFER Transfer;
-    PDEVICE_OBJECT FdoDevice;
-    PUSBPORT_DEVICE_EXTENSION FdoExtension;
+    PUSBPORT_TRANSFER ParentTransfer;
+    PUSBPORT_TRANSFER SplitTransfer;
+    PLIST_ENTRY SplitHead;
+    PLIST_ENTRY Entry;
+    KIRQL OldIrql;
 
     DPRINT_CORE("USBPORT_MiniportCompleteTransfer: USBDStatus - %x, TransferLength - %x\n",
                 USBDStatus,
@@ -1957,20 +1960,47 @@ USBPORT_MiniportCompleteTransfer(IN PVOID MiniPortExtension,
                                  USBPORT_TRANSFER,
                                  TransferParameters);
 
-    FdoDevice = Transfer->Endpoint->FdoDevice;
-    FdoExtension = FdoDevice->DeviceExtension;
-
+    Transfer->Flags |= TRANSFER_FLAG_COMPLETED;
     Transfer->CompletedTransferLen = TransferLength;
 
-    RemoveEntryList(&Transfer->TransferLink);
+    if (((Transfer->Flags & TRANSFER_FLAG_SPLITED) == 0) ||
+        TransferLength >= Transfer->TransferParameters.TransferBufferLength)
+    {
+        goto Exit;
+    }
 
-    Transfer->USBDStatus = USBDStatus;
+    ParentTransfer = Transfer->ParentTransfer;
 
-    ExInterlockedInsertTailList(&FdoExtension->DoneTransferList,
-                                &Transfer->TransferLink,
-                                &FdoExtension->DoneTransferSpinLock);
+    KeAcquireSpinLock(&ParentTransfer->TransferSpinLock, &OldIrql);
 
-    KeInsertQueueDpc(&FdoExtension->TransferFlushDpc, NULL, NULL);
+    if (IsListEmpty(&ParentTransfer->SplitTransfersList))
+    {
+        goto Exit;
+    }
+
+    SplitHead = &ParentTransfer->SplitTransfersList;
+    Entry = SplitHead->Flink;
+
+    while (Entry && !IsListEmpty(SplitHead))
+    {
+        SplitTransfer = CONTAINING_RECORD(Entry,
+                                          USBPORT_TRANSFER,
+                                          SplitLink);
+
+        if (!(SplitTransfer->Flags & TRANSFER_FLAG_SUBMITED))
+        {
+            DPRINT1("USBPORT_MiniportCompleteTransfer: SplitTransfer->Flags - %X\n",
+                    SplitTransfer->Flags);
+            //Add TRANSFER_FLAG_xxx
+        }
+
+        Entry = Entry->Flink;
+    }
+
+    KeReleaseSpinLock(&ParentTransfer->TransferSpinLock, OldIrql);
+
+Exit:
+    USBPORT_QueueDoneTransfer(Transfer, USBDStatus);
 }
 
 VOID
@@ -2250,6 +2280,9 @@ USBPORT_MapTransfer(IN PDEVICE_OBJECT FdoDevice,
     SIZE_T ElementLength;
     PUSBPORT_DEVICE_HANDLE DeviceHandle;
     PDMA_OPERATIONS DmaOperations;
+    USBD_STATUS USBDStatus;
+    LIST_ENTRY List;
+    PUSBPORT_TRANSFER transfer;
 
     DPRINT_CORE("USBPORT_MapTransfer: ... \n");
 
@@ -2266,12 +2299,12 @@ USBPORT_MapTransfer(IN PDEVICE_OBJECT FdoDevice,
     Mdl = Urb->UrbControlTransfer.TransferBufferMDL;
     CurrentVa = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl);
 
-    Transfer->SgList.CurrentVa = CurrentVa;
-    Transfer->SgList.MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
-
     sgList = &Transfer->SgList;
-    sgList->Flags = 0;
 
+    sgList->Flags = 0;
+    sgList->CurrentVa = CurrentVa;
+    sgList->MappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl,
+                                                          NormalPagePriority);
     Transfer->MapRegisterBase = MapRegisterBase;
 
     ix = 0;
@@ -2337,15 +2370,52 @@ USBPORT_MapTransfer(IN PDEVICE_OBJECT FdoDevice,
     }
     while (CurrentLength != Transfer->TransferParameters.TransferBufferLength);
 
-    Transfer->SgList.SgElementCount = ix;
+    sgList->SgElementCount = ix;
+
+    if (Endpoint->EndpointProperties.DeviceSpeed == UsbHighSpeed)
+    {
+        Transfer->Flags |= TRANSFER_FLAG_HIGH_SPEED;
+    }
+
     Transfer->Flags |= TRANSFER_FLAG_DMA_MAPPED;
 
-    ASSERT(Transfer->TransferParameters.TransferBufferLength <=
-           Endpoint->EndpointProperties.MaxTransferSize);
+    if ((Transfer->Flags & TRANSFER_FLAG_ISO) == 0)
+    {
+        KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
+                          &Endpoint->EndpointOldIrql);
+
+        USBPORT_SplitTransfer(FdoDevice, Endpoint, Transfer, &List);
+
+        while (!IsListEmpty(&List))
+        {
+            transfer = CONTAINING_RECORD(List.Flink,
+                                         USBPORT_TRANSFER,
+                                         TransferLink);
+
+            RemoveHeadList(&List);
+            InsertTailList(&Endpoint->TransferList, &transfer->TransferLink);
+        }
+
+        KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
+                          Endpoint->EndpointOldIrql);
+    }
+    else
+    {
+        USBDStatus = USBPORT_InitializeIsoTransfer(FdoDevice,
+                                                   &Urb->UrbIsochronousTransfer,
+                                                   Transfer);
+
+        if (USBDStatus != USBD_STATUS_SUCCESS)
+        {
+            KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
+                              &Endpoint->EndpointOldIrql);
+
+            USBPORT_QueueDoneTransfer(Transfer, USBDStatus);
 
-    KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
-    InsertTailList(&Endpoint->TransferList, &Transfer->TransferLink);
-    KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
+            KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
+                              Endpoint->EndpointOldIrql);
+        }
+    }
 
     DeviceHandle = Urb->UrbHeader.UsbdDeviceHandle;
     InterlockedDecrement(&DeviceHandle->DeviceHandleLock);
@@ -2438,6 +2508,7 @@ USBPORT_AllocateTransfer(IN PDEVICE_OBJECT FdoDevice,
     PUSBPORT_TRANSFER Transfer;
     PUSBPORT_PIPE_HANDLE PipeHandle;
     USBD_STATUS USBDStatus;
+    SIZE_T IsoBlockLen = 0;
 
     DPRINT_CORE("USBPORT_AllocateTransfer: FdoDevice - %p, Urb - %p, DeviceHandle - %p, Irp - %p, Event - %p\n",
            FdoDevice,
@@ -2458,15 +2529,24 @@ USBPORT_AllocateTransfer(IN PDEVICE_OBJECT FdoDevice,
 
         PagesNeed = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddr,
                                                    TransferLength);
+        if (PagesNeed > 0)
+        {
+            PagesNeed--;
+        }
     }
 
     if (Urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
     {
-        DPRINT1("USBPORT_AllocateTransfer: ISOCH_TRANSFER UNIMPLEMENTED. FIXME.\n");
+        DPRINT1("USBPORT_AllocateTransfer: ISOCH_TRANSFER UNIMPLEMENTED. FIXME\n");
+
+        //IsoBlockLen = sizeof(USBPORT_ISO_BLOCK) +
+        //              Urb->UrbIsochronousTransfer.NumberOfPackets *
+        //              sizeof(USBPORT_ISO_BLOCK_PACKET);
     }
 
     PortTransferLength = sizeof(USBPORT_TRANSFER) +
-                         PagesNeed * sizeof(USBPORT_SCATTER_GATHER_ELEMENT);
+                         PagesNeed * sizeof(USBPORT_SCATTER_GATHER_ELEMENT) +
+                         IsoBlockLen;
 
     FullTransferLength = PortTransferLength +
                          FdoExtension->MiniPortInterface->Packet.MiniPortTransferSize;
@@ -2475,30 +2555,43 @@ USBPORT_AllocateTransfer(IN PDEVICE_OBJECT FdoDevice,
                                      FullTransferLength,
                                      USB_PORT_TAG);
 
-    if (Transfer)
+    if (!Transfer)
     {
-        RtlZeroMemory(Transfer, FullTransferLength);
-
-        Transfer->Irp = Irp;
-        Transfer->Urb = Urb;
-        Transfer->Endpoint = PipeHandle->Endpoint;
-        Transfer->Event = Event;
-        Transfer->PortTransferLength = PortTransferLength;
-        Transfer->FullTransferLength = FullTransferLength;
+        DPRINT1("USBPORT_AllocateTransfer: Transfer not allocated!\n");
+        return USBD_STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-        Transfer->MiniportTransfer = (PVOID)((ULONG_PTR)Transfer +
-                                             PortTransferLength);
+    RtlZeroMemory(Transfer, FullTransferLength);
 
-        Urb->UrbControlTransfer.hca.Reserved8[0] = Transfer;
-        Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_TRANSFER;
+    Transfer->Irp = Irp;
+    Transfer->Urb = Urb;
+    Transfer->Endpoint = PipeHandle->Endpoint;
+    Transfer->Event = Event;
+    Transfer->PortTransferLength = PortTransferLength;
+    Transfer->FullTransferLength = FullTransferLength;
+    Transfer->IsoBlockPtr = NULL;
+    Transfer->Period = 0;
+    Transfer->ParentTransfer = Transfer;
 
-        USBDStatus = USBD_STATUS_SUCCESS;
-    }
-    else
+    if (IsoBlockLen)
     {
-        USBDStatus = USBD_STATUS_INSUFFICIENT_RESOURCES;
+        Transfer->IsoBlockPtr = (PVOID)((ULONG_PTR)Transfer +
+                                 PortTransferLength - IsoBlockLen);
+
+        Transfer->Period = PipeHandle->Endpoint->EndpointProperties.Period;
+        Transfer->Flags |= TRANSFER_FLAG_ISO;
     }
 
+    Transfer->MiniportTransfer = (PVOID)((ULONG_PTR)Transfer +
+                                                    PortTransferLength);
+
+    KeInitializeSpinLock(&Transfer->TransferSpinLock);
+
+    Urb->UrbControlTransfer.hca.Reserved8[0] = Transfer;
+    Urb->UrbHeader.UsbdFlags |= USBD_FLAG_ALLOCATED_TRANSFER;
+
+    USBDStatus = USBD_STATUS_SUCCESS;
+
     DPRINT_CORE("USBPORT_AllocateTransfer: return USBDStatus - %x\n",
                 USBDStatus);
 
index b9ea84e..efe4412 100644 (file)
 /* Transfer Flags (USBPORT_TRANSFER) */
 #define TRANSFER_FLAG_CANCELED   0x00000001
 #define TRANSFER_FLAG_DMA_MAPPED 0x00000002
+#define TRANSFER_FLAG_HIGH_SPEED 0x00000004
 #define TRANSFER_FLAG_SUBMITED   0x00000008
 #define TRANSFER_FLAG_ABORTED    0x00000010
 #define TRANSFER_FLAG_ISO        0x00000020
 #define TRANSFER_FLAG_DEVICE_GONE 0x00000080
 #define TRANSFER_FLAG_SPLITED    0x00000100
+#define TRANSFER_FLAG_COMPLETED  0x00000200
+#define TRANSFER_FLAG_PARENT     0x00000400
 
 extern KSPIN_LOCK USBPORT_SpinLock;
 extern LIST_ENTRY USBPORT_MiniPortDrivers;
@@ -218,6 +221,8 @@ typedef struct _USBPORT_ENDPOINT {
   LIST_ENTRY FlushAbortLink;
 } USBPORT_ENDPOINT, *PUSBPORT_ENDPOINT;
 
+typedef struct _USBPORT_ISO_BLOCK *PUSBPORT_ISO_BLOCK;
+
 typedef struct _USBPORT_TRANSFER {
   ULONG Flags;
   PIRP Irp;
@@ -237,8 +242,15 @@ typedef struct _USBPORT_TRANSFER {
   PVOID MapRegisterBase;
   ULONG TimeOut;
   LARGE_INTEGER Time;
+  struct _USBPORT_TRANSFER * ParentTransfer;
+  KSPIN_LOCK TransferSpinLock;
+  LIST_ENTRY SplitTransfersList; // for parent transfers
+  LIST_ENTRY SplitLink; // for splitted transfers
+  ULONG Period;
+  PUSBPORT_ISO_BLOCK IsoBlockPtr; // pointer on IsoBlock
   // SgList should be LAST field
-  USBPORT_SCATTER_GATHER_LIST SgList; // Non IsoTransfer
+  USBPORT_SCATTER_GATHER_LIST SgList; // variable length
+  //USBPORT_ISO_BLOCK IsoBlock; // variable length
 } USBPORT_TRANSFER, *PUSBPORT_TRANSFER;
 
 typedef struct _USBPORT_IRP_TABLE {
@@ -573,6 +585,11 @@ USBPORT_InvalidateControllerHandler(
   IN PDEVICE_OBJECT FdoDevice,
   IN ULONG Type);
 
+VOID
+NTAPI
+USBPORT_DoneTransfer(
+  IN PUSBPORT_TRANSFER Transfer);
+
 /* debug.c */
 ULONG
 NTAPI
@@ -1120,6 +1137,25 @@ NTAPI
 USBPORT_RootHubPowerAndChirpAllCcPorts(
   IN PDEVICE_OBJECT FdoDevice);
 
+/* trfsplit.c */
+VOID
+NTAPI
+USBPORT_SplitTransfer(
+  IN PDEVICE_OBJECT FdoDevice,
+  IN PUSBPORT_ENDPOINT Endpoint,
+  IN PUSBPORT_TRANSFER Transfer,
+  IN PLIST_ENTRY List);
+
+VOID
+NTAPI
+USBPORT_DoneSplitTransfer(
+  IN PUSBPORT_TRANSFER SplitTransfer);
+
+VOID
+NTAPI
+USBPORT_CancelSplitTransfer(
+  IN PUSBPORT_TRANSFER SplitTransfer);
+
 /* urb.c */
 NTSTATUS
 NTAPI
index 8cb2c96..2b14bac 100644 (file)
@@ -626,16 +626,16 @@ typedef struct _USBPORT_SCATTER_GATHER_LIST {
   ULONG_PTR CurrentVa;
   PVOID MappedSystemVa;
   ULONG SgElementCount;
-  USBPORT_SCATTER_GATHER_ELEMENT SgElement[1];
+  USBPORT_SCATTER_GATHER_ELEMENT SgElement[2];
 } USBPORT_SCATTER_GATHER_LIST, *PUSBPORT_SCATTER_GATHER_LIST;
 
-C_ASSERT(sizeof(USBPORT_SCATTER_GATHER_LIST) == 24 + 4 * sizeof(PVOID));
+C_ASSERT(sizeof(USBPORT_SCATTER_GATHER_LIST) == 48 + 4 * sizeof(PVOID));
 
 typedef struct _USBPORT_TRANSFER_PARAMETERS {
   ULONG TransferFlags;
   ULONG TransferBufferLength;
   ULONG TransferCounter;
-  ULONG Reserved1;
+  BOOL IsTransferSplited;
   ULONG Reserved2;
   USB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
 } USBPORT_TRANSFER_PARAMETERS, *PUSBPORT_TRANSFER_PARAMETERS;