mirror of
https://github.com/reactos/reactos.git
synced 2024-11-19 13:33:42 +00:00
2237 lines
64 KiB
C
2237 lines
64 KiB
C
/*
|
|
* PROJECT: ReactOS USB Port Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: USBPort USB 2.0 functions
|
|
* COPYRIGHT: Copyright 2017 Vadim Galyant <vgal@rambler.ru>
|
|
*/
|
|
|
|
#include "usbport.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
static const UCHAR CMASKS[USB2_MICROFRAMES] = {
|
|
0x1C, 0x38, 0x70, 0xE0, 0xC1, 0x83, 0x07, 0x0E
|
|
};
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_AllocateCheck(IN OUT PULONG OutTimeUsed,
|
|
IN ULONG CalcBusTime,
|
|
IN ULONG LimitAllocation)
|
|
{
|
|
ULONG BusTime;
|
|
BOOLEAN Result = TRUE;
|
|
|
|
BusTime = *OutTimeUsed + CalcBusTime;
|
|
*OutTimeUsed += CalcBusTime;
|
|
|
|
if (BusTime > LimitAllocation)
|
|
{
|
|
DPRINT("USB2_AllocateCheck: BusTime > LimitAllocation\n");
|
|
Result = FALSE;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
USHORT
|
|
NTAPI
|
|
USB2_AddDataBitStuff(IN USHORT DataTime)
|
|
{
|
|
return (DataTime + (DataTime / 16));
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_IncMicroFrame(OUT PUCHAR frame,
|
|
OUT PUCHAR uframe)
|
|
{
|
|
++*uframe;
|
|
|
|
if (*uframe > (USB2_MICROFRAMES - 1))
|
|
{
|
|
*uframe = 0;
|
|
*frame = (*frame + 1) & (USB2_FRAMES - 1);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_GetPrevMicroFrame(OUT PUCHAR frame,
|
|
OUT PUCHAR uframe)
|
|
{
|
|
*uframe = USB2_MICROFRAMES - 1;
|
|
|
|
if (*frame)
|
|
--*frame;
|
|
else
|
|
*frame = USB2_FRAMES - 1;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_CheckTtEndpointInsert(IN PUSB2_TT_ENDPOINT nextTtEndpoint,
|
|
IN PUSB2_TT_ENDPOINT TtEndpoint)
|
|
{
|
|
ULONG TransferType;
|
|
|
|
DPRINT("USB2_CheckTtEndpointInsert: nextTtEndpoint - %p, TtEndpoint - %p\n",
|
|
nextTtEndpoint,
|
|
TtEndpoint);
|
|
|
|
ASSERT(TtEndpoint);
|
|
|
|
if (TtEndpoint->CalcBusTime >= (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
|
|
{
|
|
DPRINT1("USB2_CheckTtEndpointInsert: Result - FALSE\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!nextTtEndpoint)
|
|
{
|
|
DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
|
|
if (nextTtEndpoint->ActualPeriod < TtEndpoint->ActualPeriod &&
|
|
TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
|
|
{
|
|
DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
if ((nextTtEndpoint->ActualPeriod <= TtEndpoint->ActualPeriod &&
|
|
TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS) ||
|
|
nextTtEndpoint == TtEndpoint)
|
|
{
|
|
DPRINT("USB2_CheckTtEndpointInsert: Result - TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
DPRINT("USB2_CheckTtEndpointInsert: Result - FALSE\n");
|
|
return FALSE;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
USB2_GetOverhead(IN PUSB2_TT_ENDPOINT TtEndpoint)
|
|
{
|
|
ULONG TransferType;
|
|
ULONG Direction;
|
|
ULONG DeviceSpeed;
|
|
ULONG Overhead;
|
|
ULONG HostDelay;
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
Direction = TtEndpoint->TtEndpointParams.Direction;
|
|
DeviceSpeed = TtEndpoint->TtEndpointParams.DeviceSpeed;
|
|
|
|
HostDelay = TtEndpoint->Tt->HcExtension->HcDelayTime;
|
|
|
|
if (DeviceSpeed == UsbHighSpeed)
|
|
{
|
|
if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
|
|
{
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
Overhead = HostDelay + USB2_HS_ISOCHRONOUS_OUT_OVERHEAD;
|
|
else
|
|
Overhead = HostDelay + USB2_HS_INTERRUPT_OUT_OVERHEAD;
|
|
}
|
|
else
|
|
{
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
Overhead = HostDelay + USB2_HS_ISOCHRONOUS_IN_OVERHEAD;
|
|
else
|
|
Overhead = HostDelay + USB2_HS_INTERRUPT_IN_OVERHEAD;
|
|
}
|
|
}
|
|
else if (DeviceSpeed == UsbFullSpeed)
|
|
{
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
Overhead = HostDelay + USB2_FS_ISOCHRONOUS_OVERHEAD;
|
|
else
|
|
Overhead = HostDelay + USB2_FS_INTERRUPT_OVERHEAD;
|
|
}
|
|
else
|
|
{
|
|
Overhead = HostDelay + USB2_LS_INTERRUPT_OVERHEAD;
|
|
}
|
|
|
|
return Overhead;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_GetHsOverhead(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN PULONG OverheadSS,
|
|
IN PULONG OverheadCS)
|
|
{
|
|
ULONG TransferType;
|
|
ULONG Direction;
|
|
ULONG HostDelay;
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
Direction = TtEndpoint->TtEndpointParams.Direction;
|
|
|
|
HostDelay = TtEndpoint->Tt->HcExtension->HcDelayTime;
|
|
|
|
if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
|
|
{
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
{
|
|
*OverheadSS = HostDelay + USB2_HS_SS_ISOCHRONOUS_OUT_OVERHEAD;
|
|
*OverheadCS = 0;
|
|
}
|
|
else
|
|
{
|
|
*OverheadSS = HostDelay + USB2_HS_SS_INTERRUPT_OUT_OVERHEAD;
|
|
*OverheadCS = HostDelay + USB2_HS_CS_INTERRUPT_OUT_OVERHEAD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
{
|
|
*OverheadSS = HostDelay + USB2_HS_SS_ISOCHRONOUS_IN_OVERHEAD;
|
|
*OverheadCS = HostDelay + USB2_HS_CS_ISOCHRONOUS_IN_OVERHEAD;
|
|
}
|
|
else
|
|
{
|
|
*OverheadSS = HostDelay + USB2_HS_SS_INTERRUPT_IN_OVERHEAD;
|
|
*OverheadCS = HostDelay + USB2_HS_CS_INTERRUPT_IN_OVERHEAD;
|
|
}
|
|
}
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
USB2_GetLastIsoTime(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN ULONG Frame)
|
|
{
|
|
PUSB2_TT_ENDPOINT nextTtEndpoint;
|
|
ULONG Result;
|
|
|
|
//DPRINT("USB2_GetLastIsoTime: TtEndpoint - %p, Frame - %X\n",
|
|
// TtEndpoint,
|
|
// Frame);
|
|
|
|
nextTtEndpoint = TtEndpoint->Tt->FrameBudget[Frame].IsoEndpoint->NextTtEndpoint;
|
|
|
|
if (nextTtEndpoint ||
|
|
(nextTtEndpoint = TtEndpoint->Tt->FrameBudget[Frame].AltEndpoint) != NULL)
|
|
{
|
|
Result = nextTtEndpoint->StartTime + nextTtEndpoint->CalcBusTime;
|
|
}
|
|
else
|
|
{
|
|
Result = USB2_FS_SOF_TIME;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
USB2_GetStartTime(IN PUSB2_TT_ENDPOINT nextTtEndpoint,
|
|
IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN PUSB2_TT_ENDPOINT prevTtEndpoint,
|
|
IN ULONG Frame)
|
|
{
|
|
PUSB2_TT_ENDPOINT ttEndpoint;
|
|
ULONG TransferType;
|
|
|
|
DPRINT("USB2_GetStartTime: nextTtEndpoint - %p, TtEndpoint - %p, prevTtEndpoint - %p, Frame - %X\n",
|
|
nextTtEndpoint,
|
|
TtEndpoint,
|
|
prevTtEndpoint,
|
|
Frame);
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
{
|
|
if (nextTtEndpoint)
|
|
return nextTtEndpoint->StartTime + nextTtEndpoint->CalcBusTime;
|
|
|
|
ttEndpoint = TtEndpoint->Tt->FrameBudget[Frame].AltEndpoint;
|
|
|
|
if (ttEndpoint)
|
|
return ttEndpoint->StartTime + ttEndpoint->CalcBusTime;
|
|
else
|
|
return USB2_FS_SOF_TIME;
|
|
}
|
|
else
|
|
{
|
|
ttEndpoint = prevTtEndpoint;
|
|
|
|
if (ttEndpoint == TtEndpoint->Tt->FrameBudget[Frame].IntEndpoint)
|
|
return USB2_GetLastIsoTime(TtEndpoint, Frame);
|
|
else
|
|
return ttEndpoint->StartTime + ttEndpoint->CalcBusTime;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_InitTtEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN UCHAR TransferType,
|
|
IN UCHAR Direction,
|
|
IN UCHAR DeviceSpeed,
|
|
IN USHORT Period,
|
|
IN USHORT MaxPacketSize,
|
|
IN PUSB2_TT Tt)
|
|
{
|
|
TtEndpoint->TtEndpointParams.TransferType = TransferType;
|
|
TtEndpoint->TtEndpointParams.Direction = Direction;
|
|
TtEndpoint->TtEndpointParams.DeviceSpeed = DeviceSpeed;
|
|
|
|
TtEndpoint->Period = Period;
|
|
TtEndpoint->MaxPacketSize = MaxPacketSize;
|
|
TtEndpoint->Tt = Tt;
|
|
|
|
TtEndpoint->CalcBusTime = 0;
|
|
TtEndpoint->StartTime = 0;
|
|
TtEndpoint->ActualPeriod = 0;
|
|
TtEndpoint->StartFrame = 0;
|
|
TtEndpoint->StartMicroframe = 0;
|
|
|
|
TtEndpoint->Nums.AsULONG = 0;
|
|
TtEndpoint->NextTtEndpoint = NULL;
|
|
TtEndpoint->Reserved2 = 0;
|
|
TtEndpoint->PreviosPeriod = 0;
|
|
TtEndpoint->IsPromoted = FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_AllocateHS(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN LONG Frame)
|
|
{
|
|
PUSB2_HC_EXTENSION HcExtension;
|
|
PUSB2_TT Tt;
|
|
ULONG TransferType;
|
|
ULONG Direction;
|
|
ULONG DataTime;
|
|
ULONG DataSize;
|
|
ULONG RemainDataTime;
|
|
ULONG OverheadCS;
|
|
ULONG OverheadSS;
|
|
ULONG ix;
|
|
USHORT PktSize;
|
|
USHORT PktSizeBitStuff;
|
|
UCHAR frame;
|
|
UCHAR uframe;
|
|
BOOL Result = TRUE;
|
|
|
|
DPRINT("USB2_AllocateHS: TtEndpoint - %p, Frame - %X, StartFrame - %X\n",
|
|
TtEndpoint,
|
|
Frame,
|
|
TtEndpoint->StartFrame);
|
|
|
|
Tt = TtEndpoint->Tt;
|
|
HcExtension = Tt->HcExtension;
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
Direction = TtEndpoint->TtEndpointParams.Direction;
|
|
|
|
if (Frame == 0)
|
|
{
|
|
TtEndpoint->StartMicroframe =
|
|
TtEndpoint->StartTime / USB2_FS_RAW_BYTES_IN_MICROFRAME - 1;
|
|
|
|
DPRINT("USB2_AllocateHS: TtEndpoint->StartMicroframe - %X\n",
|
|
TtEndpoint->StartMicroframe);
|
|
}
|
|
|
|
USB2_GetHsOverhead(TtEndpoint, &OverheadSS, &OverheadCS);
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
|
|
{
|
|
if (Frame == 0)
|
|
{
|
|
TtEndpoint->Nums.NumStarts = 1;
|
|
|
|
if ((CHAR)TtEndpoint->StartMicroframe < (USB2_MICROFRAMES - 3))
|
|
TtEndpoint->Nums.NumCompletes = 3;
|
|
else
|
|
TtEndpoint->Nums.NumCompletes = 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
|
|
{
|
|
DPRINT("USB2_AllocateHS: ISO UNIMPLEMENTED\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
else
|
|
{
|
|
DPRINT("USB2_AllocateHS: ISO UNIMPLEMENTED\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe;
|
|
|
|
if (TtEndpoint->StartMicroframe == USB2_PREV_MICROFRAME)
|
|
USB2_GetPrevMicroFrame(&frame, &uframe);
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumStarts; ix++)
|
|
{
|
|
if (!USB2_AllocateCheck(&HcExtension->TimeUsed[frame][uframe],
|
|
OverheadSS,
|
|
USB2_MAX_MICROFRAME_ALLOCATION))
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (Tt->NumStartSplits[frame][uframe] >
|
|
(USB2_MAX_FS_LS_TRANSACTIONS_IN_UFRAME - 1))
|
|
{
|
|
DPRINT1("USB2_AllocateHS: Num Start Splits - %X\n",
|
|
Tt->NumStartSplits[frame][uframe] + 1);
|
|
|
|
ASSERT(FALSE);
|
|
Result = FALSE;
|
|
}
|
|
|
|
++Tt->NumStartSplits[frame][uframe];
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
}
|
|
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe + TtEndpoint->Nums.NumStarts + 1;
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumCompletes; ix++)
|
|
{
|
|
if (!USB2_AllocateCheck(&HcExtension->TimeUsed[frame][uframe],
|
|
OverheadCS,
|
|
USB2_MAX_MICROFRAME_ALLOCATION))
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
}
|
|
|
|
PktSize = TtEndpoint->MaxPacketSize;
|
|
PktSizeBitStuff = USB2_AddDataBitStuff(PktSize);
|
|
|
|
if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
|
|
{
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe;
|
|
|
|
if (uframe == USB2_PREV_MICROFRAME)
|
|
USB2_GetPrevMicroFrame(&frame, &uframe);
|
|
|
|
DataTime = 0;
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumStarts; ix++)
|
|
{
|
|
DataSize = PktSizeBitStuff - DataTime;
|
|
|
|
if (DataSize <= USB2_FS_RAW_BYTES_IN_MICROFRAME)
|
|
DataTime = DataSize;
|
|
else
|
|
DataTime = USB2_FS_RAW_BYTES_IN_MICROFRAME;
|
|
|
|
DPRINT("USB2_AllocateHS: ix - %X, frame - %X, uframe - %X, TimeUsed - %X\n",
|
|
ix,
|
|
frame,
|
|
uframe,
|
|
HcExtension->TimeUsed[frame][uframe]);
|
|
|
|
if (!USB2_AllocateCheck(&HcExtension->TimeUsed[frame][uframe],
|
|
DataTime,
|
|
USB2_MAX_MICROFRAME_ALLOCATION))
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
DataTime += USB2_FS_RAW_BYTES_IN_MICROFRAME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe + TtEndpoint->Nums.NumStarts + 1;
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumCompletes; ix++)
|
|
{
|
|
if (Tt->TimeCS[frame][uframe] < USB2_FS_RAW_BYTES_IN_MICROFRAME)
|
|
{
|
|
RemainDataTime = USB2_FS_RAW_BYTES_IN_MICROFRAME -
|
|
Tt->TimeCS[frame][uframe];
|
|
|
|
if (RemainDataTime >= PktSizeBitStuff)
|
|
{
|
|
DataTime = PktSizeBitStuff;
|
|
}
|
|
else if (RemainDataTime > 0)
|
|
{
|
|
DataTime = RemainDataTime;
|
|
}
|
|
else
|
|
{
|
|
DataTime = 0;
|
|
}
|
|
|
|
if (!USB2_AllocateCheck(&HcExtension->TimeUsed[frame][uframe],
|
|
DataTime,
|
|
USB2_MAX_MICROFRAME_ALLOCATION))
|
|
{
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
|
|
if (PktSizeBitStuff < USB2_FS_RAW_BYTES_IN_MICROFRAME)
|
|
Tt->TimeCS[frame][uframe] += PktSizeBitStuff;
|
|
else
|
|
Tt->TimeCS[frame][uframe] += USB2_FS_RAW_BYTES_IN_MICROFRAME;
|
|
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
}
|
|
}
|
|
|
|
DPRINT("USB2_AllocateHS: Result - %X\n", Result);
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_DeallocateHS(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN ULONG Frame)
|
|
{
|
|
PUSB2_TT Tt;
|
|
PUSB2_HC_EXTENSION HcExtension;
|
|
ULONG OverheadCS;
|
|
ULONG OverheadSS;
|
|
ULONG Direction;
|
|
ULONG ix;
|
|
ULONG CurrentDataTime;
|
|
ULONG RemainDataTime;
|
|
ULONG DataTime;
|
|
ULONG DataSize;
|
|
USHORT PktSize;
|
|
USHORT PktSizeBitStuff;
|
|
UCHAR uframe;
|
|
UCHAR frame;
|
|
|
|
DPRINT("USB2_DeallocateHS: TtEndpoint - %p, Frame - %X\n",
|
|
TtEndpoint,
|
|
Frame);
|
|
|
|
Tt = TtEndpoint->Tt;
|
|
HcExtension = Tt->HcExtension;
|
|
|
|
USB2_GetHsOverhead(TtEndpoint, &OverheadSS, &OverheadCS);
|
|
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe;
|
|
|
|
if (TtEndpoint->StartMicroframe == USB2_PREV_MICROFRAME)
|
|
USB2_GetPrevMicroFrame(&frame, &uframe);
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumStarts; ix++)
|
|
{
|
|
HcExtension->TimeUsed[frame][uframe] -= OverheadSS;
|
|
--Tt->NumStartSplits[frame][uframe];
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
}
|
|
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe + TtEndpoint->Nums.NumStarts + 1;
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumCompletes; ix++)
|
|
{
|
|
HcExtension->TimeUsed[frame][uframe] -= OverheadCS;
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
}
|
|
|
|
Direction = TtEndpoint->TtEndpointParams.Direction;
|
|
PktSize = TtEndpoint->MaxPacketSize;
|
|
PktSizeBitStuff = USB2_AddDataBitStuff(PktSize);
|
|
|
|
if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
|
|
{
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe;
|
|
|
|
if (TtEndpoint->StartMicroframe == USB2_PREV_MICROFRAME)
|
|
USB2_GetPrevMicroFrame(&frame, &uframe);
|
|
|
|
DataTime = 0;
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumStarts; ix++)
|
|
{
|
|
DataSize = PktSizeBitStuff - DataTime;
|
|
|
|
if (DataSize <= USB2_FS_RAW_BYTES_IN_MICROFRAME)
|
|
CurrentDataTime = PktSizeBitStuff - DataTime;
|
|
else
|
|
CurrentDataTime = USB2_FS_RAW_BYTES_IN_MICROFRAME;
|
|
|
|
HcExtension->TimeUsed[frame][uframe] -= CurrentDataTime;
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
DataTime += USB2_FS_RAW_BYTES_IN_MICROFRAME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
frame = TtEndpoint->StartFrame + Frame;
|
|
uframe = TtEndpoint->StartMicroframe + TtEndpoint->Nums.NumStarts + 1;
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumCompletes; ix++)
|
|
{
|
|
if (PktSizeBitStuff >= USB2_FS_RAW_BYTES_IN_MICROFRAME)
|
|
CurrentDataTime = USB2_FS_RAW_BYTES_IN_MICROFRAME;
|
|
else
|
|
CurrentDataTime = PktSizeBitStuff;
|
|
|
|
Tt->TimeCS[frame][uframe] -= CurrentDataTime;
|
|
|
|
if (Tt->TimeCS[frame][uframe] < USB2_FS_RAW_BYTES_IN_MICROFRAME)
|
|
{
|
|
RemainDataTime = USB2_FS_RAW_BYTES_IN_MICROFRAME -
|
|
Tt->TimeCS[frame][uframe];
|
|
|
|
if (RemainDataTime >= PktSizeBitStuff)
|
|
RemainDataTime = PktSizeBitStuff;
|
|
|
|
HcExtension->TimeUsed[frame][uframe] -= RemainDataTime;
|
|
}
|
|
|
|
USB2_IncMicroFrame(&frame, &uframe);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_MoveTtEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN LONG BusTime,
|
|
IN PUSB2_REBALANCE Rebalance,
|
|
IN ULONG RebalanceListEntries,
|
|
OUT BOOLEAN * OutResult)
|
|
{
|
|
ULONG EndBusTime;
|
|
ULONG TransferType;
|
|
ULONG Num;
|
|
UCHAR ix;
|
|
|
|
DPRINT("USB2_MoveTtEndpoint: TtEndpoint - %p, BusTime - %X\n",
|
|
TtEndpoint,
|
|
BusTime);
|
|
|
|
*OutResult = TRUE;
|
|
|
|
for (Num = 0; Rebalance->RebalanceEndpoint[Num]; Num++)
|
|
{
|
|
if (Rebalance->RebalanceEndpoint[Num] == TtEndpoint)
|
|
break;
|
|
}
|
|
|
|
DPRINT("USB2_MoveTtEndpoint: Num - %X\n", Num);
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
|
|
if (Rebalance->RebalanceEndpoint[Num] &&
|
|
TtEndpoint->TtEndpointParams.EndpointMoved == TRUE &&
|
|
((TransferType != USBPORT_TRANSFER_TYPE_INTERRUPT) || BusTime >= 0))
|
|
{
|
|
DPRINT("USB2_MoveTtEndpoint: result - FALSE\n");
|
|
return FALSE;
|
|
}
|
|
|
|
for (ix = 0;
|
|
(TtEndpoint->StartFrame + ix) < USB2_FRAMES;
|
|
ix += TtEndpoint->ActualPeriod)
|
|
{
|
|
USB2_DeallocateHS(TtEndpoint, ix);
|
|
}
|
|
|
|
TtEndpoint->StartTime += BusTime;
|
|
|
|
EndBusTime = TtEndpoint->StartTime + TtEndpoint->CalcBusTime;
|
|
|
|
if (EndBusTime > USB2_FS_MAX_PERIODIC_ALLOCATION)
|
|
{
|
|
DPRINT("USB2_MoveTtEndpoint: EndBusTime is too large!\n");
|
|
*OutResult = FALSE;
|
|
}
|
|
|
|
TtEndpoint->TtEndpointParams.EndpointMoved = TRUE;
|
|
|
|
if (Rebalance->RebalanceEndpoint[Num] == NULL)
|
|
{
|
|
if (Num >= RebalanceListEntries)
|
|
{
|
|
DPRINT("USB2_MoveTtEndpoint: Too many changes!\n");
|
|
*OutResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
Rebalance->RebalanceEndpoint[Num] = TtEndpoint;
|
|
Rebalance->RebalanceEndpoint[Num + 1] = NULL;
|
|
}
|
|
}
|
|
|
|
for (ix = 0;
|
|
(TtEndpoint->StartFrame + ix) < USB2_FRAMES;
|
|
ix += TtEndpoint->ActualPeriod)
|
|
{
|
|
if (!USB2_AllocateHS(TtEndpoint, ix))
|
|
{
|
|
DPRINT("USB2_MoveTtEndpoint: OutResult - FALSE\n");
|
|
OutResult = FALSE;
|
|
}
|
|
}
|
|
|
|
DPRINT("USB2_MoveTtEndpoint: result - TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_CommonFrames(IN PUSB2_TT_ENDPOINT NextTtEndpoint,
|
|
IN PUSB2_TT_ENDPOINT TtEndpoint)
|
|
{
|
|
UCHAR Frame;
|
|
|
|
DPRINT("USB2_CommonFrames: \n");
|
|
|
|
if (NextTtEndpoint->ActualPeriod == ENDPOINT_INTERRUPT_1ms ||
|
|
TtEndpoint->ActualPeriod == ENDPOINT_INTERRUPT_1ms)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (NextTtEndpoint->ActualPeriod < TtEndpoint->ActualPeriod)
|
|
Frame = TtEndpoint->StartFrame % TtEndpoint->ActualPeriod;
|
|
else
|
|
Frame = NextTtEndpoint->StartFrame % TtEndpoint->ActualPeriod;
|
|
|
|
return (Frame == TtEndpoint->StartFrame);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_ConvertFrame(IN UCHAR Frame,
|
|
IN UCHAR Microframe,
|
|
OUT PUCHAR HcFrame,
|
|
OUT PUCHAR HcMicroframe)
|
|
{
|
|
DPRINT("USB2_ConvertFrame: Frame - %x, Microframe - %x\n",
|
|
Frame,
|
|
Microframe);
|
|
|
|
if (Microframe == USB2_PREV_MICROFRAME)
|
|
{
|
|
*HcFrame = Frame;
|
|
*HcMicroframe = 0;
|
|
}
|
|
|
|
if (Microframe <= (USB2_MICROFRAMES - 2))
|
|
{
|
|
*HcFrame = Frame;
|
|
*HcMicroframe = Microframe + 1;
|
|
}
|
|
|
|
if (Microframe == (USB2_MICROFRAMES - 1))
|
|
{
|
|
*HcFrame = Frame + 1;
|
|
*HcMicroframe = 0;
|
|
}
|
|
}
|
|
|
|
UCHAR
|
|
NTAPI
|
|
USB2_GetSMASK(IN PUSB2_TT_ENDPOINT TtEndpoint)
|
|
{
|
|
ULONG ix;
|
|
UCHAR SMask = 0;
|
|
UCHAR HcFrame;
|
|
UCHAR HcMicroFrame;
|
|
|
|
if (TtEndpoint->TtEndpointParams.DeviceSpeed == UsbHighSpeed)
|
|
{
|
|
SMask = (1 << TtEndpoint->StartMicroframe);
|
|
}
|
|
else
|
|
{
|
|
USB2_ConvertFrame(TtEndpoint->StartFrame,
|
|
TtEndpoint->StartMicroframe,
|
|
&HcFrame,
|
|
&HcMicroFrame);
|
|
|
|
for (ix = 0; ix < TtEndpoint->Nums.NumStarts; ix++)
|
|
{
|
|
SMask |= (1 << HcMicroFrame);
|
|
HcMicroFrame++;
|
|
}
|
|
}
|
|
|
|
return SMask;
|
|
}
|
|
|
|
UCHAR
|
|
NTAPI
|
|
USB2_GetCMASK(IN PUSB2_TT_ENDPOINT TtEndpoint)
|
|
{
|
|
ULONG NumCompletes;
|
|
ULONG TransferType;
|
|
ULONG DeviceSpeed;
|
|
ULONG Direction;
|
|
UCHAR Result;
|
|
UCHAR MicroFrameCS;
|
|
UCHAR HcFrame;
|
|
UCHAR HcMicroFrame;
|
|
UCHAR MaskCS = 0;
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
DeviceSpeed = TtEndpoint->TtEndpointParams.DeviceSpeed;
|
|
Direction = TtEndpoint->TtEndpointParams.Direction;
|
|
|
|
if (DeviceSpeed == UsbHighSpeed)
|
|
return 0;
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_INTERRUPT)
|
|
{
|
|
USB2_ConvertFrame(TtEndpoint->StartFrame,
|
|
TtEndpoint->StartMicroframe,
|
|
&HcFrame,
|
|
&HcMicroFrame);
|
|
|
|
Result = CMASKS[HcMicroFrame];
|
|
}
|
|
else
|
|
{
|
|
if (Direction == USBPORT_TRANSFER_DIRECTION_OUT)
|
|
return 0;
|
|
|
|
USB2_ConvertFrame(TtEndpoint->StartFrame,
|
|
TtEndpoint->StartMicroframe,
|
|
&HcFrame,
|
|
&HcMicroFrame);
|
|
|
|
NumCompletes = TtEndpoint->Nums.NumCompletes;
|
|
|
|
for (MicroFrameCS = HcMicroFrame + 2;
|
|
MicroFrameCS < USB2_MICROFRAMES;
|
|
MicroFrameCS++)
|
|
{
|
|
MaskCS |= (1 << MicroFrameCS);
|
|
NumCompletes--;
|
|
|
|
if (!NumCompletes)
|
|
return MaskCS;
|
|
}
|
|
|
|
for (; NumCompletes; NumCompletes--)
|
|
{
|
|
MaskCS |= (1 << (MicroFrameCS - USB2_MICROFRAMES));
|
|
}
|
|
|
|
Result = MaskCS;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_RebalanceEndpoint(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PLIST_ENTRY List)
|
|
{
|
|
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)
|
|
{
|
|
ASSERT(Endpoint->EndpointProperties.Period);
|
|
Factor = USB2_FRAMES / Endpoint->EndpointProperties.Period;
|
|
|
|
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;
|
|
|
|
ASSERT(NewPeriod);
|
|
Factor = USB2_FRAMES / NewPeriod;
|
|
|
|
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
|
|
NTAPI
|
|
USB2_Rebalance(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PLIST_ENTRY RebalanceList)
|
|
{
|
|
PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
|
|
PUSBPORT_ENDPOINT Endpoint;
|
|
PLIST_ENTRY Entry;
|
|
LIST_ENTRY BalanceListInt1;
|
|
LIST_ENTRY BalanceListInt2;
|
|
ULONG TransferType;
|
|
ULONG ScheduleOffset;
|
|
UCHAR SMask;
|
|
UCHAR CMask;
|
|
UCHAR ActualPeriod;
|
|
|
|
DPRINT("USB2_Rebalance: FdoDevice - %p, RebalanceList - %p\n",
|
|
FdoDevice,
|
|
RebalanceList);
|
|
|
|
InitializeListHead(&BalanceListInt1);
|
|
InitializeListHead(&BalanceListInt2);
|
|
|
|
while (!IsListEmpty(RebalanceList))
|
|
{
|
|
Entry = RebalanceList->Flink;
|
|
|
|
Endpoint = CONTAINING_RECORD(Entry,
|
|
USBPORT_ENDPOINT,
|
|
RebalanceLink.Flink);
|
|
|
|
DPRINT("USBPORT_Rebalance: Entry - %p, Endpoint - %p\n",
|
|
Entry,
|
|
Endpoint);
|
|
|
|
RemoveHeadList(RebalanceList);
|
|
Entry->Flink = NULL;
|
|
Entry->Blink = NULL;
|
|
|
|
SMask = USB2_GetSMASK(Endpoint->TtEndpoint);
|
|
CMask = USB2_GetCMASK(Endpoint->TtEndpoint);
|
|
|
|
ScheduleOffset = Endpoint->TtEndpoint->StartFrame;
|
|
ActualPeriod = Endpoint->TtEndpoint->ActualPeriod;
|
|
|
|
EndpointProperties = &Endpoint->EndpointProperties;
|
|
TransferType = EndpointProperties->TransferType;
|
|
|
|
switch (TransferType)
|
|
{
|
|
case USBPORT_TRANSFER_TYPE_ISOCHRONOUS:
|
|
DPRINT("USBPORT_Rebalance: USBPORT_TRANSFER_TYPE_ISOCHRONOUS. FIXME\n");
|
|
ASSERT(FALSE);
|
|
break;
|
|
|
|
case USBPORT_TRANSFER_TYPE_INTERRUPT:
|
|
if (SMask != EndpointProperties->InterruptScheduleMask ||
|
|
CMask != EndpointProperties->SplitCompletionMask ||
|
|
ScheduleOffset != EndpointProperties->ScheduleOffset ||
|
|
ActualPeriod != EndpointProperties->Period)
|
|
{
|
|
if (ActualPeriod == EndpointProperties->Period &&
|
|
ScheduleOffset == EndpointProperties->ScheduleOffset)
|
|
{
|
|
InsertTailList(&BalanceListInt1, Entry);
|
|
}
|
|
else
|
|
{
|
|
InsertTailList(&BalanceListInt2, Entry);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
USB2_RebalanceEndpoint(FdoDevice, &BalanceListInt2);
|
|
USB2_RebalanceEndpoint(FdoDevice, &BalanceListInt1);
|
|
//USB2_RebalanceEndpoint(FdoDevice, &BalanceListIso);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_DeallocateEndpointBudget(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN PUSB2_REBALANCE Rebalance,
|
|
IN PULONG RebalanceListEntries,
|
|
IN ULONG MaxFrames)
|
|
{
|
|
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, CalcBusTime - %X\n",
|
|
TtEndpoint,
|
|
MaxFrames,
|
|
TtEndpoint->CalcBusTime);
|
|
|
|
if (TtEndpoint->CalcBusTime == 0)
|
|
{
|
|
DPRINT("USB2_DeallocateEndpointBudget: TtEndpoint not allocated!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
Tt = TtEndpoint->Tt;
|
|
HcExtension = Tt->HcExtension;
|
|
|
|
Speed = TtEndpoint->TtEndpointParams.DeviceSpeed;
|
|
DPRINT("USB2_DeallocateEndpointBudget: DeviceSpeed - %X\n", Speed);
|
|
|
|
StartMicroframe = TtEndpoint->StartFrame * USB2_MICROFRAMES +
|
|
TtEndpoint->StartMicroframe;
|
|
|
|
if (Speed == UsbHighSpeed)
|
|
{
|
|
for (ix = StartMicroframe;
|
|
ix < USB2_MAX_MICROFRAMES;
|
|
ix += TtEndpoint->ActualPeriod)
|
|
{
|
|
frame = ix / USB2_MICROFRAMES;
|
|
uframe = ix % (USB2_MICROFRAMES - 1);
|
|
|
|
HcExtension->TimeUsed[frame][uframe] -= TtEndpoint->CalcBusTime;
|
|
}
|
|
|
|
TtEndpoint->CalcBusTime = 0;
|
|
|
|
DPRINT("USB2_DeallocateEndpointBudget: return TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
/* Speed != UsbHighSpeed (FS/LS) */
|
|
|
|
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;
|
|
}
|
|
else if (Tt->FrameBudget[frame].AltEndpoint)
|
|
{
|
|
endpoint = Tt->FrameBudget[frame].AltEndpoint;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USB2_AllocateTimeForEndpoint(IN PUSB2_TT_ENDPOINT TtEndpoint,
|
|
IN PUSB2_REBALANCE Rebalance,
|
|
IN PULONG RebalanceListEntries)
|
|
{
|
|
PUSB2_TT Tt;
|
|
PUSB2_HC_EXTENSION HcExtension;
|
|
ULONG Speed;
|
|
ULONG TimeUsed;
|
|
ULONG MinTimeUsed;
|
|
ULONG ix;
|
|
ULONG frame;
|
|
ULONG uframe;
|
|
ULONG Microframe;
|
|
ULONG TransferType;
|
|
ULONG Overhead;
|
|
ULONG LatestStart;
|
|
PUSB2_TT_ENDPOINT prevEndpoint;
|
|
PUSB2_TT_ENDPOINT nextEndpoint;
|
|
PUSB2_TT_ENDPOINT IntEndpoint;
|
|
ULONG StartTime;
|
|
ULONG calcBusTime;
|
|
BOOLEAN Result = TRUE;
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: TtEndpoint - %p\n", TtEndpoint);
|
|
|
|
Tt = TtEndpoint->Tt;
|
|
HcExtension = Tt->HcExtension;
|
|
|
|
TtEndpoint->Nums.NumStarts = 0;
|
|
TtEndpoint->Nums.NumCompletes = 0;
|
|
|
|
TtEndpoint->StartFrame = 0;
|
|
TtEndpoint->StartMicroframe = 0;
|
|
|
|
if (TtEndpoint->CalcBusTime)
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: TtEndpoint already allocated!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
Speed = TtEndpoint->TtEndpointParams.DeviceSpeed;
|
|
|
|
if (Speed == UsbHighSpeed)
|
|
{
|
|
if (TtEndpoint->Period > USB2_MAX_MICROFRAMES)
|
|
TtEndpoint->ActualPeriod = USB2_MAX_MICROFRAMES;
|
|
else
|
|
TtEndpoint->ActualPeriod = TtEndpoint->Period;
|
|
|
|
MinTimeUsed = HcExtension->TimeUsed[0][0];
|
|
|
|
for (ix = 1; ix < TtEndpoint->ActualPeriod; ix++)
|
|
{
|
|
frame = ix / USB2_MICROFRAMES;
|
|
uframe = ix % (USB2_MICROFRAMES - 1);
|
|
|
|
TimeUsed = HcExtension->TimeUsed[frame][uframe];
|
|
|
|
if (TimeUsed < MinTimeUsed)
|
|
{
|
|
MinTimeUsed = TimeUsed;
|
|
TtEndpoint->StartFrame = frame;
|
|
TtEndpoint->StartMicroframe = uframe;
|
|
}
|
|
}
|
|
|
|
TtEndpoint->CalcBusTime = USB2_GetOverhead(TtEndpoint) +
|
|
USB2_AddDataBitStuff(TtEndpoint->MaxPacketSize);
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: StartFrame - %X, StartMicroframe - %X, CalcBusTime - %X\n",
|
|
TtEndpoint->StartFrame,
|
|
TtEndpoint->StartMicroframe,
|
|
TtEndpoint->CalcBusTime);
|
|
|
|
Microframe = TtEndpoint->StartFrame * USB2_MICROFRAMES +
|
|
TtEndpoint->StartMicroframe;
|
|
|
|
if (Microframe >= USB2_MAX_MICROFRAMES)
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: Microframe >= 256. Result - TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
for (ix = Microframe;
|
|
ix < USB2_MAX_MICROFRAMES;
|
|
ix += TtEndpoint->ActualPeriod)
|
|
{
|
|
frame = ix / USB2_MICROFRAMES;
|
|
uframe = ix % (USB2_MICROFRAMES - 1);
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: frame - %X, uframe - %X, TimeUsed[f][uf] - %X\n",
|
|
frame,
|
|
uframe,
|
|
HcExtension->TimeUsed[frame][uframe]);
|
|
|
|
if (!USB2_AllocateCheck(&HcExtension->TimeUsed[frame][uframe],
|
|
TtEndpoint->CalcBusTime,
|
|
USB2_MAX_MICROFRAME_ALLOCATION))
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: Result = FALSE\n");
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!Result)
|
|
{
|
|
for (ix = Microframe;
|
|
ix < USB2_MAX_MICROFRAMES;
|
|
ix += TtEndpoint->ActualPeriod)
|
|
{
|
|
frame = ix / USB2_MICROFRAMES;
|
|
uframe = ix % (USB2_MICROFRAMES - 1);
|
|
|
|
HcExtension->TimeUsed[frame][uframe] -= TtEndpoint->CalcBusTime;
|
|
}
|
|
}
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: Result - TRUE\n");
|
|
return TRUE;
|
|
}
|
|
|
|
/* Speed != UsbHighSpeed (FS/LS) */
|
|
|
|
if (TtEndpoint->Period > USB2_FRAMES)
|
|
TtEndpoint->ActualPeriod = USB2_FRAMES;
|
|
else
|
|
TtEndpoint->ActualPeriod = TtEndpoint->Period;
|
|
|
|
MinTimeUsed = Tt->FrameBudget[0].TimeUsed;
|
|
|
|
for (ix = 1; ix < TtEndpoint->ActualPeriod; ix++)
|
|
{
|
|
if ((Tt->FrameBudget[ix].TimeUsed) < MinTimeUsed)
|
|
{
|
|
MinTimeUsed = Tt->FrameBudget[ix].TimeUsed;
|
|
TtEndpoint->StartFrame = ix;
|
|
}
|
|
}
|
|
|
|
TransferType = TtEndpoint->TtEndpointParams.TransferType;
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
{
|
|
if (Speed == UsbFullSpeed)
|
|
{
|
|
Overhead = USB2_FS_ISOCHRONOUS_OVERHEAD + Tt->DelayTime;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: ISO can not be on a LS bus!\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Speed == UsbFullSpeed)
|
|
Overhead = USB2_FS_INTERRUPT_OVERHEAD + Tt->DelayTime;
|
|
else
|
|
Overhead = USB2_LS_INTERRUPT_OVERHEAD + Tt->DelayTime;
|
|
}
|
|
|
|
if (Speed == UsbLowSpeed)
|
|
TtEndpoint->CalcBusTime = TtEndpoint->MaxPacketSize * 8 + Overhead;
|
|
else
|
|
TtEndpoint->CalcBusTime = TtEndpoint->MaxPacketSize + Overhead;
|
|
|
|
LatestStart = USB2_HUB_DELAY + USB2_FS_SOF_TIME;
|
|
|
|
for (ix = 0;
|
|
(TtEndpoint->StartFrame + ix) < USB2_FRAMES;
|
|
ix += TtEndpoint->ActualPeriod)
|
|
{
|
|
frame = TtEndpoint->StartFrame + ix;
|
|
|
|
if (Tt->FrameBudget[frame].AltEndpoint &&
|
|
TtEndpoint->CalcBusTime >= (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: return FALSE\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
prevEndpoint = Tt->FrameBudget[frame].IsoEndpoint;
|
|
else
|
|
prevEndpoint = Tt->FrameBudget[frame].IntEndpoint;
|
|
|
|
for (nextEndpoint = prevEndpoint->NextTtEndpoint;
|
|
nextEndpoint;
|
|
nextEndpoint = nextEndpoint->NextTtEndpoint)
|
|
{
|
|
if (USB2_CheckTtEndpointInsert(nextEndpoint, TtEndpoint))
|
|
break;
|
|
|
|
prevEndpoint = nextEndpoint;
|
|
}
|
|
|
|
StartTime = USB2_GetStartTime(nextEndpoint,
|
|
TtEndpoint,
|
|
prevEndpoint,
|
|
frame);
|
|
|
|
LatestStart = max(LatestStart, StartTime);
|
|
}
|
|
|
|
TtEndpoint->StartTime = LatestStart;
|
|
|
|
if ((LatestStart + TtEndpoint->CalcBusTime) > USB2_FS_MAX_PERIODIC_ALLOCATION)
|
|
{
|
|
TtEndpoint->CalcBusTime = 0;
|
|
DPRINT("USB2_AllocateTimeForEndpoint: return FALSE\n");
|
|
return FALSE;
|
|
}
|
|
|
|
for (ix = 0, frame = -TtEndpoint->StartFrame;
|
|
ix < USB2_FRAMES;
|
|
ix++, frame++)
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: ix - %X, frame - %X, StartFrame - %X\n",
|
|
ix,
|
|
frame,
|
|
TtEndpoint->StartFrame);
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_ISOCHRONOUS)
|
|
{
|
|
DPRINT1("USB2_AllocateTimeForEndpoint: Iso Ep UNIMPLEMENTED. FIXME\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
else
|
|
{
|
|
IntEndpoint = Tt->FrameBudget[ix].IntEndpoint;
|
|
nextEndpoint = IntEndpoint->NextTtEndpoint;
|
|
|
|
for (nextEndpoint = IntEndpoint->NextTtEndpoint;
|
|
nextEndpoint;
|
|
nextEndpoint = nextEndpoint->NextTtEndpoint)
|
|
{
|
|
if (USB2_CheckTtEndpointInsert(nextEndpoint, TtEndpoint))
|
|
break;
|
|
IntEndpoint = nextEndpoint;
|
|
}
|
|
|
|
if ((frame % TtEndpoint->ActualPeriod) == 0)
|
|
{
|
|
calcBusTime = 0;
|
|
}
|
|
else
|
|
{
|
|
if (nextEndpoint)
|
|
{
|
|
calcBusTime = LatestStart + TtEndpoint->CalcBusTime -
|
|
nextEndpoint->StartTime;
|
|
}
|
|
else
|
|
{
|
|
calcBusTime = TtEndpoint->CalcBusTime;
|
|
}
|
|
|
|
if (calcBusTime > 0)
|
|
{
|
|
TimeUsed = Tt->FrameBudget[ix].TimeUsed;
|
|
|
|
if (!USB2_AllocateCheck(&TimeUsed,
|
|
calcBusTime,
|
|
USB2_FS_MAX_PERIODIC_ALLOCATION))
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: Result = FALSE\n");
|
|
Result = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nextEndpoint != TtEndpoint)
|
|
{
|
|
if ((frame % TtEndpoint->ActualPeriod) == 0)
|
|
{
|
|
if (frame == 0)
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: frame == 0\n");
|
|
TtEndpoint->NextTtEndpoint = nextEndpoint;
|
|
}
|
|
|
|
IntEndpoint->NextTtEndpoint = TtEndpoint;
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: TtEndpoint - %p, nextEndpoint - %p\n",
|
|
TtEndpoint,
|
|
nextEndpoint);
|
|
}
|
|
|
|
if (calcBusTime > 0)
|
|
{
|
|
BOOLEAN IsMoved;
|
|
BOOLEAN MoveResult;
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: nextEndpoint - %p, calcBusTime - %X\n",
|
|
nextEndpoint,
|
|
calcBusTime);
|
|
|
|
for (;
|
|
nextEndpoint;
|
|
nextEndpoint = nextEndpoint->NextTtEndpoint)
|
|
{
|
|
MoveResult = USB2_MoveTtEndpoint(nextEndpoint,
|
|
calcBusTime,
|
|
Rebalance,
|
|
*RebalanceListEntries,
|
|
&IsMoved);
|
|
|
|
if (!IsMoved)
|
|
{
|
|
DPRINT("USB2_AllocateTimeForEndpoint: Result = FALSE\n");
|
|
Result = FALSE;
|
|
}
|
|
|
|
if (!MoveResult)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((frame % TtEndpoint->ActualPeriod) == 0)
|
|
{
|
|
if (!USB2_AllocateHS(TtEndpoint, frame))
|
|
{
|
|
DPRINT1("USB2_AllocateTimeForEndpoint: USB2_AllocateHS return FALSE\n");
|
|
Result = FALSE;
|
|
}
|
|
|
|
Tt->FrameBudget[ix].TimeUsed += TtEndpoint->CalcBusTime;
|
|
}
|
|
|
|
if (Result == FALSE)
|
|
{
|
|
USB2_DeallocateEndpointBudget(TtEndpoint,
|
|
Rebalance,
|
|
RebalanceListEntries,
|
|
ix + 1);
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: return FALSE\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
DPRINT("USB2_AllocateTimeForEndpoint: Result - %X\n", Result);
|
|
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)
|
|
{
|
|
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 &&
|
|
(CHAR)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;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBPORT_UpdateAllocatedBwTt(IN PUSB2_TT_EXTENSION TtExtension)
|
|
{
|
|
ULONG BusBandwidth;
|
|
ULONG NewBusBandwidth;
|
|
ULONG MaxBusBandwidth = 0;
|
|
ULONG MinBusBandwidth;
|
|
ULONG ix;
|
|
|
|
DPRINT("USBPORT_UpdateAllocatedBwTt: TtExtension - %p\n", TtExtension);
|
|
|
|
BusBandwidth = TtExtension->BusBandwidth;
|
|
MinBusBandwidth = BusBandwidth;
|
|
|
|
for (ix = 0; ix < USB2_FRAMES; ix++)
|
|
{
|
|
NewBusBandwidth = BusBandwidth - TtExtension->Bandwidth[ix];
|
|
|
|
MaxBusBandwidth = max(MaxBusBandwidth, NewBusBandwidth);
|
|
MinBusBandwidth = min(MinBusBandwidth, NewBusBandwidth);
|
|
}
|
|
|
|
TtExtension->MaxBandwidth = MaxBusBandwidth;
|
|
|
|
if (MinBusBandwidth == BusBandwidth)
|
|
TtExtension->MinBandwidth = 0;
|
|
else
|
|
TtExtension->MinBandwidth = MinBusBandwidth;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
USBPORT_AllocateBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PUSBPORT_ENDPOINT Endpoint)
|
|
{
|
|
PUSBPORT_DEVICE_EXTENSION FdoExtension;
|
|
PUSBPORT_ENDPOINT_PROPERTIES EndpointProperties;
|
|
PUSB2_TT_EXTENSION TtExtension;
|
|
ULONG TransferType;
|
|
PUSB2_REBALANCE Rebalance;
|
|
LIST_ENTRY RebalanceList;
|
|
ULONG RebalanceListEntries;
|
|
PUSB2_TT_ENDPOINT TtEndpoint;
|
|
PUSB2_TT_ENDPOINT RebalanceTtEndpoint;
|
|
PUSB2_TT Tt;
|
|
USB_DEVICE_SPEED DeviceSpeed;
|
|
ULONG Period;
|
|
ULONG AllocedBusTime;
|
|
ULONG EndpointBandwidth;
|
|
ULONG ScheduleOffset;
|
|
ULONG Factor;
|
|
ULONG ix;
|
|
ULONG n;
|
|
BOOLEAN Direction;
|
|
UCHAR SMask;
|
|
UCHAR CMask;
|
|
UCHAR ActualPeriod;
|
|
BOOLEAN Result;
|
|
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: FdoDevice - %p, Endpoint - %p\n",
|
|
FdoDevice,
|
|
Endpoint);
|
|
|
|
EndpointProperties = &Endpoint->EndpointProperties;
|
|
EndpointProperties->ScheduleOffset = 0;
|
|
|
|
if (Endpoint->Flags & ENDPOINT_FLAG_ROOTHUB_EP0)
|
|
{
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: ENDPOINT_FLAG_ROOTHUB_EP0\n");
|
|
return TRUE;
|
|
}
|
|
|
|
FdoExtension = FdoDevice->DeviceExtension;
|
|
|
|
TransferType = EndpointProperties->TransferType;
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: TransferType - %X\n", TransferType);
|
|
|
|
if (TransferType == USBPORT_TRANSFER_TYPE_CONTROL ||
|
|
TransferType == USBPORT_TRANSFER_TYPE_BULK)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (Endpoint->TtExtension)
|
|
TtExtension = Endpoint->TtExtension;
|
|
else
|
|
TtExtension = NULL;
|
|
|
|
InitializeListHead(&RebalanceList);
|
|
|
|
Rebalance = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(USB2_REBALANCE),
|
|
USB_PORT_TAG);
|
|
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: Rebalance - %p, TtExtension - %p\n",
|
|
Rebalance,
|
|
TtExtension);
|
|
|
|
if (Rebalance)
|
|
{
|
|
RtlZeroMemory(Rebalance, sizeof(USB2_REBALANCE));
|
|
|
|
TtEndpoint = Endpoint->TtEndpoint;
|
|
TtEndpoint->Endpoint = Endpoint;
|
|
|
|
Direction = EndpointProperties->Direction == USBPORT_TRANSFER_DIRECTION_OUT;
|
|
DeviceSpeed = EndpointProperties->DeviceSpeed;
|
|
|
|
switch (DeviceSpeed)
|
|
{
|
|
case UsbLowSpeed:
|
|
case UsbFullSpeed:
|
|
{
|
|
Tt = &TtExtension->Tt;
|
|
Period = USB2_FRAMES;
|
|
|
|
while (Period > 0 && Period > EndpointProperties->Period)
|
|
{
|
|
Period >>= 1;
|
|
}
|
|
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: Period - %X\n", Period);
|
|
break;
|
|
}
|
|
|
|
case UsbHighSpeed:
|
|
{
|
|
Tt = &FdoExtension->Usb2Extension->HcTt;
|
|
Period = EndpointProperties->Period;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPRINT1("USBPORT_AllocateBandwidthUSB2: DeviceSpeed - %X!\n",
|
|
DeviceSpeed);
|
|
|
|
DbgBreakPoint();
|
|
|
|
Tt = &TtExtension->Tt;
|
|
break;
|
|
}
|
|
}
|
|
|
|
USB2_InitTtEndpoint(TtEndpoint,
|
|
TransferType,
|
|
Direction,
|
|
DeviceSpeed,
|
|
Period,
|
|
EndpointProperties->MaxPacketSize,
|
|
Tt);
|
|
|
|
RebalanceListEntries = USB2_FRAMES - 2;
|
|
|
|
Result = USB2_AllocateTimeForEndpoint(TtEndpoint,
|
|
Rebalance,
|
|
&RebalanceListEntries);
|
|
|
|
if (Result)
|
|
{
|
|
Result = USB2_PromotePeriods(TtEndpoint,
|
|
Rebalance,
|
|
&RebalanceListEntries);
|
|
}
|
|
|
|
RebalanceListEntries = 0;
|
|
|
|
for (ix = 0; Rebalance->RebalanceEndpoint[ix]; ix++)
|
|
{
|
|
RebalanceListEntries = ix + 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RebalanceListEntries = 0;
|
|
Result = FALSE;
|
|
}
|
|
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: RebalanceListEntries - %X, Result - %X\n",
|
|
RebalanceListEntries,
|
|
Result);
|
|
|
|
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);
|
|
}
|
|
|
|
if (Rebalance)
|
|
ExFreePoolWithTag(Rebalance, USB_PORT_TAG);
|
|
|
|
if (Result)
|
|
{
|
|
SMask = USB2_GetSMASK(Endpoint->TtEndpoint);
|
|
EndpointProperties->InterruptScheduleMask = SMask;
|
|
|
|
CMask = USB2_GetCMASK(Endpoint->TtEndpoint);
|
|
EndpointProperties->SplitCompletionMask = CMask;
|
|
|
|
AllocedBusTime = TtEndpoint->CalcBusTime;
|
|
|
|
EndpointBandwidth = USB2_MICROFRAMES * AllocedBusTime;
|
|
EndpointProperties->UsbBandwidth = EndpointBandwidth;
|
|
|
|
ActualPeriod = Endpoint->TtEndpoint->ActualPeriod;
|
|
EndpointProperties->Period = ActualPeriod;
|
|
|
|
ScheduleOffset = Endpoint->TtEndpoint->StartFrame;
|
|
EndpointProperties->ScheduleOffset = ScheduleOffset;
|
|
|
|
ASSERT(ActualPeriod);
|
|
Factor = USB2_FRAMES / ActualPeriod;
|
|
n = ScheduleOffset * Factor;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
USBPORT_DumpingEndpointProperties(EndpointProperties);
|
|
USBPORT_DumpingTtEndpoint(Endpoint->TtEndpoint);
|
|
|
|
if (AllocedBusTime >= (USB2_FS_MAX_PERIODIC_ALLOCATION / 2))
|
|
{
|
|
DPRINT1("USBPORT_AllocateBandwidthUSB2: AllocedBusTime >= 0.5 * MAX_ALLOCATION \n");
|
|
}
|
|
}
|
|
|
|
USB2_Rebalance(FdoDevice, &RebalanceList);
|
|
|
|
if (!TtExtension)
|
|
{
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
|
|
return Result;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
DPRINT("USBPORT_AllocateBandwidthUSB2: Result - %X\n", Result);
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USBPORT_FreeBandwidthUSB2(IN PDEVICE_OBJECT FdoDevice,
|
|
IN PUSBPORT_ENDPOINT Endpoint)
|
|
{
|
|
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;
|
|
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));
|
|
|
|
ASSERT(Period != 0);
|
|
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
|
|
NTAPI
|
|
USB2_InitTT(IN PUSB2_HC_EXTENSION HcExtension,
|
|
IN PUSB2_TT Tt)
|
|
{
|
|
ULONG ix;
|
|
ULONG jx;
|
|
|
|
DPRINT("USB2_InitTT: HcExtension - %p, Tt - %p\n", HcExtension, Tt);
|
|
|
|
Tt->HcExtension = HcExtension;
|
|
Tt->DelayTime = 1;
|
|
Tt->MaxTime = USB2_FS_MAX_PERIODIC_ALLOCATION;
|
|
|
|
for (ix = 0; ix < USB2_FRAMES; ix++)
|
|
{
|
|
Tt->FrameBudget[ix].TimeUsed = USB2_MAX_MICROFRAMES;
|
|
Tt->FrameBudget[ix].AltEndpoint = NULL;
|
|
|
|
for (jx = 0; jx < USB2_MICROFRAMES; jx++)
|
|
{
|
|
Tt->TimeCS[ix][jx] = 0;
|
|
Tt->NumStartSplits[ix][jx] = 0;
|
|
}
|
|
|
|
Tt->FrameBudget[ix].IsoEndpoint = &Tt->IsoEndpoint[ix];
|
|
|
|
USB2_InitTtEndpoint(&Tt->IsoEndpoint[ix],
|
|
USBPORT_TRANSFER_TYPE_ISOCHRONOUS,
|
|
USBPORT_TRANSFER_DIRECTION_OUT,
|
|
UsbFullSpeed,
|
|
USB2_FRAMES,
|
|
0,
|
|
Tt);
|
|
|
|
Tt->IsoEndpoint[ix].ActualPeriod = USB2_FRAMES;
|
|
Tt->IsoEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
|
|
Tt->IsoEndpoint[ix].StartFrame = ix;
|
|
Tt->IsoEndpoint[ix].StartMicroframe = USB2_PREV_MICROFRAME;
|
|
|
|
Tt->FrameBudget[ix].IntEndpoint = &Tt->IntEndpoint[ix];
|
|
|
|
USB2_InitTtEndpoint(&Tt->IntEndpoint[ix],
|
|
USBPORT_TRANSFER_TYPE_INTERRUPT,
|
|
USBPORT_TRANSFER_DIRECTION_OUT,
|
|
UsbFullSpeed,
|
|
USB2_FRAMES,
|
|
0,
|
|
Tt);
|
|
|
|
Tt->IntEndpoint[ix].ActualPeriod = USB2_FRAMES;
|
|
Tt->IntEndpoint[ix].CalcBusTime = USB2_FS_SOF_TIME + USB2_HUB_DELAY;
|
|
Tt->IntEndpoint[ix].StartFrame = ix;
|
|
Tt->IntEndpoint[ix].StartMicroframe = USB2_PREV_MICROFRAME;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
USB2_InitController(IN PUSB2_HC_EXTENSION HcExtension)
|
|
{
|
|
ULONG ix;
|
|
ULONG jx;
|
|
|
|
DPRINT("USB2_InitController: HcExtension - %p\n", HcExtension);
|
|
|
|
HcExtension->MaxHsBusAllocation = USB2_MAX_MICROFRAME_ALLOCATION;
|
|
|
|
for (ix = 0; ix < USB2_FRAMES; ix++)
|
|
{
|
|
for (jx = 0; jx < USB2_MICROFRAMES; jx++)
|
|
{
|
|
HcExtension->TimeUsed[ix][jx] = 0;
|
|
}
|
|
}
|
|
|
|
HcExtension->HcDelayTime = USB2_CONTROLLER_DELAY;
|
|
|
|
USB2_InitTT(HcExtension, &HcExtension->HcTt);
|
|
}
|