Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

787 lines
25 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
usb2.c
Abstract:
functions for processing usb 2.0 specific requests
Environment:
kernel mode only
Notes:
Revision History:
6-20-99 : created
--*/
#include "common.h"
#ifdef ALLOC_PRAGMA
#endif
// taken from budgeter code
#define LARGEXACT (579)
#define USBPORT_MAX_REBALANCE 30
VOID
USBPORT_Rebalance(
PDEVICE_OBJECT FdoDeviceObject,
PLIST_ENTRY ReblanceListHead
)
/*++
Routine Description:
The rebalnce list contains all the endpoints that were effected
by budgeting this new USB2 endpoint. We must re-schedule each of
them.
This process occurs during configuration of the device which is
serialized so we don't need to protect the list.
--*/
{
PLIST_ENTRY listEntry;
PHCD_ENDPOINT endpoint;
LONG startHframe;
ULONG scheduleOffset;
UCHAR sMask, cMask, period;
ULONG bandwidth;
PDEVICE_EXTENSION devExt;
LIST_ENTRY interruptChangeList;
LIST_ENTRY periodPromotionList;
LIST_ENTRY isoChangeList;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
InitializeListHead(&interruptChangeList);
InitializeListHead(&periodPromotionList);
InitializeListHead(&isoChangeList);
// bugbug
// can the insertion of the new endpiont occurr after the modification
// of the rebalnced endpoints?
// bugbug, this list must be sorted such that the changes occurr
// in the proper sequnence.
// ???
// <------chnages must travel this direction
// iso--interrupt
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS,
'2RB>', 0, 0, 0);
while (!IsListEmpty(ReblanceListHead)) {
listEntry = RemoveHeadList(ReblanceListHead);
endpoint = (PHCD_ENDPOINT) CONTAINING_RECORD(
listEntry,
struct _HCD_ENDPOINT,
RebalanceLink);
ASSERT_ENDPOINT(endpoint);
endpoint->RebalanceLink.Flink = NULL;
endpoint->RebalanceLink.Blink = NULL;
sMask = USB2LIB_GetSMASK(endpoint->Usb2LibEpContext);
cMask = USB2LIB_GetCMASK(endpoint->Usb2LibEpContext);
bandwidth = USB2LIB_GetAllocedBusTime(endpoint->Usb2LibEpContext) * 8;
scheduleOffset = USB2LIB_GetScheduleOffset(endpoint->Usb2LibEpContext);
period = USB2LIB_GetNewPeriod(endpoint->Usb2LibEpContext);
USBPORT_KdPrint((1,"'[RB-old] %x sMask = x%x cMask = x%x\n", endpoint,
endpoint->Parameters.InterruptScheduleMask,
endpoint->Parameters.SplitCompletionMask));
USBPORT_KdPrint((1,"'[RB-old] Period x%x Offset x%x\n",
endpoint->Parameters.Period,
endpoint->Parameters.ScheduleOffset));
USBPORT_KdPrint((1,"'[RB-new] %x sMask = x%x cMask = x%x\n",
endpoint, sMask, cMask));
USBPORT_KdPrint((1,"'[RB-new] Period x%x Offset x%x\n",
period, scheduleOffset));
switch (endpoint->Parameters.TransferType) {
case Interrupt:
if (sMask == endpoint->Parameters.InterruptScheduleMask &&
cMask == endpoint->Parameters.SplitCompletionMask &&
scheduleOffset == endpoint->Parameters.ScheduleOffset &&
period == endpoint->Parameters.Period) {
USBPORT_KdPrint((1,"'[RB] no changes\n"));
USBPORT_ASSERT(bandwidth == endpoint->Parameters.Bandwidth);
} else if (period != endpoint->Parameters.Period ||
scheduleOffset != endpoint->Parameters.ScheduleOffset) {
USBPORT_KdPrint((1,"'[RB] period changes\n"));
InsertTailList(&periodPromotionList,
&endpoint->RebalanceLink);
} else {
USBPORT_KdPrint((1,"'[RB] interrupt changes\n"));
InsertTailList(&interruptChangeList,
&endpoint->RebalanceLink);
}
break;
case Isochronous:
if (sMask == endpoint->Parameters.InterruptScheduleMask &&
cMask == endpoint->Parameters.SplitCompletionMask &&
scheduleOffset == endpoint->Parameters.ScheduleOffset &&
period == endpoint->Parameters.Period) {
USBPORT_KdPrint((1,"'[RB] iso no changes\n"));
USBPORT_ASSERT(bandwidth == endpoint->Parameters.Bandwidth);
} else if (period != endpoint->Parameters.Period ||
scheduleOffset != endpoint->Parameters.ScheduleOffset) {
// currently not handled
USBPORT_KdPrint((1,"'[RB] iso period changes\n"));
TEST_TRAP();
} else {
USBPORT_KdPrint((1,"'[RB] iso changes\n"));
InsertTailList(&isoChangeList,
&endpoint->RebalanceLink);
}
break;
}
}
// now do the period promotions
// BUGBUG lump period and interrupt together
USBPORT_KdPrint((1,"'[RB] period\n"));
USBPORT_RebalanceEndpoint(FdoDeviceObject,
&periodPromotionList);
USBPORT_KdPrint((1,"'[RB] interrupt\n"));
USBPORT_RebalanceEndpoint(FdoDeviceObject,
&interruptChangeList);
// now rebalance the iso endpoints
USBPORT_KdPrint((1,"'[RB] iso\n"));
USBPORT_RebalanceEndpoint(FdoDeviceObject,
&isoChangeList);
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS,
'2RB<', 0, 0, 0);
}
VOID
USBPORT_RebalanceEndpoint(
PDEVICE_OBJECT FdoDeviceObject,
PLIST_ENTRY EndpointList
)
/*++
Routine Description:
Computes the best schedule parameters for a USB2 endpoint.
--*/
{
PLIST_ENTRY listEntry;
PHCD_ENDPOINT endpoint;
ULONG scheduleOffset;
UCHAR sMask, cMask, period;
ULONG bandwidth, n, i, bt;
PDEVICE_EXTENSION devExt;
PHCD_ENDPOINT nextEndpoint;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
while (!IsListEmpty(EndpointList)) {
listEntry = RemoveHeadList(EndpointList);
endpoint = (PHCD_ENDPOINT) CONTAINING_RECORD(
listEntry,
struct _HCD_ENDPOINT,
RebalanceLink);
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS,
'rbe+', endpoint, 0, 0);
ASSERT_ENDPOINT(endpoint);
endpoint->RebalanceLink.Flink = NULL;
endpoint->RebalanceLink.Blink = NULL;
ACQUIRE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'Lex+');
// notify the miniport of the changed parameters
sMask = USB2LIB_GetSMASK(endpoint->Usb2LibEpContext);
cMask = USB2LIB_GetCMASK(endpoint->Usb2LibEpContext);
scheduleOffset = USB2LIB_GetScheduleOffset(endpoint->Usb2LibEpContext);
period = USB2LIB_GetNewPeriod(endpoint->Usb2LibEpContext);
bt = USB2LIB_GetAllocedBusTime(endpoint->Usb2LibEpContext);
bandwidth = bt * 8;
nextEndpoint = USB2LIB_GetNextEndpoint(endpoint->Usb2LibEpContext);
#if DBG
if (nextEndpoint) {
ASSERT_ENDPOINT(nextEndpoint);
}
#endif
USBPORT_KdPrint((1,"'[RB - %x] \n", endpoint));
USBPORT_ASSERT(bandwidth == endpoint->Parameters.Bandwidth);
endpoint->Parameters.InterruptScheduleMask = sMask;
endpoint->Parameters.SplitCompletionMask = cMask;
if (endpoint->Parameters.Period != period) {
// adjust bandwidth tracked for this endpoint
n = USBPORT_MAX_INTEP_POLLING_INTERVAL/endpoint->Parameters.Period;
for (i=0; i<n; i++) {
USBPORT_ASSERT(n*endpoint->Parameters.ScheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
endpoint->Tt->BandwidthTable[n*endpoint->Parameters.ScheduleOffset+i] +=
endpoint->Parameters.Bandwidth;
}
if (bt >= LARGEXACT) {
SET_FLAG(endpoint->Flags, EPFLAG_FATISO);
} else {
CLEAR_FLAG(endpoint->Flags, EPFLAG_FATISO);
}
// track new parameters resulting from period change
endpoint->Parameters.Period = period;
endpoint->Parameters.ScheduleOffset = scheduleOffset;
endpoint->Parameters.Bandwidth = bandwidth;
endpoint->Parameters.Ordinal =
USBPORT_SelectOrdinal(FdoDeviceObject, endpoint);
// new allocation
n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
for (i=0; i<n; i++) {
USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
endpoint->Tt->BandwidthTable[n*scheduleOffset+i] +=
bandwidth;
}
}
MP_RebalanceEndpoint(devExt, endpoint);
RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'Lex-');
}
}
BOOLEAN
USBPORT_AllocateBandwidthUSB20(
PDEVICE_OBJECT FdoDeviceObject,
PHCD_ENDPOINT Endpoint
)
/*++
Routine Description:
Computes the best schedule parameters for a USB2 endpoint.
--*/
{
PDEVICE_EXTENSION devExt;
USB2LIB_BUDGET_PARAMETERS budget;
BOOLEAN alloced;
LONG startHframe;
ULONG scheduleOffset, bt;
UCHAR sMask, cMask, period;
PREBALANCE_LIST rebalanceList;
ULONG rebalanceListEntries;
ULONG bytes;
LIST_ENTRY endpointList;
PVOID ttContext;
PTRANSACTION_TRANSLATOR translator = NULL;
PHCD_ENDPOINT nextEndpoint;
PAGED_CODE();
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
ASSERT_ENDPOINT(Endpoint);
InitializeListHead(&endpointList);
Endpoint->Parameters.ScheduleOffset = 0;
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS,
'a2BW', Endpoint, 0, 0);
// bulk and control are not tracked
if (Endpoint->Parameters.TransferType == Bulk ||
Endpoint->Parameters.TransferType == Control ||
TEST_FLAG(Endpoint->Flags, EPFLAG_ROOTHUB)) {
Endpoint->Parameters.ScheduleOffset = 0;
return TRUE;
}
if (Endpoint->Parameters.TransferType == Interrupt ||
Endpoint->Parameters.TransferType == Isochronous) {
USBPORT_KdPrint((1,"'ALLOCBW (EP) %x >>>>>>>>>>>>\n", Endpoint));
// period has been normalized to a value <=
// USBPORT_MAX_INTEP_POLLING_INTERVAL in either mf of frames
// call the engine to compute appropriate split masks
// for this interrupt endpoint
//
USBPORT_KdPrint((1,"'(alloc) ep = %x\n", Endpoint));
// set budget input parameters
if (Endpoint->Parameters.TransferType == Interrupt) {
budget.TransferType = Budget_Interrupt;
budget.Period = Endpoint->Parameters.Period;
} else {
budget.TransferType = Budget_Iso;
budget.Period = 1;
}
budget.MaxPacket = Endpoint->Parameters.MaxPacketSize;
if (Endpoint->Parameters.TransferDirection == In) {
budget.Direction = Budget_In;
} else {
budget.Direction = Budget_Out;
}
switch (Endpoint->Parameters.DeviceSpeed) {
case HighSpeed:
budget.Speed = Budget_HighSpeed;
break;
case LowSpeed:
budget.Speed = Budget_LowSpeed;
break;
case FullSpeed:
budget.Speed = Budget_FullSpeed;
break;
}
bytes = sizeof(PVOID) * USBPORT_MAX_REBALANCE;
ALLOC_POOL_Z(rebalanceList,
NonPagedPool,
bytes);
// high speed endpoints will have no Tt context
ttContext = NULL;
if (Endpoint->Tt != NULL) {
ASSERT_TT(Endpoint->Tt);
translator = Endpoint->Tt;
ttContext = &Endpoint->Tt->Usb2LibTtContext[0];
}
if (rebalanceList != NULL) {
rebalanceListEntries = USBPORT_MAX_REBALANCE;
alloced = USB2LIB_AllocUsb2BusTime(
devExt->Fdo.Usb2LibHcContext,
ttContext,
Endpoint->Usb2LibEpContext,
&budget,
Endpoint, // context
rebalanceList,
&rebalanceListEntries);
} else {
alloced = FALSE;
rebalanceListEntries = 0;
}
USBPORT_KdPrint((1,"'(alloc %d) rebalance count = %d\n",
alloced, rebalanceListEntries));
if (rebalanceListEntries > 0) {
PHCD_ENDPOINT rebalanceEndpoint;
ULONG i;
// convert the rebalance entries to endpoints
for (i=0; i< rebalanceListEntries; i++) {
rebalanceEndpoint = rebalanceList->RebalanceContext[i];
USBPORT_KdPrint((1,"'(alloc) rebalance Endpoint = %x \n",
rebalanceList->RebalanceContext[i]));
USBPORT_ASSERT(rebalanceEndpoint->RebalanceLink.Flink == NULL);
USBPORT_ASSERT(rebalanceEndpoint->RebalanceLink.Blink == NULL);
InsertTailList(&endpointList,
&rebalanceEndpoint->RebalanceLink);
}
}
if (rebalanceList != NULL) {
FREE_POOL(FdoDeviceObject, rebalanceList);
}
if (alloced == TRUE) {
ULONG n, bandwidth;
ULONG i;
// compute parameters for the miniport
startHframe = USB2LIB_GetStartMicroFrame(Endpoint->Usb2LibEpContext);
scheduleOffset = USB2LIB_GetScheduleOffset(Endpoint->Usb2LibEpContext);
period = USB2LIB_GetNewPeriod(Endpoint->Usb2LibEpContext);
sMask = USB2LIB_GetSMASK(Endpoint->Usb2LibEpContext);
cMask = USB2LIB_GetCMASK(Endpoint->Usb2LibEpContext);
// bw in bit times
bt = USB2LIB_GetAllocedBusTime(Endpoint->Usb2LibEpContext);
bandwidth = bt*8;
nextEndpoint = USB2LIB_GetNextEndpoint(Endpoint->Usb2LibEpContext);
#if DBG
if (nextEndpoint) {
ASSERT_ENDPOINT(nextEndpoint);
}
#endif
// update the bw table in the TT
if (translator == NULL) {
n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
for (i=0; i<n; i++) {
USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
USBPORT_ASSERT(devExt->Fdo.BandwidthTable[n*scheduleOffset+i] >= bandwidth);
devExt->Fdo.BandwidthTable[n*scheduleOffset+i] -= bandwidth;
}
} else {
// tt allocation, track the bw
n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
for (i=0; i<n; i++) {
USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
USBPORT_ASSERT(translator->BandwidthTable[n*scheduleOffset+i] >= bandwidth);
translator->BandwidthTable[n*scheduleOffset+i] -= bandwidth;
}
}
Endpoint->Parameters.Period = period;
Endpoint->Parameters.ScheduleOffset = scheduleOffset;
Endpoint->Parameters.InterruptScheduleMask = sMask;
Endpoint->Parameters.SplitCompletionMask = cMask;
Endpoint->Parameters.Bandwidth = bandwidth;
if (bt >= LARGEXACT) {
SET_FLAG(Endpoint->Flags, EPFLAG_FATISO);
}
USBPORT_KdPrint((1,"'[NEW] %x sMask = x%x cMask = x%x hFrame x%x\n",
Endpoint, sMask, cMask, startHframe));
USBPORT_KdPrint((1,"'[NEW] Period x%x Offset x%x bw = %d\n",
period, scheduleOffset, bandwidth));
USBPORT_KdPrint((1,"'[NEW] BudgetNextEp x%x \n", nextEndpoint));
} else {
USBPORT_KdPrint((1,"'[NEW] alloc failed\n"));
}
USBPORT_KdPrint((1,"'ALLOCBW (EP) <<<<<<<<<<<<<<<<<\n"));
}
LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS,
'a2RB', 0, 0, alloced);
USBPORT_KdPrint((1,"'REBLANCE (EP) >>>>>>>>>>>>>>>>>>>>\n"));
// process the rebalanced endpoints
USBPORT_Rebalance(FdoDeviceObject,
&endpointList);
USBPORT_KdPrint((1,"'REBLANCE (EP) <<<<<<<<<<<<<<<<<<<<<\n"));
if (translator != NULL) {
// adjust the global bandwidth tracked for this tt
ULONG bandwidth, i;
// release old bandwidth
bandwidth = translator->MaxAllocedBw;
for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
devExt->Fdo.BandwidthTable[i] += bandwidth;
}
USBPORT_UpdateAllocatedBwTt(translator);
// alloc new
bandwidth = translator->MaxAllocedBw;
for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
devExt->Fdo.BandwidthTable[i] -= bandwidth;
}
}
return alloced;
}
VOID
USBPORT_FreeBandwidthUSB20(
PDEVICE_OBJECT FdoDeviceObject,
PHCD_ENDPOINT Endpoint
)
/*++
Routine Description:
Frees the bw reserved for a give endpoint
Arguments:
Return Value:
FALSE if no bandwidth availble
--*/
{
PDEVICE_EXTENSION devExt;
ULONG period, bandwidth, sheduleOffset, i, n;
PREBALANCE_LIST rebalanceList;
ULONG rebalanceListEntries;
ULONG bytes;
LIST_ENTRY endpointList;
PVOID ttContext;
PTRANSACTION_TRANSLATOR translator = NULL;
ULONG scheduleOffset;
PAGED_CODE();
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
ASSERT_ENDPOINT(Endpoint);
period = Endpoint->Parameters.Period;
scheduleOffset = Endpoint->Parameters.ScheduleOffset;
bandwidth = Endpoint->Parameters.Bandwidth;
InitializeListHead(&endpointList);
if (Endpoint->Parameters.TransferType == Bulk ||
Endpoint->Parameters.TransferType == Control ||
TEST_FLAG(Endpoint->Flags, EPFLAG_ROOTHUB)) {
// these come out of our standard 10%
return;
}
USBPORT_KdPrint((1,"'(free) Endpoint = %x\n", Endpoint));
bytes = sizeof(PVOID) * USBPORT_MAX_REBALANCE;
// This must succeed, if we can't get memory for the
// rebalance list we cannot reorganize the schedule
// as a result of the device leaving. This means the
// whole schedule is busted and the bus will not function
// at all after this occurs.
//
ALLOC_POOL_Z(rebalanceList,
NonPagedPool,
bytes);
if (rebalanceList == NULL) {
// if this fails we have no choice but to leave
// the schedule hoplessly you-know-what'ed up.
return;
}
rebalanceListEntries = USBPORT_MAX_REBALANCE;
// high speed endpoints will have no Tt context
ttContext = NULL;
if (Endpoint->Tt != NULL) {
ASSERT_TT(Endpoint->Tt);
translator = Endpoint->Tt;
ttContext = &Endpoint->Tt->Usb2LibTtContext[0];
}
if (translator == NULL) {
// allocate 2.0 bus time
n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
for (i=0; i<n; i++) {
USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
devExt->Fdo.BandwidthTable[n*scheduleOffset+i] += bandwidth;
}
} else {
// tt allocation, track the bw on the tt
n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
for (i=0; i<n; i++) {
USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
translator->BandwidthTable[n*scheduleOffset+i] += bandwidth;
}
}
USB2LIB_FreeUsb2BusTime(
devExt->Fdo.Usb2LibHcContext,
ttContext,
Endpoint->Usb2LibEpContext,
rebalanceList,
&rebalanceListEntries);
USBPORT_KdPrint((1,"'[FREE] %x sMask = x%x cMask = x%x\n",
Endpoint,
Endpoint->Parameters.InterruptScheduleMask,
Endpoint->Parameters.SplitCompletionMask));
USBPORT_KdPrint((1,"'[FREE] Period x%x Offset x%x bw %d\n",
Endpoint->Parameters.Period,
Endpoint->Parameters.ScheduleOffset,
Endpoint->Parameters.Bandwidth));
USBPORT_KdPrint((1,"'rebalance count = %d\n",
rebalanceListEntries));
if (rebalanceListEntries > 0) {
PHCD_ENDPOINT rebalanceEndpoint;
ULONG rbIdx;
// convert the rebalance entries to endpoints
for (rbIdx=0; rbIdx< rebalanceListEntries; rbIdx++) {
rebalanceEndpoint = rebalanceList->RebalanceContext[rbIdx];
USBPORT_KdPrint((1,"'(free) rebalance Endpoint = %x\n",
rebalanceList->RebalanceContext[rbIdx]));
if (rebalanceEndpoint != Endpoint) {
USBPORT_ASSERT(rebalanceEndpoint->RebalanceLink.Flink == NULL);
USBPORT_ASSERT(rebalanceEndpoint->RebalanceLink.Blink == NULL);
InsertTailList(&endpointList,
&rebalanceEndpoint->RebalanceLink);
}
}
}
if (rebalanceList != NULL) {
FREE_POOL(FdoDeviceObject, rebalanceList);
}
// process the rebalanced endpoints
USBPORT_Rebalance(FdoDeviceObject,
&endpointList);
if (translator != NULL) {
// adjust the global bandwidth tracked for this tt
// release old bandwidth
bandwidth = translator->MaxAllocedBw;
for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
devExt->Fdo.BandwidthTable[i] += bandwidth;
}
USBPORT_UpdateAllocatedBwTt(translator);
// alloc new
bandwidth = translator->MaxAllocedBw;
for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
devExt->Fdo.BandwidthTable[i] -= bandwidth;
}
}
return;
}
/*
Endpoint Ordinal
An endpoint ordinal is a schedule attribute of the endpoint.
The ordinal set is unique for each endpoint type,period,offset,speed
combination. The ordinal is used to indicate the relative
order the endpoints should be visited by the host controller
hardware.
Interrupt Ordinals
These are unique to each node in the interrupt schedule, we maintain
a table similar to the miniport interrupt tree:
// the array looks like this, values indicate period:
// 1, 2, 2, 4, 4, 4, 4, 8,
// 8, 8, 8, 8, 8, 8, 8,16,
// 16,16,16,16,16,16,16,16,
// 16,16,16,16,16,16,16,32,
// 32,32,32,32,32,32,32,32,
// 32,32,32,32,32,32,32,32,
// 32,32,32,32,32,32,32,32,
// 32,32,32,32,32,32,32,
*/
ULONG
USBPORT_SelectOrdinal(
PDEVICE_OBJECT FdoDeviceObject,
PHCD_ENDPOINT Endpoint
)
/*++
Routine Description:
Frees the bw reserved for a give endpoint
Arguments:
Return Value:
FALSE if no bandwidth availble
--*/
{
PDEVICE_EXTENSION devExt;
ULONG ordinal;
static o = 0;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
if (!USBPORT_IS_USB20(devExt)) {
return 0;
}
switch (Endpoint->Parameters.TransferType) {
case Bulk:
case Control:
ordinal = 0;
break;
case Interrupt:
// BUGBUG
ordinal = o++;
break;
case Isochronous:
if (TEST_FLAG(Endpoint->Flags, EPFLAG_FATISO)) {
ordinal = 0;
} else {
ordinal = 1;
}
break;
}
return ordinal;
}