|
|
/*++
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(¤tTime); 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); } }
|