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.
 
 
 
 
 
 

758 lines
19 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
service.c
Abstract:
DLL Services provided by usbport.sys
This module conatins the load and initialization code
used by the port driver to link up with the miniport.
Environment:
kernel mode only
Notes:
Revision History:
6-20-99 : created
--*/
#define USBPORT
#include "common.h"
extern USBPORT_SPIN_LOCK USBPORT_GlobalsSpinLock;
extern LIST_ENTRY USBPORT_USB2fdoList;
extern LIST_ENTRY USBPORT_USB1fdoList;
#ifdef ALLOC_PRAGMA
//#pragma alloc_text(PAGE, USBD_InternalGetInterfaceLength)
#endif
NTSTATUS
DllUnload(
VOID
)
{
extern BOOLEAN USBPORT_GlobalInitialized;
USBPORT_KdPrint((1, "'unloading USBPORT\n"));
// this will cause us to re-init even if our
// image is not unloaded or the data segment
// is not re-initialized (this happens on win9x)
if (USBPORT_GlobalInitialized && USBPORT_DummyUsbdExtension) {
FREE_POOL(NULL, USBPORT_DummyUsbdExtension);
}
USBPORT_GlobalInitialized = FALSE;
USBPORT_DummyUsbdExtension = NULL;
return STATUS_SUCCESS;
}
ULONG
USBPORT_GetHciMn(
)
{
return USB_HCI_MN;
}
PDEVICE_OBJECT
USBPORT_FindUSB2Controller(
PDEVICE_OBJECT CcFdoDeviceObject
)
/*++
Routine Description:
Given a companion controller find the FDO for the parent
Arguments:
Return Value:
--*/
{
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION devExt;
KIRQL irql;
PLIST_ENTRY listEntry;
PDEVICE_EXTENSION ccExt;
GET_DEVICE_EXT(ccExt, CcFdoDeviceObject);
ASSERT_FDOEXT(ccExt);
KeAcquireSpinLock(&USBPORT_GlobalsSpinLock.sl, &irql);
GET_HEAD_LIST(USBPORT_USB2fdoList, listEntry);
while (listEntry &&
listEntry != &USBPORT_USB2fdoList) {
devExt = (PDEVICE_EXTENSION) CONTAINING_RECORD(
listEntry,
struct _DEVICE_EXTENSION,
Fdo.ControllerLink);
// find the USB 2 controller assocaited with this CC
if (devExt->Fdo.BusNumber == ccExt->Fdo.BusNumber &&
devExt->Fdo.BusDevice == ccExt->Fdo.BusDevice) {
deviceObject = devExt->HcFdoDeviceObject;
break;
}
listEntry = devExt->Fdo.ControllerLink.Flink;
}
KeReleaseSpinLock(&USBPORT_GlobalsSpinLock.sl, irql);
return deviceObject;
}
BOOLEAN
USBPORT_IsCCForFdo(
PDEVICE_OBJECT Usb2FdoDeviceObject,
PDEVICE_EXTENSION CcExt
)
/*++
--*/
{
PDEVICE_EXTENSION usb2Ext;
GET_DEVICE_EXT(usb2Ext, Usb2FdoDeviceObject);
ASSERT_FDOEXT(usb2Ext);
ASSERT_FDOEXT(CcExt);
if (usb2Ext->Fdo.BusNumber == CcExt->Fdo.BusNumber &&
usb2Ext->Fdo.BusDevice == CcExt->Fdo.BusDevice) {
return TRUE;
}
return FALSE;
}
PDEVICE_RELATIONS
USBPORT_FindCompanionControllers(
PDEVICE_OBJECT Usb2FdoDeviceObject,
BOOLEAN ReferenceObjects,
BOOLEAN ReturnFdo
)
/*++
Routine Description:
Given a companion controller find the FDO for the parent
Arguments:
Return Value:
--*/
{
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION devExt;
PLIST_ENTRY listEntry;
KIRQL irql;
PDEVICE_RELATIONS deviceRelations = NULL;
ULONG count = 0;
KeAcquireSpinLock(&USBPORT_GlobalsSpinLock.sl, &irql);
GET_HEAD_LIST(USBPORT_USB1fdoList, listEntry);
while (listEntry &&
listEntry != &USBPORT_USB1fdoList) {
devExt = (PDEVICE_EXTENSION) CONTAINING_RECORD(
listEntry,
struct _DEVICE_EXTENSION,
Fdo.ControllerLink);
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC) &&
USBPORT_IsCCForFdo(Usb2FdoDeviceObject, devExt)) {
count++;
}
listEntry = devExt->Fdo.ControllerLink.Flink;
} /* while */
LOGENTRY(NULL, Usb2FdoDeviceObject, LOG_MISC, 'fccR', count, 0,
Usb2FdoDeviceObject);
if (count) {
ALLOC_POOL_OSOWNED(deviceRelations,
NonPagedPool,
sizeof(*deviceRelations)*count);
}
if (deviceRelations != NULL) {
deviceRelations->Count = count;
count = 0;
GET_HEAD_LIST(USBPORT_USB1fdoList, listEntry);
while (listEntry &&
listEntry != &USBPORT_USB1fdoList) {
devExt = (PDEVICE_EXTENSION) CONTAINING_RECORD(
listEntry,
struct _DEVICE_EXTENSION,
Fdo.ControllerLink);
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC) &&
USBPORT_IsCCForFdo(Usb2FdoDeviceObject, devExt)) {
USBPORT_ASSERT(count < deviceRelations->Count);
deviceRelations->Objects[count] = devExt->Fdo.PhysicalDeviceObject;
if (ReferenceObjects) {
ObReferenceObject(deviceRelations->Objects[count]);
}
if (ReturnFdo) {
deviceRelations->Objects[count] =
devExt->HcFdoDeviceObject;
}
USBPORT_KdPrint((1, "'Found CC %x\n", deviceRelations->Objects[count]));
count++;
}
listEntry = devExt->Fdo.ControllerLink.Flink;
} /* while */
}
KeReleaseSpinLock(&USBPORT_GlobalsSpinLock.sl, irql);
return deviceRelations;
}
VOID
USBPORT_RegisterUSB2fdo(
PDEVICE_OBJECT FdoDeviceObject
)
/*++
Routine Description:
tracks an instance of a USB 2 device
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_FDO_REGISTERED);
ExInterlockedInsertTailList(&USBPORT_USB2fdoList,
&devExt->Fdo.ControllerLink,
&USBPORT_GlobalsSpinLock.sl);
}
VOID
USBPORT_RegisterUSB1fdo(
PDEVICE_OBJECT FdoDeviceObject
)
/*++
Routine Description:
tracks an instance of a USB 2 device
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_FDO_REGISTERED);
ExInterlockedInsertTailList(&USBPORT_USB1fdoList,
&devExt->Fdo.ControllerLink,
&USBPORT_GlobalsSpinLock.sl);
}
VOID
USBPORT_DeregisterUSB2fdo(
PDEVICE_OBJECT FdoDeviceObject
)
/*++
Routine Description:
tracks an instance of a USB 2 device
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
USBPORT_ASSERT(devExt->Fdo.ControllerLink.Flink != NULL);
USBPORT_ASSERT(devExt->Fdo.ControllerLink.Blink != NULL);
USBPORT_InterlockedRemoveEntryList(&devExt->Fdo.ControllerLink,
&USBPORT_GlobalsSpinLock.sl);
CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_FDO_REGISTERED);
devExt->Fdo.ControllerLink.Blink = NULL;
devExt->Fdo.ControllerLink.Flink = NULL;
}
VOID
USBPORT_DeregisterUSB1fdo(
PDEVICE_OBJECT FdoDeviceObject
)
/*++
Routine Description:
tracks an instance of a USB 2 device
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION devExt;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
USBPORT_ASSERT(devExt->Fdo.ControllerLink.Flink != NULL);
USBPORT_ASSERT(devExt->Fdo.ControllerLink.Blink != NULL);
USBPORT_InterlockedRemoveEntryList(&devExt->Fdo.ControllerLink,
&USBPORT_GlobalsSpinLock.sl);
CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_FDO_REGISTERED);
devExt->Fdo.ControllerLink.Blink = NULL;
devExt->Fdo.ControllerLink.Flink = NULL;
}
NTSTATUS
USBPORT_RegisterUSBPortDriver(
PDRIVER_OBJECT DriverObject,
ULONG MiniportHciVersion,
PUSBPORT_REGISTRATION_PACKET RegistrationPacket
)
/*++
Routine Description:
Called from DriverEntry by miniport.
The opposite of this function is the DriverObject->Unload
routine which we hook.
Arguments:
Return Value:
--*/
{
PUSBPORT_MINIPORT_DRIVER miniportDriver;
extern LIST_ENTRY USBPORT_MiniportDriverList;
extern USBPORT_SPIN_LOCK USBPORT_GlobalsSpinLock;
extern BOOLEAN USBPORT_GlobalInitialized;
NTSTATUS ntStatus;
extern ULONG USB2LIB_HcContextSize;
extern ULONG USB2LIB_EndpointContextSize;
extern ULONG USB2LIB_TtContextSize;
ULONG regPacketLength = 0;
// get global registry parameters, check on every
// miniport load
GET_GLOBAL_DEBUG_PARAMETERS();
USBPORT_KdPrint((1, "'USBPORT Universal Serial Bus Host Controller Port Driver.\n"));
USBPORT_KdPrint((1, "'Using USBDI version %x\n", USBDI_VERSION));
USBPORT_KdPrint((2, "'Registration Packet %x\n", RegistrationPacket));
DEBUG_BREAK();
if (USBPORT_GlobalInitialized == FALSE) {
// do some first time loaded stuff
USBPORT_GlobalInitialized = TRUE;
InitializeListHead(&USBPORT_MiniportDriverList);
InitializeListHead(&USBPORT_USB2fdoList);
InitializeListHead(&USBPORT_USB1fdoList);
KeInitializeSpinLock(&USBPORT_GlobalsSpinLock.sl);
ALLOC_POOL_Z(USBPORT_DummyUsbdExtension,
NonPagedPool,
USBPORT_DUMMY_USBD_EXT_SIZE);
if (USBPORT_DummyUsbdExtension == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
USB2LIB_InitializeLib(
&USB2LIB_HcContextSize,
&USB2LIB_EndpointContextSize,
&USB2LIB_TtContextSize,
USB2LIB_DbgPrint,
USB2LIB_DbgBreak);
}
// non paged because we will call the function pointers
// thru this structure
ALLOC_POOL_Z(miniportDriver,
NonPagedPool,
sizeof(*miniportDriver));
if (miniportDriver == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
USBPORT_KdPrint((1, "'miniport driver: %x\n", miniportDriver));
miniportDriver->DriverObject = DriverObject;
//
// Create dispatch points for appropriate irps
//
DriverObject->MajorFunction[IRP_MJ_CREATE]=
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
DriverObject->MajorFunction[IRP_MJ_PNP] =
DriverObject->MajorFunction[IRP_MJ_POWER] = USBPORT_Dispatch;
DriverObject->DriverExtension->AddDevice = USBPORT_PnPAddDevice;
miniportDriver->MiniportUnload = DriverObject->DriverUnload;
DriverObject->DriverUnload = USBPORT_Unload;
// set up the registration packet and return our function pointers
// miniport.
// bump this for pre-release versions of the stack to prevent
// compatibilty problms with pre-release miniports
#define USBHDCDI_MIN_REV_SUPPORTED 100
// remeber the registered version
miniportDriver->HciVersion = MiniportHciVersion;
if (MiniportHciVersion < USBHDCDI_MIN_REV_SUPPORTED) {
return STATUS_UNSUCCESSFUL;
}
// do our version (1) stuff
if (MiniportHciVersion >= 100) {
// validate the registrtion packet
// if (RegistrationPacket->
// USBPORT_KdPrint((0, "'Miniport Registrtaion Packet is invalid!\n"));
// DEBUG_BREAK();
// ntStatus = STATUS_UNSUCCESSFUL;
// goto USBPORT_RegisterUSBPortDriver_Done;
// }
// do our version (1) stuff
RegistrationPacket->USBPORTSVC_DbgPrint =
USBPORTSVC_DbgPrint;
RegistrationPacket->USBPORTSVC_TestDebugBreak =
USBPORTSVC_TestDebugBreak;
RegistrationPacket->USBPORTSVC_AssertFailure =
USBPORTSVC_AssertFailure;
RegistrationPacket->USBPORTSVC_GetMiniportRegistryKeyValue =
USBPORTSVC_GetMiniportRegistryKeyValue;
RegistrationPacket->USBPORTSVC_InvalidateRootHub =
USBPORTSVC_InvalidateRootHub;
RegistrationPacket->USBPORTSVC_InvalidateEndpoint =
USBPORTSVC_InvalidateEndpoint;
RegistrationPacket->USBPORTSVC_CompleteTransfer =
USBPORTSVC_CompleteTransfer;
RegistrationPacket->USBPORTSVC_CompleteIsoTransfer =
USBPORTSVC_CompleteIsoTransfer;
RegistrationPacket->USBPORTSVC_LogEntry =
USBPORTSVC_LogEntry;
RegistrationPacket->USBPORTSVC_MapHwPhysicalToVirtual =
USBPORTSVC_MapHwPhysicalToVirtual;
RegistrationPacket->USBPORTSVC_RequestAsyncCallback =
USBPORTSVC_RequestAsyncCallback;
RegistrationPacket->USBPORTSVC_ReadWriteConfigSpace =
USBPORTSVC_ReadWriteConfigSpace;
RegistrationPacket->USBPORTSVC_Wait =
USBPORTSVC_Wait;
RegistrationPacket->USBPORTSVC_InvalidateController =
USBPORTSVC_InvalidateController;
RegistrationPacket->USBPORTSVC_BugCheck =
USBPORTSVC_BugCheck;
RegistrationPacket->USBPORTSVC_NotifyDoubleBuffer =
USBPORTSVC_NotifyDoubleBuffer;
regPacketLength = sizeof(USBPORT_REGISTRATION_PACKET_V1);
USBPORT_KdPrint((1, "'Miniport Version 1 support\n"));
}
// do our version (2) stuff, this is a superset of version 1
if (MiniportHciVersion >= 200) {
USBPORT_KdPrint((1, "'Miniport Version 2 support\n"));
regPacketLength = sizeof(USBPORT_REGISTRATION_PACKET);
}
// save a copy of the packet
RtlCopyMemory(&miniportDriver->RegistrationPacket,
RegistrationPacket,
regPacketLength);
// put this driver on our list
ExInterlockedInsertTailList(&USBPORT_MiniportDriverList,
&miniportDriver->ListEntry,
&USBPORT_GlobalsSpinLock.sl);
ntStatus = STATUS_SUCCESS;
TEST_PATH(ntStatus, FAILED_REGISTERUSBPORT);
USBPORT_RegisterUSBPortDriver_Done:
return ntStatus;
}
/*
Misc Miniport callable services
*/
#if 0
BOOLEAN
USBPORTSVC_SyncWait(
PDEVICE_DATA DeviceData,
xxx WaitCompletePollFunction,
ULONG MaxMillisecondsToWait
)
/*++
Routine Description:
Service exported to miniports to wait on the HW
Arguments:
Return Value:
Returns true if the time expired before the WaitCompletePoll
function returns true
--*/
{
PDEVICE_EXTENSION devExt;
PDEVICE_OBJECT fdoDeviceObject;
LARGE_INTEGER finishTime, currentTime;
DEVEXT_FROM_DEVDATA(devExt, DeviceData);
ASSERT_FDOEXT(devExt);
fdoDeviceObject = devExt->HcFdoDeviceObject;
LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'synW', 0, 0, 0);
KeQuerySystemTime(&finishTime);
// convert millisecs to nanosecs (10 ^-3 -> 10^-9)
nonosecs.QuadPart = MaxMillisecondsToWait * 1000000
// figure when we quit
finishTime.QuadPart += nonosecs.QuadPart
while (!MP_WaitPollFunction(xxx)) {
KeQuerySystemTime(&currentTime);
if (currentTime.QuadPart >= finishTime.QuadPart) {
LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'syTO', 0, 0, 0);
return TRUE;
}
}
return FALSE;
}
#endif
typedef struct _USBPORT_ASYNC_TIMER {
ULONG Sig;
PDEVICE_OBJECT FdoDeviceObject;
KTIMER Timer;
KDPC Dpc;
PMINIPORT_CALLBACK MpCallbackFunction;
UCHAR MiniportContext[0];
} USBPORT_ASYNC_TIMER, *PUSBPORT_ASYNC_TIMER;
VOID
USBPORT_AsyncTimerDpc(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext - supplies FdoDeviceObject.
SystemArgument1 - not used.
SystemArgument2 - not used.
Return Value:
None.
--*/
{
PDEVICE_OBJECT fdoDeviceObject;
KIRQL irql;
PUSBPORT_ASYNC_TIMER asyncTimer = DeferredContext;
PDEVICE_EXTENSION devExt;
fdoDeviceObject = asyncTimer->FdoDeviceObject;
GET_DEVICE_EXT(devExt, fdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, fdoDeviceObject, LOG_RH, 'ayTM', fdoDeviceObject, asyncTimer, 0);
// call the miniport
asyncTimer->Sig = SIG_MP_TIMR;
asyncTimer->MpCallbackFunction(devExt->Fdo.MiniportDeviceData,
&asyncTimer->MiniportContext[0]);
DECREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, NULL);
FREE_POOL(fdoDeviceObject, asyncTimer);
}
VOID
USBPORTSVC_RequestAsyncCallback(
PDEVICE_DATA DeviceData,
ULONG MilliSeconds,
PVOID Context,
ULONG ContextLength,
PMINIPORT_CALLBACK CallbackFunction
)
/*++
Routine Description:
Service exported to miniports to wait on the HW
and to time asynchronous events
Arguments:
Return Value:
None.
--*/
{
PDEVICE_EXTENSION devExt;
PDEVICE_OBJECT fdoDeviceObject;
LONG dueTime;
ULONG timerIncerent;
PUSBPORT_ASYNC_TIMER asyncTimer;
SIZE_T siz;
DEVEXT_FROM_DEVDATA(devExt, DeviceData);
ASSERT_FDOEXT(devExt);
fdoDeviceObject = devExt->HcFdoDeviceObject;
// allocate a timer
siz = sizeof(USBPORT_ASYNC_TIMER) + ContextLength;
ALLOC_POOL_Z(asyncTimer, NonPagedPool, siz);
LOGENTRY(NULL, fdoDeviceObject, LOG_RH, 'asyT', 0, siz, asyncTimer);
// if this fails the miniport will be waiting a very long
// time.
if (asyncTimer != NULL) {
if (ContextLength) {
RtlCopyMemory(&asyncTimer->MiniportContext[0],
Context,
ContextLength);
}
asyncTimer->MpCallbackFunction = CallbackFunction;
asyncTimer->FdoDeviceObject = fdoDeviceObject;
KeInitializeTimer(&asyncTimer->Timer);
KeInitializeDpc(&asyncTimer->Dpc,
USBPORT_AsyncTimerDpc,
asyncTimer);
timerIncerent = KeQueryTimeIncrement() - 1;
dueTime =
-1 * (timerIncerent + MILLISECONDS_TO_100_NS_UNITS(MilliSeconds));
KeSetTimer(&asyncTimer->Timer,
RtlConvertLongToLargeInteger(dueTime),
&asyncTimer->Dpc);
INCREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, NULL);
}
}