2020-09-30 17:17:25 +02:00

409 lines
15 KiB
C++

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
usbinit.cpp
Abstract:
Implementation of IUsbInit. This class is passed to class drivers to collect
resource information during initialization.
Environment:
XBOX kernel mode only
Notes:
Revision History:
01-10-01 created by Mitchell Dernis (mitchd)
--*/
//
// Pull in OS headers
//
extern "C" {
#include <ntos.h>
}
#include <ntrtl.h>
#include <nturtl.h>
#include <xtl.h>
#include <xapidrv.h>
//
// Setup the debug information for this file (see ..\inc\debug.h)
//
#define MODULE_POOL_TAG 'DBSU'
#include <debug.h>
DEFINE_USB_DEBUG_FUNCTIONS("USBD");
//
// Pull in usbd headers
//
#include <usbd.h>
#pragma code_seg(".XPPCINIT")
#pragma data_seg(".XPPDINIT")
#pragma const_seg(".XPPRINIT")
ULONG IUsbInit::GetMaxDeviceTypeCount(PXPP_DEVICE_TYPE XppDeviceType)
{
ULONG ulIndex;
//
// Return XGetPortCount(), if m_pDeviceTypes is NULL.
//
if(NULL == m_pDeviceTypes)
{
return 0;
}
//
// Otherwise, find the device type.
//
for(ulIndex = 0; ulIndex < m_NumDeviceTypes; ulIndex++)
{
if( m_pDeviceTypes[ulIndex].DeviceType == XppDeviceType)
{
ULONG ulResult = m_pDeviceTypes[ulIndex].dwPreallocCount;
#if DBG
if(0==ulResult)
{
XDebugPrint(XDBG_WARNING, "XInitDevices", "A device type was explictly listed requesting 0 open instances.\n\
This forces the linkage of the supporting driver library. Ommitting the device\ntype from the list is always better practice.");
}
#endif
return ulResult;
}
}
//
// If the device type was not registered, then we support 0.
// (Don't spew here, this could happen because one device
// supported by a given driver is in the list, but others are not.)
return 0;
}
BOOL IUsbInit::UseDefaultCount()
{
return m_pDeviceTypes ? FALSE : TRUE;
}
//
// It is inline, because we just want something more robust
// than a MAX macro which has a number of problems.
// It is static because we don't want code generated for it
//
inline static void SetToMax(UCHAR& dest, UCHAR src) {if(src > dest) dest = src;}
void IUsbInit::RegisterResources(PUSB_RESOURCE_REQUIREMENTS pResourceRequirements)
/*++
Routine Description:
Called by each driver for each type of connector it supports. It is up to each
driver to figure the maximum number of devices it can support in each slot type.
If a driver supports composite devices (such as audio) it should add the resources
of the composites together and register once.
If a driver supports multiple device types (not composites) it should register them separately.
If the devices have the same connector type, the driver may choose to register only the worst
case device.
--*/
{
PUSB_RESOURCE_REQUIREMENTS pConnectorResourceList;
ULONG ulMaxDevices = pResourceRequirements->MaxDevices;
ULONG ulMaxPorts = XGetPortCount();
//
// Choose which list to reserve resource from
//
switch(pResourceRequirements->ConnectorType)
{
case USB_CONNECTOR_TYPE_DIRECT:
// Direct
pConnectorResourceList = m_Direct;
break;
case USB_CONNECTOR_TYPE_HIGH_POWER:
pConnectorResourceList = m_TopSlots;
break;
case USB_CONNECTOR_TYPE_LOW_POWER:
//
// Low power devices have their resource allocated first against
// the bottom slots
//
pConnectorResourceList = m_BottomSlots;
// Low Power can go in top slots two, see
// below for way we use the 0th index.
SetToMax(
m_TopSlots[0].MaxCompositeInterfaces,
pResourceRequirements->MaxCompositeInterfaces
);
//
// If the device count exceeds the bottom slots, apply the rest
// towards the top-slots. The easiest way is to change the
// connector type to high-power and call ourselves.
//
if(pResourceRequirements->MaxDevices > ulMaxPorts)
{
pResourceRequirements->MaxDevices -= (UCHAR)ulMaxPorts;
pResourceRequirements->ConnectorType = USB_CONNECTOR_TYPE_HIGH_POWER;
RegisterResources(pResourceRequirements);
pResourceRequirements->MaxDevices += (UCHAR)ulMaxPorts;
pResourceRequirements->ConnectorType = USB_CONNECTOR_TYPE_LOW_POWER;
ulMaxDevices -= ulMaxPorts;
}
break;
}
//
// Composite Interface require nodes whether or not the device is opened.
// So we just use the 0th slot of the given type to track it, we are
// going to multiply by the number of ports anyway during Process.
//
SetToMax(
pConnectorResourceList[0].MaxCompositeInterfaces,
pResourceRequirements->MaxCompositeInterfaces
);
ASSERT(ulMaxDevices <= ulMaxPorts);
// Some variables for walk the resource table.
ULONG ulTempSlotIndex;
ULONG ulDeviceCount;
ULONG ulSlotIndex;
//
// Record Control Endpoint Resources
//
ulSlotIndex = 0;
ulDeviceCount = ulMaxDevices;
while(ulDeviceCount && (ulSlotIndex < ulMaxPorts))
{
if(pConnectorResourceList[ulSlotIndex].MaxControlEndpoints > pResourceRequirements->MaxControlEndpoints)
{
//Increment the slot index and continue trying to place the resources somewhere.
ulSlotIndex++;
continue;
} else
{
//Shift the resources to the right
for(ulTempSlotIndex = ulMaxPorts; ulTempSlotIndex > ulSlotIndex; ulTempSlotIndex--)
{
pConnectorResourceList[ulTempSlotIndex].MaxControlEndpoints = pConnectorResourceList[ulTempSlotIndex-1].MaxControlEndpoints;
}
// Record the new resources
pConnectorResourceList[ulSlotIndex].MaxControlEndpoints = pResourceRequirements->MaxControlEndpoints;
ulSlotIndex++;
ulDeviceCount--;
}
}
//
// Record Bulk Endpoint Resources
//
ulSlotIndex = 0;
ulDeviceCount = ulMaxDevices;
while(ulDeviceCount && (ulSlotIndex < ulMaxPorts))
{
if(pConnectorResourceList[ulSlotIndex].MaxBulkEndpoints > pResourceRequirements->MaxBulkEndpoints)
{
//Increment the slot index and continue trying to place the resources somewhere.
ulSlotIndex++;
continue;
} else
{
//Shift the resources to the right
for(ulTempSlotIndex = ulMaxPorts; ulTempSlotIndex > ulSlotIndex; ulTempSlotIndex--)
{
pConnectorResourceList[ulTempSlotIndex].MaxBulkEndpoints = pConnectorResourceList[ulTempSlotIndex-1].MaxBulkEndpoints;
}
// Record the new resources
pConnectorResourceList[ulSlotIndex].MaxBulkEndpoints = pResourceRequirements->MaxBulkEndpoints;
ulSlotIndex++;
ulDeviceCount--;
}
}
//
// Record Interrupt Endpoint Resources
//
ulSlotIndex = 0;
ulDeviceCount = ulMaxDevices;
while(ulDeviceCount && (ulSlotIndex < ulMaxPorts))
{
if(pConnectorResourceList[ulSlotIndex].MaxInterruptEndpoints > pResourceRequirements->MaxInterruptEndpoints)
{
//Increment the slot index and continue trying to place the resources somewhere.
ulSlotIndex++;
continue;
} else
{
//Shift the resources to the right
for(ulTempSlotIndex = ulMaxPorts; ulTempSlotIndex > ulSlotIndex; ulTempSlotIndex--)
{
pConnectorResourceList[ulTempSlotIndex].MaxInterruptEndpoints = pConnectorResourceList[ulTempSlotIndex-1].MaxInterruptEndpoints;
}
// Record the new resources
pConnectorResourceList[ulSlotIndex].MaxInterruptEndpoints = pResourceRequirements->MaxInterruptEndpoints;
ulSlotIndex++;
ulDeviceCount--;
}
}
//
// Record Isochronous Endpoint Resources
//
ulSlotIndex = 0;
ulDeviceCount = ulMaxDevices;
while(ulDeviceCount && (ulSlotIndex < ulMaxPorts))
{
if(pConnectorResourceList[ulSlotIndex].MaxIsochEndpoints > pResourceRequirements->MaxIsochEndpoints)
{
//Increment the slot index and continue trying to place the resources somewhere.
ulSlotIndex++;
continue;
} else
{
//Shift the resources to the right
for(ulTempSlotIndex = ulMaxPorts; ulTempSlotIndex > ulSlotIndex; ulTempSlotIndex--)
{
pConnectorResourceList[ulTempSlotIndex].MaxIsochEndpoints = pConnectorResourceList[ulTempSlotIndex-1].MaxIsochEndpoints;
}
// Record the new resources
pConnectorResourceList[ulSlotIndex].MaxIsochEndpoints = pResourceRequirements->MaxIsochEndpoints;
ulSlotIndex++;
ulDeviceCount--;
}
}
//
// These are max'd across all connector types and all slots. Unlike the other fields
// that are later summed across the connector types and slots.
SetToMax(m_HcdResources.ControlTDQuota, pResourceRequirements->MaxControlEndpoints);
SetToMax(m_HcdResources.BulkTDQuota, pResourceRequirements->MaxBulkTDperTransfer);
SetToMax(m_HcdResources.IsochMaxBuffers, pResourceRequirements->MaxIsochMaxBuffers);
//We keep track MaxComposite Interfaces, both per slot, and the global
return;
}
VOID
IUsbInit::Process()
/*
This routine takes all the table information, and boils it down to the information
that USBD needs.
*/
{
ULONG ulMaxPorts = XGetPortCount();
ULONG ulControlEndpoints = 0;
ULONG ulBulkEndpoints = 0;
ULONG ulInterruptEndpoints = 0;
// The members should all be 0 from the c'tor:
//
// Figure the base number of nodes based on how
// many devices may be pending enumeration at once.
// This number to USBD_BASE_NODES_PER_PORT per port.
// This is four, one for the hub, one for "direct connect"
// and one for each slot. It assumes there are no composites
// composites are figured in below.
//
m_NodeCount = USBD_BASE_NODES_PER_PORT*ulMaxPorts;
// Add two nodes: one for a host controller and one for
// an internal hub. Alternatively, on SILVER we support
// two host controllers but no internal hub.
//
// Also add a slop node. This is for when a device stops
// responding and needs to be reenumerated on a full bus.
// Due to timing constraints only one slop node should ever
// be needed.
//
m_NodeCount += 3;
//
// Now add nodes for the number of composites that can be found
// while enumerating a devices that is potentially not support.
//
m_NodeCount +=
(m_Direct[0].MaxCompositeInterfaces +
m_BottomSlots[0].MaxCompositeInterfaces +
m_TopSlots[0].MaxCompositeInterfaces) * ulMaxPorts;
//
// We also need nodes for composite interfaces of unsupported
// devices while they are enumerated, but before they are rejected.
//
SetToMax(m_MaxCompositeInterfaces,m_Direct[0].MaxCompositeInterfaces);
SetToMax(m_MaxCompositeInterfaces,m_BottomSlots[0].MaxCompositeInterfaces);
SetToMax(m_MaxCompositeInterfaces,m_TopSlots[0].MaxCompositeInterfaces);
m_NodeCount += m_MaxCompositeInterfaces;
//
// Add up the info that gets add across connector types and slots
//
for(ULONG ulSlotIndex = 0; ulSlotIndex < ulMaxPorts; ulSlotIndex++)
{
//
// Sum the Interrupt endpoints by type
//
ulInterruptEndpoints += m_Direct[ulSlotIndex].MaxInterruptEndpoints;
ulInterruptEndpoints += m_BottomSlots[ulSlotIndex].MaxInterruptEndpoints;
ulInterruptEndpoints += m_TopSlots[ulSlotIndex].MaxInterruptEndpoints;
//
// Sum the Control endpoints by type
//
ulControlEndpoints += m_Direct[ulSlotIndex].MaxControlEndpoints;
ulControlEndpoints += m_BottomSlots[ulSlotIndex].MaxControlEndpoints;
ulControlEndpoints += m_TopSlots[ulSlotIndex].MaxControlEndpoints;
//
// Sum the Bulk endpoints by type
//
ulBulkEndpoints += m_Direct[ulSlotIndex].MaxBulkEndpoints;
ulBulkEndpoints += m_BottomSlots[ulSlotIndex].MaxBulkEndpoints;
ulBulkEndpoints += m_TopSlots[ulSlotIndex].MaxBulkEndpoints;
//
// Sum the Isoch endpoints by type
//
m_HcdResources.IsochEndpointCount += m_Direct[ulSlotIndex].MaxIsochEndpoints;
m_HcdResources.IsochEndpointCount += m_BottomSlots[ulSlotIndex].MaxIsochEndpoints;
m_HcdResources.IsochEndpointCount += m_TopSlots[ulSlotIndex].MaxIsochEndpoints;
}
//
// The hub driver is a special case. It would be a different slot type,
// but instead it does not register, we just hard code it's resources.
// (The control qouta is less than enumerations, so don't worry about it.)
//
ulInterruptEndpoints += ulMaxPorts+1; //1 Interrupt EP per hub, one hub per port, plus an internal hub
ulControlEndpoints += ulMaxPorts+1; //1 Control EP per hub, one hub per port, plus an internal hub
//
// An extra control endpoint is needed for enumeration
// USBD also has a control TD quota
ulControlEndpoints += 1;
SetToMax(m_HcdResources.ControlTDQuota, USBD_CONTROL_TD_QUOTA);
//
// add the control and bulk endpoints,
// we will add in the interrupt below.
//
m_HcdResources.EndpointCount = ulControlEndpoints + ulBulkEndpoints;
//
// TD Count is the control quota plus the bulk quota plus
// one for each control and bulk endpoint, and USBD_INTERRUPT_TD_QUOTA
// times the number of interrupt endpoints.
//
m_HcdResources.TDCount = m_HcdResources.ControlTDQuota + m_HcdResources.BulkTDQuota +
m_HcdResources.EndpointCount +
(HCD_INTERRUPT_TD_QUOTA * ulInterruptEndpoints);
//
// Now add in the interrupt endpoint. Note that the isoch endpoint
// count is not included, ever. Isoch endpoints are allocated differently.
//
m_HcdResources.EndpointCount += ulInterruptEndpoints;
}