|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
SERVICE.C
Abstract:
Services provided to the DBC port driver
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include <wdm.h>
#include "stdarg.h"
#include "stdio.h"
#include "dbci.h"
#include "dbclass.h"
#include "dbfilter.h"
#define DBCLASS
#include "dbclib.h"
#undef DBCLASS
extern PDBC_CONTEXT DBCLASS_ControllerList; extern KSPIN_LOCK DBCLASS_ControllerListSpin; extern LIST_ENTRY DBCLASS_DevicePdoList; extern LIST_ENTRY DBCLASS_BusFilterMdoList;
NTSTATUS DBCLASS_Initialize( ) { // temp init code.
static init = 0;
if (init) { return STATUS_SUCCESS; }
#if DBG
DBCLASS_GetClassGlobalDebugRegistryParameters(); BRK_ON_TRAP(); #endif
DBCLASS_KdPrint((1, "'Initailize DBC Class Driver\n")); #ifdef DEBUG_LOG
//
// Initialize our debug trace log
//
DBCLASS_LogInit(); #endif
DBCLASS_ControllerList = NULL; KeInitializeSpinLock(&DBCLASS_ControllerListSpin); InitializeListHead(&DBCLASS_DevicePdoList); InitializeListHead(&DBCLASS_BusFilterMdoList); init = 1;
return STATUS_SUCCESS; }
#if 0
__declspec(dllexport) NTSTATUS DllInitialize( IN PUNICODE_STRING RegistryPath ) { TEST_TRAP(); return STATUS_SUCCESS; } #endif
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++
Routine Description:
Installable driver initialization entry point. This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path to driver-specific key in the registry
Return Value:
NT status code
--*/ { TEST_TRAP();
return STATUS_SUCCESS; }
NTSTATUS DBCLASS_RegisterController( IN ULONG DbclassVersion, IN PDEVICE_OBJECT ControllerFdo, IN PDEVICE_OBJECT TopOfPdoStack, IN PDEVICE_OBJECT ControllerPdo, IN ULONG ControllerSig ) /*++
Routine Description:
This function registers a DBC with the class driver, the FDO of the DBC is passed in along with the PDO for the DBC.
The class driver uses this information to locate the correct instances of the DB Class Driver FDOs.
Arguments:
Return Value:
None
--*/ { PDBC_CONTEXT dbcContext; KIRQL irql; NTSTATUS ntStatus;
#if DBG
DBCLASS_GetClassGlobalDebugRegistryParameters(); #endif
DBCLASS_KdPrint((0, "'Class Registration\n")); LOGENTRY(LOG_MISC, 'REGc', ControllerFdo, 0, 0);
// initialize here
DBCLASS_Initialize();
// search our list if we find the TopOfStack device
// object then this must be a filter driver, otherwise
// allocate a new context structure for this controller
if (ControllerSig == DBC_OEM_FILTER_SIG) {
KeAcquireSpinLock(&DBCLASS_ControllerListSpin, &irql);
dbcContext = DBCLASS_ControllerList;
while (dbcContext) { if (dbcContext->TopOfStack == TopOfPdoStack) {
// we have a DBC filter, update our
// TopOfStack DeviceObject so that
// the filter gets called first
DBCLASS_KdPrint((0, "'>Registering Filter\n"));
dbcContext->TopOfStack = ControllerFdo; KeReleaseSpinLock(&DBCLASS_ControllerListSpin, irql); return STATUS_SUCCESS; }
dbcContext = dbcContext->Next; }
KeReleaseSpinLock(&DBCLASS_ControllerListSpin, irql);
DBCLASS_KdPrint((0, "'>Register Filter, could not find controller?\n"));
} else { // create a context structure for this controller
DBCLASS_KdPrint((0, "'>Registering Controller\n"));
KeAcquireSpinLock(&DBCLASS_ControllerListSpin, &irql); dbcContext = DbcExAllocatePool(NonPagedPool, sizeof(*dbcContext)); if (dbcContext) { RtlZeroMemory(dbcContext, sizeof(*dbcContext));
dbcContext->Sig = DBC_CONTEXT_SIG; dbcContext->Next = DBCLASS_ControllerList; DBCLASS_ControllerList = dbcContext; dbcContext->TopOfStack = ControllerFdo; dbcContext->ControllerFdo = ControllerFdo; // consider ourselves initially stopped
dbcContext->Stopped = TRUE; dbcContext->ControllerSig = ControllerSig; dbcContext->ControllerPdo = ControllerPdo; dbcContext->TopOfPdoStack = TopOfPdoStack;
DBCLASS_KdPrint((0, "'ControllerFdo (%08X) ControllerPdo (%08X) TopOfPdoStack (%08X) TopOfStack (%08X) DbcContext (%08X)\n", dbcContext->ControllerFdo, dbcContext->ControllerPdo, dbcContext->TopOfPdoStack, dbcContext->TopOfStack, dbcContext));
ntStatus = STATUS_SUCCESS; } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; }
KeReleaseSpinLock(&DBCLASS_ControllerListSpin, irql);
}
LOGENTRY(LOG_MISC, 'rEGc', ControllerFdo, ntStatus, 0); return ntStatus; }
NTSTATUS DBCLASS_PortQDeviceRelationsComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
/*++
Routine Description:
Arguments:
DeviceObject - a pointer to the device object
Irp - a pointer to the irp
Context - NULL ptr
Return Value:
STATUS_SUCCESS
--*/
{ PDBC_CONTEXT dbcContext = Context; PIO_STACK_LOCATION irpStack; PDEVICE_RELATIONS oldList, newList; PDEVICE_EXTENSION deviceExtension; ULONG pdoCount, i; // we are interested in REMOVAL_RELATIONS
irpStack = IoGetCurrentIrpStackLocation (Irp);
DBCLASS_ASSERT(IRP_MJ_PNP == irpStack->MajorFunction); DBCLASS_ASSERT(IRP_MN_QUERY_DEVICE_RELATIONS == irpStack->MinorFunction); switch (irpStack->Parameters.QueryDeviceRelations.Type) { case RemovalRelations:
//
// Add the PDOs for the device bay devices to the list
//
oldList = (PDEVICE_RELATIONS) Irp->IoStatus.Information; newList = NULL;
if (oldList) { pdoCount = oldList->Count; } else { // empty list
pdoCount = 0; }
//
// count our PDOs
//
for (i=1; i<=NUMBER_OF_BAYS(dbcContext); i++) { if (dbcContext->BayInformation[i].DeviceFilterObject) { pdoCount++; } }
if (pdoCount) { newList = ExAllocatePoolWithTag(PagedPool, sizeof(*newList) + (pdoCount - 1) * sizeof(PDEVICE_OBJECT), DBC_TAG); } if (newList) { newList->Count = pdoCount = 0;
// add the old list to the new list
if (oldList) { for (i=0; i< oldList->Count; i++) { newList->Objects[pdoCount] = oldList->Objects[i]; newList->Count++; pdoCount++; } } // free the old list
ExFreePool(oldList); // add our PDOs to the list;
for (i=1; i<=NUMBER_OF_BAYS(dbcContext); i++) { if (dbcContext->BayInformation[i].DeviceFilterObject) { deviceExtension = dbcContext->BayInformation[i].DeviceFilterObject->DeviceExtension; newList->Objects[pdoCount] = deviceExtension->PhysicalDeviceObject; pdoCount++; newList->Count++; } }
Irp->IoStatus.Information = PtrToUlong(newList); } break; default: break; } return STATUS_SUCCESS; }
NTSTATUS DBCLASS_UnRegisterController( IN PDEVICE_OBJECT ControllerFdo, IN PDEVICE_OBJECT TopOfStack ) /*++
Routine Description:
Arguments:
Return Value:
None
--*/ {
// locate which instance of the class driver is associated
// with this DBC.
PDBC_CONTEXT dbcContext = NULL; PDBC_CONTEXT prev = NULL;
prev = dbcContext = DBCLASS_ControllerList;
while (dbcContext) {
if (dbcContext->ControllerFdo == ControllerFdo) { // remove controller
DBCLASS_KdPrint((0, "'>UnRegister Controller\n")); DBCLASS_KdPrint((0, "'ControllerFdo (%08X) ControllerPdo (%08X) TopOfPdoStack (%08X) TopOfStack (%08X) FilterMDOUSB (%08X) DbcContext (%08X)\n", dbcContext->ControllerFdo, dbcContext->ControllerPdo, dbcContext->TopOfPdoStack, dbcContext->TopOfStack, dbcContext->BusFilterMdoUSB, dbcContext));
// unlink
if (DBCLASS_ControllerList == dbcContext) { DBCLASS_ControllerList = dbcContext->Next; } else { DBCLASS_ASSERT(prev->Next == dbcContext); prev->Next = dbcContext->Next; }
DBCLASS_RemoveControllerFromMdo(dbcContext);
DbcExFreePool(dbcContext); break; }
prev = dbcContext; dbcContext = dbcContext->Next; } LOGENTRY(LOG_MISC, 'UNRc', dbcContext, 0, 0); #if DBG
if (dbcContext == NULL) { DBCLASS_KdPrint((0, "'Controller not Found\n")); TRAP(); } #endif
return STATUS_SUCCESS; }
NTSTATUS DBCLASS_ClassDispatch( IN PDEVICE_OBJECT ControllerFdo, IN PIRP Irp, IN PBOOLEAN HandledByClass ) /*++
Routine Description:
Arguments:
Return Value:
None
--*/ { PIO_STACK_LOCATION irpStack; NTSTATUS ntStatus; PDBC_CONTEXT dbcContext;
*HandledByClass = FALSE; dbcContext = DBCLASS_GetDbcContext(ControllerFdo);
LOGENTRY(LOG_MISC, 'dIRP', ControllerFdo, 0, Irp);
if (dbcContext == NULL) { DBCLASS_KdPrint((0, "'Invalid ControllerFdo passed in\n")); TRAP(); ntStatus = STATUS_INVALID_PARAMETER; *HandledByClass = TRUE; goto DBCLASS_Dispatch_Done; }
ntStatus = Irp->IoStatus.Status; irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_POWER:
ntStatus = DBCLASS_ClassPower(ControllerFdo, Irp, HandledByClass); goto DBCLASS_Dispatch_Exit; break; /* IRP_MJ_POWER */ case IRP_MJ_PNP: switch (irpStack->MinorFunction) { case IRP_MN_QUERY_DEVICE_RELATIONS: // handle Q_BUS_RELATIONS for the port driver
*HandledByClass = TRUE; // hook the completion and pass on
IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, DBCLASS_PortQDeviceRelationsComplete, dbcContext, TRUE, TRUE, TRUE); ntStatus = IoCallDriver(dbcContext->TopOfStack, Irp); // we did the calldown for the port driver so
// all we do now is exit
goto DBCLASS_Dispatch_Exit; break; case IRP_MN_START_DEVICE: DBCLASS_KdPrint((1, "'IRP_MN_START_DEVICE\n")); ntStatus = DBCLASS_StartController(dbcContext, Irp, HandledByClass); break;
#if 0
case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: #if DBG
if (irpStack->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE) { DBCLASS_KdPrint((1, "'IRP_MN_QUERY_REMOVE_DEVICE\n")); } else { DBCLASS_KdPrint((1, "'IRP_MN_QUERY_STOP_DEVICE\n")); } #endif
// would like to eject the devices at this
// point -- instead I will fail if we have devices in
// the bays!
{ BOOLEAN empty = TRUE; USHORT bay; for (bay=1; bay <=NUMBER_OF_BAYS(dbcContext); bay++) { if (dbcContext->BayInformation[bay].DeviceFilterObject != NULL) { empty = FALSE; break; } }
if (!empty) { *HandledByClass = TRUE; ntStatus = STATUS_UNSUCCESSFUL; DBCLASS_KdPrint((1, "'Bays not Empty!")); goto DBCLASS_Dispatch_Done; } } break; #endif
case IRP_MN_STOP_DEVICE: DBCLASS_KdPrint((1, "'IRP_MN_STOP_DEVICE\n")); ntStatus = DBCLASS_StopController(dbcContext, Irp, HandledByClass); if (NT_SUCCESS(ntStatus)) { // free allocated resources
ntStatus = DBCLASS_CleanupController(dbcContext); } dbcContext->Stopped = TRUE; LOGENTRY(LOG_MISC, 'STPd', dbcContext, 0, ntStatus); break; case IRP_MN_REMOVE_DEVICE: DBCLASS_KdPrint((1, "'IRP_MN_REMOVE_DEVICE\n")); DBCLASS_KdPrint((1, "'FDO (%08X)\n", ControllerFdo)); if (!dbcContext->Stopped) { ntStatus = DBCLASS_StopController(dbcContext, Irp, HandledByClass); if (NT_SUCCESS(ntStatus)) { // free allocated resources
ntStatus = DBCLASS_CleanupController(dbcContext); } } else { ntStatus = STATUS_SUCCESS; }
LOGENTRY(LOG_MISC, 'RMVd', dbcContext, 0, ntStatus); break; } break; case IRP_MJ_CREATE: case IRP_MJ_CLOSE: ntStatus = STATUS_SUCCESS; break; default: //
// Irp is not interesting to us
LOGENTRY(LOG_MISC, 'pIRP', ControllerFdo, 0, Irp); break; }; /* case MJ_FUNCTION */
DBCLASS_Dispatch_Done:
if (*HandledByClass) { DBCLASS_KdPrint((2, "'Completing Irp\n")); Irp->IoStatus.Status = ntStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); }
DBCLASS_Dispatch_Exit:
return ntStatus; }
NTSTATUS DBCLASS_FilterDispatch( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++
Routine Description:
figure out what type of FDO we are and dispatch to the appropriate handler Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/ { PIO_STACK_LOCATION irpStack; NTSTATUS ntStatus; PDEVICE_EXTENSION deviceExtension; BOOLEAN handled = FALSE; PDEVICE_OBJECT topOfStackDeviceObject; ULONG MinFunc, MajFunc;
deviceExtension = DeviceObject->DeviceExtension; topOfStackDeviceObject = deviceExtension->TopOfStackDeviceObject;
LOGENTRY(LOG_MISC, 'FLT>', 0, DeviceObject, Irp); irpStack = IoGetCurrentIrpStackLocation(Irp);
MinFunc = irpStack->MinorFunction; MajFunc = irpStack->MajorFunction; // figure out what kind of PDO this call is bound for
switch(deviceExtension->FdoType) { case DB_FDO_BUS_IGNORE: break; case DB_FDO_BUS_UNKNOWN: ntStatus = DBCLASS_BusFilterDispatch( DeviceObject, Irp, &handled); break; case DB_FDO_USBHUB_BUS: ntStatus = DBCLASS_UsbhubBusFilterDispatch( DeviceObject, Irp, &handled); break; case DB_FDO_USB_DEVICE: case DB_FDO_1394_DEVICE: ntStatus = DBCLASS_PdoFilterDispatch( DeviceObject, Irp, &handled); break; case DB_FDO_1394_BUS: ntStatus = DBCLASS_1394BusFilterDispatch( DeviceObject, Irp, &handled); break; default: DBCLASS_KdPrint((0, "'Invalid Extension Signature")); TRAP(); }
if (!handled) {
if(MajFunc == IRP_MJ_POWER) { PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); ntStatus = PoCallDriver(topOfStackDeviceObject, Irp);
if(ntStatus) { DBCLASS_KdPrint((2, "'Filter Power Dispatch Status (%08X)\n", ntStatus)); }
} else { // all filters behave pretty much the same
// if the routine we called did not want to
// handle the IRP we take the default action
// here.
IoSkipCurrentIrpStackLocation(Irp); ntStatus = IoCallDriver(topOfStackDeviceObject, Irp);
if(ntStatus) { DBCLASS_KdPrint((2, "'Filter Dispatch Status (%08X)\n", ntStatus)); } }
}
LOGENTRY(LOG_MISC, 'PNP<', ntStatus, DeviceObject, 0); return ntStatus; }
#if 0
NTSTATUS DBCLASS_SetD0_Complete( PDEVICE_OBJECT ControllerFdo, PIRP Irp ) /*++
Routine Description:
Called by port driver when the port driver enters D0. Arguments:
DeviceObject - Device bay Filter FDO
Return Value:
NTSTATUS
--*/ { PIO_STACK_LOCATION irpStack; NTSTATUS ntStatus = STATUS_SUCCESS; PDBC_CONTEXT dbcContext; LOGENTRY(LOG_MISC, 'D0cp', 0, ControllerFdo, Irp); irpStack = IoGetCurrentIrpStackLocation(Irp); dbcContext = DBCLASS_GetDbcContext(ControllerFdo); DBCLASS_KdPrint((0, "'Set DevicePowerState = D0\n")); dbcContext->CurrentDevicePowerState = PowerDeviceD0; return ntStatus; } #endif
NTSTATUS DBCLASS_RegisterBusFilter( ULONG DbclassVersion, PDRIVER_OBJECT FilterDriverObject, PDEVICE_OBJECT FilterMdo ) /*++
Routine Description:
find the controller for this PDO and associate the PDO with the correct bay Arguments:
Return Value:
NTSTATUS --*/ { PDEVICE_EXTENSION deviceExtension; NTSTATUS ntStatus = STATUS_SUCCESS;
deviceExtension = FilterMdo->DeviceExtension;
// initialize here
DBCLASS_Initialize(); LOGENTRY(LOG_MISC, 'rPDO', 0, FilterMdo, 0); DBCLASS_KdPrint((0, "'Register Bus Filter FDO(%x)\n", FilterMdo));
// The bus filter handle one instance of the 1394 bus --
// which may have multiple DBCs associated with it.
// therefore we don't use the Context field in the bus filter
// extension
deviceExtension->DbcContext = (PDBC_CONTEXT) -1;
// Put the filter MDO on our list of bus filters
DBCLASS_AddBusFilterMDOToList(FilterMdo); return ntStatus; }
NTSTATUS DBCLASS_AddBusFilterMDOToList( PDEVICE_OBJECT BusFilterMdo )
/*++
Routine Description:
Adds a bus filter to our internal list
Arguments:
Return Value:
NTSTATUS --*/
{ PDBCLASS_PDO_LIST newEntry;
newEntry = ExAllocatePool(NonPagedPool, sizeof(DBCLASS_PDO_LIST));
DBCLASS_ASSERT(newEntry);
if (newEntry == NULL) { TRAP(); return STATUS_INSUFFICIENT_RESOURCES; }
// Fill in fields in new entry
newEntry->FilterDeviceObject = BusFilterMdo;
// Add new entry to end of list
InsertTailList(&DBCLASS_BusFilterMdoList, &newEntry->ListEntry);
DBCLASS_KdPrint((2, "'AddBusFilterMdo (%08X)\n", BusFilterMdo));
return STATUS_SUCCESS; }
VOID DBCLASS_RemoveBusFilterMDOFromList( IN PDEVICE_OBJECT BusFilterMdo )
/*++
Routine Description:
Removes a bus filter from the internal list Arguments:
BusFilterMdo - a pointer to the device object to remove.
Return Value:
VOID
--*/
{ PDBCLASS_PDO_LIST entry; PLIST_ENTRY listEntry;
listEntry = &DBCLASS_BusFilterMdoList;
if (!IsListEmpty(listEntry)) { listEntry = DBCLASS_BusFilterMdoList.Flink; } while (listEntry != &DBCLASS_BusFilterMdoList) { entry = CONTAINING_RECORD(listEntry, DBCLASS_PDO_LIST, ListEntry); DBCLASS_ASSERT(entry);
if (entry->FilterDeviceObject == BusFilterMdo) break;
listEntry = entry->ListEntry.Flink;
}
// we should always find it
DBCLASS_ASSERT(listEntry != &DBCLASS_BusFilterMdoList);
DBCLASS_KdPrint((2, "'RemoveBusFilterMdo (%08X)\n", BusFilterMdo)); RemoveEntryList(listEntry); ExFreePool(entry); }
VOID DBCLASS_Refresh1394( )
/*++
Routine Description:
Removes a bus filter from the internal list Arguments:
DeviceObject - a pointer to the device object to remove.
Return Value:
VOID
--*/
{ PDBCLASS_PDO_LIST entry; PLIST_ENTRY listEntry; PDEVICE_EXTENSION busFilterDeviceExtension; PDEVICE_OBJECT FilterDevObj;
listEntry = &DBCLASS_BusFilterMdoList;
if (!IsListEmpty(listEntry)) { listEntry = DBCLASS_BusFilterMdoList.Flink; } while (listEntry != &DBCLASS_BusFilterMdoList) {
entry = CONTAINING_RECORD(listEntry, DBCLASS_PDO_LIST, ListEntry); DBCLASS_ASSERT(entry);
FilterDevObj = entry->FilterDeviceObject;
DBCLASS_KdPrint((2, "'Refresh1394 Entry (%08X) FilterDevObj (%08X)\n", entry, FilterDevObj));
if(FilterDevObj) { busFilterDeviceExtension = FilterDevObj->DeviceExtension;
if(busFilterDeviceExtension) { if (busFilterDeviceExtension->FdoType == DB_FDO_1394_BUS) { DBCLASS_KdPrint((0, "'IoInvalidate 1394\n")); IoInvalidateDeviceRelations(busFilterDeviceExtension->PhysicalDeviceObject, BusRelations); } } }
listEntry = entry->ListEntry.Flink;
}
}
VOID DBCLASS_RemoveControllerFromMdo(PDBC_CONTEXT DbcContext)
/*++
Routine Description:
Removes reference to USB controller from a filter Return Value:
VOID
--*/
{ PDBCLASS_PDO_LIST entry; PLIST_ENTRY listEntry; PDEVICE_EXTENSION busFilterDeviceExtension; PDEVICE_OBJECT FilterDevObj;
listEntry = &DBCLASS_DevicePdoList;
if (!IsListEmpty(listEntry)) { listEntry = DBCLASS_DevicePdoList.Flink; } while (listEntry != &DBCLASS_DevicePdoList) {
entry = CONTAINING_RECORD(listEntry, DBCLASS_PDO_LIST, ListEntry); DBCLASS_ASSERT(entry);
FilterDevObj = entry->FilterDeviceObject;
if(FilterDevObj) { busFilterDeviceExtension = FilterDevObj->DeviceExtension;
if(busFilterDeviceExtension) { if (busFilterDeviceExtension->DbcContext == DbcContext) { DBCLASS_KdPrint((2, "'Remove Controller From FilterDevObj (%08X)\n", FilterDevObj));
busFilterDeviceExtension->DbcContext = NULL; } } }
listEntry = entry->ListEntry.Flink;
}
}
|