[USBPORT] Check Period instead Factor.
[reactos.git] / drivers / usb / usbport / usb2.c
index d1dce19..6259cf4 100644 (file)
@@ -877,8 +877,90 @@ NTAPI
 USB2_RebalanceEndpoint(IN PDEVICE_OBJECT FdoDevice,
                        IN PLIST_ENTRY List)
 {
-    DPRINT1("USB2_RebalanceEndpoint: UNIMPLEMENTED. FIXME\n");
-    ASSERT(FALSE);
+    PUSBPORT_DEVICE_EXTENSION FdoExtension;
+    PUSBPORT_REGISTRATION_PACKET Packet;
+    PUSBPORT_ENDPOINT Endpoint;
+    PLIST_ENTRY Entry;
+    ULONG AllocedBusTime;
+    ULONG EndpointBandwidth;
+    ULONG Factor;
+    ULONG ScheduleOffset;
+    ULONG Bandwidth;
+    ULONG n;
+    ULONG ix;
+    KIRQL OldIrql;
+    UCHAR NewPeriod;
+    UCHAR SMask;
+    UCHAR CMask;
+
+    FdoExtension = FdoDevice->DeviceExtension;
+    Packet = &FdoExtension->MiniPortInterface->Packet;
+
+    while (!IsListEmpty(List))
+    {
+        Entry = RemoveHeadList(List);
+
+        Endpoint = CONTAINING_RECORD(Entry,
+                                     USBPORT_ENDPOINT,
+                                     RebalanceLink.Flink);
+
+        DPRINT("USB2_RebalanceEndpoint: Endpoint - %p\n", Endpoint);
+
+        Endpoint->RebalanceLink.Flink = NULL;
+        Endpoint->RebalanceLink.Blink = NULL;
+
+        KeAcquireSpinLock(&Endpoint->EndpointSpinLock,
+                          &Endpoint->EndpointOldIrql);
+
+        SMask = USB2_GetSMASK(Endpoint->TtEndpoint);
+        CMask = USB2_GetCMASK(Endpoint->TtEndpoint);
+
+        ScheduleOffset = Endpoint->TtEndpoint->StartFrame;
+        NewPeriod = Endpoint->TtEndpoint->ActualPeriod;
+
+        AllocedBusTime = Endpoint->TtEndpoint->CalcBusTime;
+        EndpointBandwidth = USB2_MICROFRAMES * AllocedBusTime;
+
+        Endpoint->EndpointProperties.InterruptScheduleMask = SMask;
+        Endpoint->EndpointProperties.SplitCompletionMask = CMask;
+
+        if (Endpoint->EndpointProperties.Period != NewPeriod)
+        {
+            Factor = USB2_FRAMES / Endpoint->EndpointProperties.Period;
+            ASSERT(Factor);
+
+            for (ix = 0; ix < Factor; ix++)
+            {
+                Bandwidth = Endpoint->EndpointProperties.UsbBandwidth;
+                n = Factor * Endpoint->EndpointProperties.ScheduleOffset;
+                Endpoint->TtExtension->Bandwidth[n + ix] += Bandwidth;
+            }
+
+            Endpoint->EndpointProperties.Period = NewPeriod;
+            Endpoint->EndpointProperties.ScheduleOffset = ScheduleOffset;
+            Endpoint->EndpointProperties.UsbBandwidth = EndpointBandwidth;
+
+            Factor = USB2_FRAMES / NewPeriod;
+            ASSERT(Factor);
+
+            for (ix = 0; ix < Factor; ix++)
+            {
+                n = Factor * ScheduleOffset;
+                Endpoint->TtExtension->Bandwidth[n + ix] += EndpointBandwidth;
+            }
+        }
+
+        KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
+
+        Packet->RebalanceEndpoint(FdoExtension->MiniPortExt,
+                                  &Endpoint->EndpointProperties,
+                                  (PVOID)((ULONG_PTR)Endpoint + sizeof(USBPORT_ENDPOINT)));
+
+        KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
+
+        KeReleaseSpinLock(&Endpoint->EndpointSpinLock,
+                          Endpoint->EndpointOldIrql);
+    }
 }
 
 VOID
