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

350 lines
9.4 KiB
C++

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
usbd.c
Abstract:
USBD System Driver Main Entry Points
and Initialization
Environment:
XBOX kernel mode only
Notes:
Revision History:
12-28-99 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");
#pragma data_seg(".XPP$ClassA")
extern "C" DWORD USBD_BeginClassDescriptionTable = 0;
#pragma data_seg(".XPP$ClassZ")
extern "C" DWORD USBD_EndClassDescriptionTable = 0;
#pragma data_seg(".XPP$Data")
// Tells the linker to merge the USB sections together
#pragma comment(linker, "/merge:.XPPCODE=XPP")
#pragma comment(linker, "/merge:.XPPRDATA=XPP")
#pragma comment(linker, "/merge:.XPPCINIT=XPP")
#pragma comment(linker, "/merge:.XPPRINIT=XPP")
#pragma comment(linker, "/merge:.XPP=XPP")
#pragma comment(linker, "/merge:.XPPDINIT=XPP")
// Tell the linker that the code section contains read/write data.
#pragma comment(linker, "/section:XPP,ERW")
//
// Pull in usbd headers
//
#include <usbd.h>
//----------------------------------------------------------------------------------
// Globals - all of which must be initialized in DriverEntry
//----------------------------------------------------------------------------------
UCHAR GLOBAL_HostControllerCount;
//----------------------------------------------------------------------------------------------
// Just a simple inline new and matching delete that uses RTL_ALLOCATE_HEAP
//----------------------------------------------------------------------------------------------
#pragma warning(disable:4211)
static __inline void * __cdecl operator new(size_t memSize){return RTL_ALLOCATE_HEAP(memSize);}
static __inline void __cdecl operator delete(void *buffer){RTL_FREE_HEAP(buffer);}
#pragma warning(default:4211)
//----------------------------------------------------------------------------------
// Top level entry points called by the I\O Manager
//----------------------------------------------------------------------------------
#pragma code_seg(".XPPCINIT")
EXTERNUSB VOID USBD_Init(DWORD NumDeviceTypes, PXDEVICE_PREALLOC_TYPE DeviceTypes)
/*++
Routine Description:
Standard DriverEntry Routine - Let's libraries initialize globals,
then fills out dispatch table and returns success.
Arguments:
DriverObject - Pointer to DriverObject
RegistryPath - Pointer to RegistryPath
Return Value:
None.
--*/
{
USB_DBG_ENTRY_PRINT(("Entering USBD_Init"));
USB_DBG_TRACE_PRINT(("Built on %s @%s", __DATE__,__TIME__));
IUsbInit *pUsbInit = new IUsbInit(NumDeviceTypes, DeviceTypes);
//
// Walk the class drivers and call their init functions
//
PUSB_CLASS_DRIVER_DESCRIPTION *ppClassDriverDesc;
ppClassDriverDesc = (PUSB_CLASS_DRIVER_DESCRIPTION *)((&USBD_BeginClassDescriptionTable)+1);
while( (ULONG_PTR)ppClassDriverDesc < (ULONG_PTR)&USBD_EndClassDescriptionTable )
{
if(*ppClassDriverDesc) (*ppClassDriverDesc)->Init(pUsbInit);
ppClassDriverDesc++;
}
pUsbInit->Process();
//
// Give the HCD a chance to initialize its globals.
//
HCD_DriverEntry(pUsbInit->GetHcdResourcePtr());
//
// Initialize the device tree
//
g_DeviceTree.Init(pUsbInit->GetNodeCount(), pUsbInit->GetMaxCompositeInterfaces());
//
// We are done with the IUsbInit object
//
delete pUsbInit;
GLOBAL_HostControllerCount=0;
//
// Call the HCD layer to enumerate the hardware.
//
HCD_EnumHardware();
USB_DBG_EXIT_PRINT(("Exiting USBD_Init"));
}
VOID
USBD_NewHostController(
IN PPCI_DEVICE_DESCRIPTOR PciDevice,
IN ULONG HcdDeviceExtensionSize
)
/*++
Routine Description:
Called by the HCD_EnumHardware for every host controller
it finds.
We do the following:
a1. Create a device. (Actually, we need only the extensions not the device objects)
2. Initialize the USBD portion of the of the device
3. Call HCD_NewHostController to initialize the hardware portion.
Arguments:
PciDevice - PCI descriptor to pass back to the hardware initialization later.
HcdDeviceExtensionSize - Size of HCD portion of host controller context.
Return Value:
None - what good does it do to annouce failure anyway.
--*/
{
PUSBD_HOST_CONTROLLER hostController;
USB_DBG_ENTRY_PRINT(("Entering USBD_NewHostController"));
//
// Allocate the Host Controller
//
hostController = (PUSBD_HOST_CONTROLLER)RTL_ALLOCATE_HEAP(sizeof(USBD_HOST_CONTROLLER) + HcdDeviceExtensionSize);
if(hostController)
{
//
// Zero out the whole memory we just allocated. We do this for our extension
// and for the HCD's.
//
RtlZeroMemory(hostController, sizeof(USBD_HOST_CONTROLLER) + HcdDeviceExtensionSize);
//
// We need to number our controllers, so the game can distinguish
//
hostController->ControllerNumber = ++GLOBAL_HostControllerCount;
USB_DBG_TRACE_PRINT(("Host Controller #%d Found:", hostController->ControllerNumber));
USB_DBG_TRACE_PRINT(("HCD extension = 0x%0.8x:", USBD_GetHCDExtension(hostController)));
//
// Add a RootHub device for this host controller.
//
hostController->RootHub = g_DeviceTree.AllocDevice();
ASSERT(hostController->RootHub);
hostController->RootHub->m_Type = UDN_TYPE_ROOT_HUB;
hostController->RootHub->m_FirstChild = UDN_INVALID_NODE_INDEX;
hostController->RootHub->m_Parent = UDN_INVALID_NODE_INDEX;
hostController->RootHub->m_Sibling = UDN_INVALID_NODE_INDEX;
hostController->RootHub->m_HostController = hostController;
//
// Initialize the hardware
//
HCD_NewHostController(USBD_GetHCDExtension(hostController), hostController->ControllerNumber, PciDevice);
}
USB_DBG_EXIT_PRINT(("Exiting USBD_NewHostController"));
return;
}
#pragma code_seg(".XPPCODE")
VOID
USBD_CompleteRequest(
IN PURB Urb
)
/*++
Routine Description:
Entry point called by HCD (and a few places in USBD) to complete an URB.
Basically, it calls the completion routine if there is one.
Arguments:
Urb - The URB that was just completed.
Return Value:
--*/
{
//
// If there is a completion routine than call it.
//
if(Urb->Header.CompleteProc)
{
USB_DBG_TRACE_PRINT(("Calling the completion routine @0x%0.8x for URB @0x%0.8x.",
Urb->Header.CompleteProc, Urb));
Urb->Header.CompleteProc(Urb, Urb->Header.CompleteContext);
}
}
USHORT
USBD_CalculateUsbBandwidth(
IN USHORT MaxPacketSize,
IN UCHAR EndpointType,
IN BOOLEAN LowSpeed
)
/*++
Routine Description:
Arguments:
Return Value:
banwidth consumed in bits/ms, returns 0 for bulk
and control endpoints
--*/
{
USHORT bw;
//
// control, iso, bulk, interrupt
//
ULONG overhead[4] = {
0,
USB_ISO_OVERHEAD_BYTES,
0,
USB_INTERRUPT_OVERHEAD_BYTES
};
ASSERT(EndpointType<4);
//
// Calculate bandwidth for endpoint. We will use the
// approximation: (overhead bytes plus MaxPacket bytes)
// times 8 bits/byte times worst case bitstuffing overhead.
// This gives bit times, for low speed endpoints we multiply
// by 8 again to convert to full speed bits.
//
//
// Figure out how many bits are required for the transfer.
// (multiply by 7/6 because, in the worst case you might
// have a bit-stuff every six bits requiring 7 bit times to
// transmit 6 bits of data.)
//
// overhead(bytes) * maxpacket(bytes/ms) * 8
// (bits/byte) * bitstuff(7/6) = bits/ms
bw = (USHORT)(((overhead[EndpointType]+MaxPacketSize) * 8 * 7) / 6);
// return zero for control or bulk
if (!overhead[EndpointType]) {
bw = 0;
}
if (LowSpeed) {
bw *= 8;
}
return bw;
}
PUSB_CLASS_DRIVER_DESCRIPTION USBD_FindClassDriver(PNP_CLASS_ID ClassId)
{
PUSB_CLASS_DRIVER_DESCRIPTION *ppMatch;
//
// Match only the class and class specific type.
// The class specific type has a slightly different meaning here.
// In this context ir is whether the device is interface level or
// device level. Later the class driver will set it to be something
// which is really class specific.
//
ppMatch = (PUSB_CLASS_DRIVER_DESCRIPTION *)((&USBD_BeginClassDescriptionTable)+1);
while( (ULONG_PTR)ppMatch < (ULONG_PTR)&USBD_EndClassDescriptionTable)
{
if(
*ppMatch &&
(ClassId.USB.bClass == (*ppMatch)->ClassId.USB.bClass) &&
(ClassId.USB.bClassSpecificType == (*ppMatch)->ClassId.USB.bClassSpecificType)
)
{
goto found_match;
}
ppMatch++;
}
return NULL;
found_match:
return (*ppMatch);
}