350 lines
9.4 KiB
C++
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);
|
|
}
|
|
|