@@ -975,19 +1057,32 @@ USB2_DeallocateEndpointBudget(IN PUSB2_TT_ENDPOINT TtEndpoint,
     PUSB2_TT Tt;
     PUSB2_HC_EXTENSION HcExtension;
     ULONG Speed;
+    ULONG TransferType;
+    ULONG Frame;
     ULONG StartMicroframe;
     ULONG ix;
-
+    PUSB2_TT_ENDPOINT endpoint;
+    PUSB2_TT_ENDPOINT nextEndpoint;
+    PUSB2_TT_ENDPOINT lastEndpoint;
+    PUSB2_TT_ENDPOINT tmpEndpoint;
+    ULONG endTime;
+    ULONG maxEndTime;
+    ULONG lastEndTime;
+    ULONG Factor;
+    ULONG jx;
     UCHAR frame;
     UCHAR uframe;
+    USHORT Period;
+    BOOLEAN IsMoved = FALSE;
 
-    DPRINT("USB2_DeallocateEndpointBudget: TtEndpoint - %p, MaxFrames - %X\n",
+    DPRINT("USB2_DeallocateEndpointBudget: TtEndpoint - %p, MaxFrames - %X, CalcBusTime - %X\n",
            TtEndpoint,
-           MaxFrames);
+           MaxFrames,
+           TtEndpoint->CalcBusTime);
 
     if (TtEndpoint->CalcBusTime == 0)
     {
-        DPRINT("USB2_DeallocateEndpointBudget: endpoint not allocated\n");//error((int)"endpoint not allocated");
+        DPRINT("USB2_DeallocateEndpointBudget: TtEndpoint not allocated!\n");
         return FALSE;
     }
 
@@ -1020,10 +1115,204 @@ USB2_DeallocateEndpointBudget(IN PUSB2_TT_ENDPOINT TtEndpoint,
 
     /* Speed != UsbHighSpeed (FS/LS) */
 
-    DPRINT("USB2_DeallocateEndpointBudget: UNIMPLEMENTED FIXME\n");
-    ASSERT(FALSE);
+    TransferType = TtEndpoint->TtEndpointParams.TransferType;
+
+    for (ix = MaxFrames, Frame = (MaxFrames - 1) - TtEndpoint->StartFrame;
+         ix > 0;
+         ix--, Frame--)
+    {
+        frame = TtEndpoint->StartFrame + Frame;
+
+        DPRINT("USB2_DeallocateEndpointBudget: frame - %X, Frame - %X, StartFrame - %X\n",
+               frame,
+               Frame,
+               TtEndpoint->StartFrame);
+
+        if ((Frame % TtEndpoint->ActualPeriod) == 0)
+        {
+            USB2_DeallocateHS(TtEndpoint, Frame);
+            Tt->FrameBudget[frame].TimeUsed -= TtEndpoint->CalcBusTime;
+        }
+
+        if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
+        {
+            endpoint = Tt->FrameBudget[frame].IntEndpoint;
+        }
+        else
+        {
+            endpoint = Tt->FrameBudget[frame].IsoEndpoint;
+        }
+
+        nextEndpoint = endpoint->NextTtEndpoint;
+
+        DPRINT("USB2_DeallocateEndpointBudget: TtEndpoint - %p, nextEndpoint - %p\n",
+               TtEndpoint,
+               nextEndpoint);
+
+        if (TtEndpoint->CalcBusTime > (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
+        {
+            while (nextEndpoint)
+            {
+                endpoint = nextEndpoint;
+                nextEndpoint = nextEndpoint->NextTtEndpoint;
+            }
+
+            nextEndpoint = TtEndpoint;
+
+            DPRINT("USB2_DeallocateEndpointBudget: endpoint - %p, nextEndpoint - %p\n",
+                   endpoint,
+                   nextEndpoint);
+        }
+        else
+        {
+            while (nextEndpoint &&
+                   !USB2_CheckTtEndpointInsert(nextEndpoint, TtEndpoint))
+            {
+                endpoint = nextEndpoint;
+                nextEndpoint = nextEndpoint->NextTtEndpoint;
+            }
+
+            if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS &&
+                nextEndpoint)
+            {
+                DPRINT1("USB2_DeallocateEndpointBudget: Iso Ep UNIMPLEMENTED. FIXME\n");
+                ASSERT(FALSE);
+            }
+
+            DPRINT("USB2_DeallocateEndpointBudget: endpoint - %p, nextEndpoint - %p\n",
+                   endpoint,
+                   nextEndpoint);
+        }
+
+        if ((Frame % TtEndpoint->ActualPeriod) == 0)
+        {
+            if (TtEndpoint->CalcBusTime > (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
+            {
+                Tt->FrameBudget[frame].AltEndpoint = NULL;
+            }
+            else if (nextEndpoint)
+            {
+                nextEndpoint = nextEndpoint->NextTtEndpoint;
+                endpoint->NextTtEndpoint = nextEndpoint;
+
+                DPRINT("USB2_DeallocateEndpointBudget: endpoint - %p, nextEndpoint - %p\n",
+                       endpoint,
+                       nextEndpoint);
+            }
+        }
+
+        if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
+        {
+            if (endpoint == Tt->FrameBudget[frame].IntEndpoint)
+            {
+                if (Tt->FrameBudget[frame].IsoEndpoint->NextTtEndpoint)
+                {
+                    endpoint = Tt->FrameBudget[frame].IsoEndpoint->NextTtEndpoint;
+                    DPRINT("USB2_DeallocateEndpointBudget: endpoint - %p\n", endpoint);
+                }
+                else if (Tt->FrameBudget[frame].AltEndpoint)
+                {
+                    endpoint = Tt->FrameBudget[frame].AltEndpoint;
+                    DPRINT("USB2_DeallocateEndpointBudget: endpoint - %p\n", endpoint);
+                }
+            }
+        }
+        else
+        {
+            DPRINT1("USB2_DeallocateEndpointBudget: Iso Ep UNIMPLEMENTED. FIXME\n");
+            ASSERT(FALSE);
+        }
+
+        Period = TtEndpoint->ActualPeriod;
+
+        for (;
+             nextEndpoint;
+             endpoint = nextEndpoint,
+             nextEndpoint = nextEndpoint->NextTtEndpoint)
+        {
+            DPRINT("USB2_DeallocateEndpointBudget: endpoint - %p, nextEndpoint - %p\n",
+                   endpoint,
+                   nextEndpoint);
+
+            endTime = endpoint->StartTime + endpoint->CalcBusTime;
+            maxEndTime = endTime;
+
+            if (Period > nextEndpoint->ActualPeriod ||
+                TtEndpoint->StartFrame != nextEndpoint->StartFrame)
+            {
+                if (USB2_CommonFrames(nextEndpoint, TtEndpoint))
+                    Factor = Period / nextEndpoint->ActualPeriod;
+                else
+                    Factor = USB2_FRAMES / nextEndpoint->ActualPeriod;
+
+                maxEndTime = endTime;
+
+                for (jx = 0, frame = nextEndpoint->StartFrame;
+                     jx < Factor;
+                     jx++, frame += nextEndpoint->ActualPeriod)
+                {
+                    if (nextEndpoint->StartFrame != TtEndpoint->StartFrame)
+                    {
+                        lastEndpoint = Tt->FrameBudget[frame].IntEndpoint;
+
+                        if (Tt->FrameBudget[frame].IsoEndpoint->NextTtEndpoint)
+                        {
+                            lastEndpoint = Tt->FrameBudget[frame].IsoEndpoint->NextTtEndpoint;
+                        }
+                        else if (Tt->FrameBudget[frame].AltEndpoint)
+                        {
+                            lastEndpoint = Tt->FrameBudget[frame].AltEndpoint;
+                        }
+
+                        for (tmpEndpoint = Tt->FrameBudget[frame].IntEndpoint->NextTtEndpoint;
+                             tmpEndpoint && tmpEndpoint != nextEndpoint;
+                             tmpEndpoint = tmpEndpoint->NextTtEndpoint)
+                        {
+                            lastEndpoint = tmpEndpoint;
+                        }
+
+                        lastEndTime = lastEndpoint->StartTime + lastEndpoint->CalcBusTime;
+
+                        if (endTime < (lastEndTime - 1))
+                        {
+                            maxEndTime = lastEndTime;
+                            endTime = maxEndTime;
+
+                            if (nextEndpoint->StartTime == maxEndTime)
+                                break;
+                        }
+                        else
+                        {
+                            maxEndTime = endTime;
+                        }
+                    }
+                }
+            }
+
+            if (maxEndTime >= nextEndpoint->StartTime)
+                break;
+
+            if (!USB2_MoveTtEndpoint(nextEndpoint,
+                                     maxEndTime - nextEndpoint->StartTime,
+                                     Rebalance,
+                                     *RebalanceListEntries,
+                                     &IsMoved))
+            {
+                if (!IsMoved)
+                {
+                    DPRINT("USB2_DeallocateEndpointBudget: Not moved!\n");
+                }
+
+                break;
+            }
+
+            if (Period > nextEndpoint->ActualPeriod)
+                Period = nextEndpoint->ActualPeriod;
+        }
+    }
 
     TtEndpoint->CalcBusTime = 0;
+
     DPRINT("USB2_DeallocateEndpointBudget: return TRUE\n");
     return TRUE;
 }
@@ -1384,14 +1673,132 @@ USB2_AllocateTimeForEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
     return Result;
 }
 
+BOOLEAN
+NTAPI
+USB2_ChangePeriod(IN PUSB2_TT_ENDPOINT TtEndpoint,
+                  IN PUSB2_REBALANCE Rebalance,
+                  IN PULONG RebalanceListEntries)
+{
+    BOOLEAN Result;
+
+    DPRINT("USB2_ChangePeriod: RebalanceListEntries - %X\n",
+           *RebalanceListEntries);
+
+    USB2_DeallocateEndpointBudget(TtEndpoint,
+                                  Rebalance,
+                                  RebalanceListEntries,
+                                  USB2_FRAMES);
+
+    TtEndpoint->PreviosPeriod = TtEndpoint->Period;
+    TtEndpoint->Period = ENDPOINT_INTERRUPT_1ms;
+
+    Result = USB2_AllocateTimeForEndpoint(TtEndpoint,
+                                          Rebalance,
+                                          RebalanceListEntries);
+
+    return Result;
+}
+
 BOOLEAN
 NTAPI
 USB2_PromotePeriods(IN PUSB2_TT_ENDPOINT TtEndpoint,
                     IN PUSB2_REBALANCE Rebalance,
                     IN PULONG RebalanceListEntries)
 {
-    DPRINT1("USB2_PromotePeriods: UNIMPLEMENTED. FIXME\n");
-    ASSERT(FALSE);
+    PUSB2_TT_ENDPOINT ttEndpoint;
+    ULONG TransferType;
+    ULONG ix;
+
+    TransferType = TtEndpoint->TtEndpointParams.TransferType;
+
+    if (TtEndpoint->ActualPeriod != ENDPOINT_INTERRUPT_1ms &&
+        TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT &&
+        (CHAR)TtEndpoint->StartMicroframe > 2 &&
+        !USB2_ChangePeriod(TtEndpoint, Rebalance, RebalanceListEntries))
+    {
+        DPRINT("USB2_PromotePeriods: return FALSE\n");
+        return FALSE;
+    }
+
+    if (Rebalance->RebalanceEndpoint[0] == NULL)
+    {
+        DPRINT("USB2_PromotePeriods: return TRUE\n");
+        return TRUE;
+    }
+
+    DPRINT("USB2_PromotePeriods: RebalanceListEntries - %X\n",
+           *RebalanceListEntries);
+
+    for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
+    {
+        Rebalance->RebalanceEndpoint[ix]->IsPromoted = FALSE;
+    }
+
+    for (ix = 0; ; ix++)
+    {
+        ttEndpoint = Rebalance->RebalanceEndpoint[ix];
+        TransferType = ttEndpoint->TtEndpointParams.TransferType;
+
+        if (ttEndpoint->ActualPeriod != ENDPOINT_INTERRUPT_1ms &&
+            TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT &&
+            ttEndpoint->StartMicroframe > 2)
+        {
+            USB2_DeallocateEndpointBudget(ttEndpoint,
+                                          Rebalance,
+                                          RebalanceListEntries,
+                                          USB2_FRAMES);
+
+            ttEndpoint->IsPromoted = TRUE;
+            ttEndpoint->PreviosPeriod = ttEndpoint->Period;
+            ttEndpoint->Period = ENDPOINT_INTERRUPT_1ms;
+
+            if (!USB2_AllocateTimeForEndpoint(ttEndpoint,
+                                              Rebalance,
+                                              RebalanceListEntries))
+            {
+                break;
+            }
+        }
+
+        if (Rebalance->RebalanceEndpoint[ix + 1] == NULL)
+        {
+            DPRINT("USB2_PromotePeriods: return TRUE\n");
+            return TRUE;
+        }
+    }
+
+    USB2_DeallocateEndpointBudget(TtEndpoint,
+                                  Rebalance,
+                                  RebalanceListEntries,
+                                  USB2_FRAMES);
+
+    TtEndpoint->Period = TtEndpoint->PreviosPeriod;
+    TtEndpoint->PreviosPeriod = 0;
+
+    for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
+    {
+        ttEndpoint = Rebalance->RebalanceEndpoint[ix];
+
+        if (ttEndpoint->IsPromoted)
+        {
+            if (ttEndpoint->CalcBusTime)
+            {
+                USB2_DeallocateEndpointBudget(ttEndpoint,
+                                              Rebalance,
+                                              RebalanceListEntries,
+                                              USB2_FRAMES);
+            }
+
+            TtEndpoint->Period = TtEndpoint->PreviosPeriod;
+            TtEndpoint->PreviosPeriod = 0;
+
+            USB2_AllocateTimeForEndpoint(ttEndpoint,
+                                         Rebalance,
+                                         RebalanceListEntries);
+        }
+    }
+
+    DPRINT("USB2_PromotePeriods: return FALSE\n");
     return FALSE;
 }
 
@@ -1681,7 +2088,122 @@ NTAPI
 USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
                           IN PUSBPORT_ENDPOINT Endpoint)
 {
-    DPRINT1("USBPORT_FreeBandwidthUSB2: UNIMPLEMENTED. FIXME. \n");
+    PUSBPORT_DEVICE_EXTENSION FdoExtension;
+    ULONG Period;
+    ULONG ScheduleOffset;
+    ULONG EndpointBandwidth;
+    LIST_ENTRY RebalanceList;
+    ULONG TransferType;
+    PUSB2_REBALANCE Rebalance;
+    ULONG RebalanceListEntries;
+    ULONG Factor;
+    ULONG ix;
+    ULONG n;
+    PUSB2_TT_EXTENSION TtExtension;
+    PUSB2_TT_ENDPOINT RebalanceTtEndpoint;
+
+    DPRINT("USBPORT_FreeBandwidthUSB2: Endpoint - %p\n", Endpoint);
+
+    FdoExtension = FdoDevice->DeviceExtension;
+
+    Period = Endpoint->EndpointProperties.Period;
+    ASSERT(Period != 0);
+
+    ScheduleOffset = Endpoint->EndpointProperties.ScheduleOffset;
+    EndpointBandwidth = Endpoint->EndpointProperties.UsbBandwidth;
+
+    InitializeListHead(&RebalanceList);
+
+    TransferType = Endpoint->EndpointProperties.TransferType;
+
+    if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
+        TransferType == USBPORT_TRANSFER_TYPE_BULK ||
+        (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0))
+    {
+        return;
+    }
+
+    Rebalance = ExAllocatePoolWithTag(NonPagedPool,
+                                      sizeof(USB2_REBALANCE),
+                                      USB_PORT_TAG);
+
+    if (!Rebalance)
+    {
+        DPRINT1("USBPORT_FreeBandwidthUSB2: Rebalance == NULL!\n");
+        return;
+    }
+
+    RtlZeroMemory(Rebalance, sizeof(USB2_REBALANCE));
+
+    Factor = USB2_FRAMES / Period;
+    n = ScheduleOffset * Factor;
+
+    TtExtension = Endpoint->TtExtension;
+
+    if (TtExtension)
+    {
+        for (ix = 0; ix < Factor; ix++)
+        {
+            TtExtension->Bandwidth[n + ix] += EndpointBandwidth;
+        }
+    }
+    else
+    {
+        for (ix = 1; ix < Factor; ix++)
+        {
+            FdoExtension->Bandwidth[n + ix] += EndpointBandwidth;
+        }
+    }
+
+    RebalanceListEntries = USB2_FRAMES - 2;
+
+    USB2_DeallocateEndpointBudget(Endpoint->TtEndpoint,
+                                  Rebalance,
+                                  &RebalanceListEntries,
+                                  USB2_FRAMES);
+
+    RebalanceListEntries = 0;
+
+    for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
+    {
+        RebalanceListEntries = ix + 1;
+    }
+
+    for (ix = 0; ix < RebalanceListEntries; ix++)
+    {
+        RebalanceTtEndpoint = Rebalance->RebalanceEndpoint[ix];
+
+        DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceTtEndpoint[%X] - %p, RebalanceTtEndpoint - %p, RebalanceLink - %p\n",
+               ix,
+               RebalanceTtEndpoint,
+               &RebalanceTtEndpoint->Endpoint->RebalanceLink);
+
+        InsertTailList(&RebalanceList,
+                       &RebalanceTtEndpoint->Endpoint->RebalanceLink);
+    }
+
+    ExFreePoolWithTag(Rebalance, USB_PORT_TAG);
+
+    USB2_Rebalance(FdoDevice, &RebalanceList);
+
+    if (!TtExtension)
+    {
+        return;
+    }
+
+    for (ix = 0; ix < USB2_FRAMES; ix++)
+    {
+        FdoExtension->Bandwidth[ix] += TtExtension->MaxBandwidth;
+    }
+
+    USBPORT_UpdateAllocatedBwTt(TtExtension);
+
+    for (ix = 0; ix < USB2_FRAMES; ix++)
+    {
+        FdoExtension->Bandwidth[ix] -= TtExtension->MaxBandwidth;
+    }
+
+    DPRINT1("USBPORT_FreeBandwidthUSB2: exit\n");
 }
 
 VOID