/drivers/storage/classpnp/class.c
C | 9183 lines | 6777 code | 933 blank | 1473 comment | 409 complexity | 57fb997264080c066297aa10d46bb03d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-3.0, AGPL-3.0, GPL-3.0, CPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*++
- Copyright (C) Microsoft Corporation, 1991 - 1999
- Module Name:
- class.c
- Abstract:
- SCSI class driver routines
- Environment:
- kernel mode only
- Notes:
- Revision History:
- --*/
- #define CLASS_INIT_GUID 1
- #include "classp.h"
- #include "debug.h"
- #ifdef ALLOC_PRAGMA
- #pragma alloc_text(INIT, DriverEntry)
- #pragma alloc_text(PAGE, ClassAddDevice)
- #pragma alloc_text(PAGE, ClassClaimDevice)
- #pragma alloc_text(PAGE, ClassCreateDeviceObject)
- #pragma alloc_text(PAGE, ClassDispatchPnp)
- #pragma alloc_text(PAGE, ClassGetDescriptor)
- #pragma alloc_text(PAGE, ClassGetPdoId)
- #pragma alloc_text(PAGE, ClassInitialize)
- #pragma alloc_text(PAGE, ClassInitializeEx)
- #pragma alloc_text(PAGE, ClassInvalidateBusRelations)
- #pragma alloc_text(PAGE, ClassMarkChildMissing)
- #pragma alloc_text(PAGE, ClassMarkChildrenMissing)
- #pragma alloc_text(PAGE, ClassModeSense)
- #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations)
- #pragma alloc_text(PAGE, ClassPnpStartDevice)
- #pragma alloc_text(PAGE, ClassQueryPnpCapabilities)
- #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue)
- #pragma alloc_text(PAGE, ClassRemoveDevice)
- #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations)
- #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry)
- #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous)
- #pragma alloc_text(PAGE, ClassUnload)
- #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest)
- #pragma alloc_text(PAGE, ClasspFreeReleaseRequest)
- #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo)
- #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface)
- #pragma alloc_text(PAGE, ClasspScanForClassHacks)
- #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry)
- #endif
- ULONG ClassPnpAllowUnload = TRUE;
- #define FirstDriveLetter 'C'
- #define LastDriveLetter 'Z'
- /*++////////////////////////////////////////////////////////////////////////////
- DriverEntry()
- Routine Description:
- Temporary entry point needed to initialize the class system dll.
- It doesn't do anything.
- Arguments:
- DriverObject - Pointer to the driver object created by the system.
- Return Value:
- STATUS_SUCCESS
- --*/
- NTSTATUS
- NTAPI
- DriverEntry(
- IN PDRIVER_OBJECT DriverObject,
- IN PUNICODE_STRING RegistryPath
- )
- {
- return STATUS_SUCCESS;
- }
- /*++////////////////////////////////////////////////////////////////////////////
- ClassInitialize()
- Routine Description:
- This routine is called by a class driver during its
- DriverEntry routine to initialize the driver.
- Arguments:
- Argument1 - Driver Object.
- Argument2 - Registry Path.
- InitializationData - Device-specific driver's initialization data.
- Return Value:
- A valid return code for a DriverEntry routine.
- --*/
- ULONG
- ClassInitialize(
- IN PVOID Argument1,
- IN PVOID Argument2,
- IN PCLASS_INIT_DATA InitializationData
- )
- {
- PDRIVER_OBJECT DriverObject = Argument1;
- PUNICODE_STRING RegistryPath = Argument2;
- PCLASS_DRIVER_EXTENSION driverExtension;
- NTSTATUS status;
- PAGED_CODE();
-
- DebugPrint((3,"\n\nSCSI Class Driver\n"));
- ClasspInitializeDebugGlobals();
- //
- // Validate the length of this structure. This is effectively a
- // version check.
- //
- if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0,"ClassInitialize: Class driver wrong version\n"));
- return (ULONG) STATUS_REVISION_MISMATCH;
- }
- //
- // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
- // are not required entry points.
- //
- if ((!InitializationData->FdoData.ClassDeviceControl) ||
- (!((InitializationData->FdoData.ClassReadWriteVerification) ||
- (InitializationData->ClassStartIo))) ||
- (!InitializationData->ClassAddDevice) ||
- (!InitializationData->FdoData.ClassStartDevice)) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0,
- "ClassInitialize: Class device-specific driver missing required "
- "FDO entry\n"));
- return (ULONG) STATUS_REVISION_MISMATCH;
- }
- if ((InitializationData->ClassEnumerateDevice) &&
- ((!InitializationData->PdoData.ClassDeviceControl) ||
- (!InitializationData->PdoData.ClassStartDevice) ||
- (!((InitializationData->PdoData.ClassReadWriteVerification) ||
- (InitializationData->ClassStartIo))))) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0, "ClassInitialize: Class device-specific missing "
- "required PDO entry\n"));
- return (ULONG) STATUS_REVISION_MISMATCH;
- }
- if((InitializationData->FdoData.ClassStopDevice == NULL) ||
- ((InitializationData->ClassEnumerateDevice != NULL) &&
- (InitializationData->PdoData.ClassStopDevice == NULL))) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0, "ClassInitialize: Class device-specific missing "
- "required PDO entry\n"));
- ASSERT(FALSE);
- return (ULONG) STATUS_REVISION_MISMATCH;
- }
- //
- // Setup the default power handlers if the class driver didn't provide
- // any.
- //
- if(InitializationData->FdoData.ClassPowerDevice == NULL) {
- InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler;
- }
- if((InitializationData->ClassEnumerateDevice != NULL) &&
- (InitializationData->PdoData.ClassPowerDevice == NULL)) {
- InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler;
- }
- //
- // warn that unload is not supported
- //
- // ISSUE-2000/02/03-peterwie
- // We should think about making this a fatal error.
- //
- if(InitializationData->ClassUnload == NULL) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n",
- RegistryPath));
- }
- //
- // Create an extension for the driver object
- //
- status = IoAllocateDriverObjectExtension(DriverObject,
- CLASS_DRIVER_EXTENSION_KEY,
- sizeof(CLASS_DRIVER_EXTENSION),
- &driverExtension);
- if(NT_SUCCESS(status)) {
- //
- // Copy the registry path into the driver extension so we can use it later
- //
- driverExtension->RegistryPath.Length = RegistryPath->Length;
- driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
- driverExtension->RegistryPath.Buffer =
- ExAllocatePoolWithTag(PagedPool,
- RegistryPath->MaximumLength,
- '1CcS');
- if(driverExtension->RegistryPath.Buffer == NULL) {
- status = STATUS_INSUFFICIENT_RESOURCES;
- return status;
- }
- RtlCopyUnicodeString(
- &(driverExtension->RegistryPath),
- RegistryPath);
- //
- // Copy the initialization data into the driver extension so we can reuse
- // it during our add device routine
- //
- RtlCopyMemory(
- &(driverExtension->InitData),
- InitializationData,
- sizeof(CLASS_INIT_DATA));
- driverExtension->DeviceCount = 0;
- } else if (status == STATUS_OBJECT_NAME_COLLISION) {
- //
- // The extension already exists - get a pointer to it
- //
- driverExtension = IoGetDriverObjectExtension(DriverObject,
- CLASS_DRIVER_EXTENSION_KEY);
- ASSERT(driverExtension != NULL);
- } else {
- DebugPrint((1, "ClassInitialize: Class driver extension could not be "
- "allocated %lx\n", status));
- return status;
- }
- //
- // Update driver object with entry points.
- //
- DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreateClose;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassCreateClose;
- DriverObject->MajorFunction[IRP_MJ_READ] = ClassReadWrite;
- DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassReadWrite;
- DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassInternalIoControl;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch;
- DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassShutdownFlush;
- DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush;
- DriverObject->MajorFunction[IRP_MJ_PNP] = ClassDispatchPnp;
- DriverObject->MajorFunction[IRP_MJ_POWER] = ClassDispatchPower;
- DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl;
- if (InitializationData->ClassStartIo) {
- DriverObject->DriverStartIo = ClasspStartIo;
- }
- if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) {
- DriverObject->DriverUnload = ClassUnload;
- } else {
- DriverObject->DriverUnload = NULL;
- }
- DriverObject->DriverExtension->AddDevice = ClassAddDevice;
- DbgPrint("Driver is ready to go\n");
- status = STATUS_SUCCESS;
- return status;
- } // end ClassInitialize()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassInitializeEx()
- Routine Description:
- This routine is allows the caller to do any extra initialization or
- setup that is not done in ClassInitialize. The operation is
- controlled by the GUID that is passed and the contents of the Data
- parameter is dependent upon the GUID.
- This is the list of supported operations:
- Guid - GUID_CLASSPNP_QUERY_REGINFOEX
- Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer
- Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX
- callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The
- former callback allows the driver to specify the name of the
- mof resource.
- Arguments:
- DriverObject
- Guid
- Data
- Return Value:
- Status Code
- --*/
- ULONG
- ClassInitializeEx(
- IN PDRIVER_OBJECT DriverObject,
- IN LPGUID Guid,
- IN PVOID Data
- )
- {
- PCLASS_DRIVER_EXTENSION driverExtension;
- NTSTATUS status;
- PAGED_CODE();
- driverExtension = IoGetDriverObjectExtension( DriverObject,
- CLASS_DRIVER_EXTENSION_KEY
- );
- if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx))
- {
- PCLASS_QUERY_WMI_REGINFO_EX_LIST List;
- //
- // Indicate the device supports PCLASS_QUERY_REGINFO_EX
- // callback instead of PCLASS_QUERY_REGINFO callback.
- //
- List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data;
- if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST))
- {
- driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx;
- driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx;
- status = STATUS_SUCCESS;
- } else {
- status = STATUS_INVALID_PARAMETER;
- }
- } else {
- status = STATUS_NOT_SUPPORTED;
- }
- return(status);
- } // end ClassInitializeEx()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassUnload()
- Routine Description:
- called when there are no more references to the driver. this allows
- drivers to be updated without rebooting.
- Arguments:
- DriverObject - a pointer to the driver object that is being unloaded
- Status:
- --*/
- VOID
- ClassUnload(
- IN PDRIVER_OBJECT DriverObject
- )
- {
- PCLASS_DRIVER_EXTENSION driverExtension;
- NTSTATUS status;
- PAGED_CODE();
- ASSERT( DriverObject->DeviceObject == NULL );
- driverExtension = IoGetDriverObjectExtension( DriverObject,
- CLASS_DRIVER_EXTENSION_KEY
- );
- ASSERT(driverExtension != NULL);
- ASSERT(driverExtension->RegistryPath.Buffer != NULL);
- ASSERT(driverExtension->InitData.ClassUnload != NULL);
- DebugPrint((1, "ClassUnload: driver unloading %wZ\n",
- &driverExtension->RegistryPath));
- //
- // attempt to process the driver's unload routine first.
- //
- driverExtension->InitData.ClassUnload(DriverObject);
- //
- // free own allocated resources and return
- //
- ExFreePool( driverExtension->RegistryPath.Buffer );
- driverExtension->RegistryPath.Buffer = NULL;
- driverExtension->RegistryPath.Length = 0;
- driverExtension->RegistryPath.MaximumLength = 0;
- return;
- } // end ClassUnload()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassAddDevice()
- Routine Description:
- SCSI class driver add device routine. This is called by pnp when a new
- physical device come into being.
- This routine will call out to the class driver to verify that it should
- own this device then will create and attach a device object and then hand
- it to the driver to initialize and create symbolic links
- Arguments:
- DriverObject - a pointer to the driver object that this is being created for
- PhysicalDeviceObject - a pointer to the physical device object
- Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device
- STATUS_SUCCESS if the creation and attachment was successful
- status of device creation and initialization
- --*/
- NTSTATUS
- ClassAddDevice(
- IN PDRIVER_OBJECT DriverObject,
- IN PDEVICE_OBJECT PhysicalDeviceObject
- )
- {
- PCLASS_DRIVER_EXTENSION driverExtension =
- IoGetDriverObjectExtension(DriverObject,
- CLASS_DRIVER_EXTENSION_KEY);
- NTSTATUS status;
- PAGED_CODE();
- DbgPrint("got a device\n");
- status = driverExtension->InitData.ClassAddDevice(DriverObject,
- PhysicalDeviceObject);
- return status;
- } // end ClassAddDevice()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassDispatchPnp()
- Routine Description:
- Storage class driver pnp routine. This is called by the io system when
- a PNP request is sent to the device.
- Arguments:
- DeviceObject - pointer to the device object
- Irp - pointer to the io request packet
- Return Value:
- status
- --*/
- NTSTATUS
- ClassDispatchPnp(
- IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp
- )
- {
- PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
- BOOLEAN isFdo = commonExtension->IsFdo;
- PCLASS_DRIVER_EXTENSION driverExtension;
- PCLASS_INIT_DATA initData;
- PCLASS_DEV_INFO devInfo;
- PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
- PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
- NTSTATUS status = Irp->IoStatus.Status;
- BOOLEAN completeRequest = TRUE;
- BOOLEAN lockReleased = FALSE;
- ULONG isRemoved;
- PAGED_CODE();
- //
- // Extract all the useful information out of the driver object
- // extension
- //
- driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
- CLASS_DRIVER_EXTENSION_KEY);
- if (driverExtension){
- initData = &(driverExtension->InitData);
- if(isFdo) {
- devInfo = &(initData->FdoData);
- } else {
- devInfo = &(initData->PdoData);
- }
- isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
- DebugPrint((2, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n",
- DeviceObject, Irp,
- irpStack->MinorFunction,
- isFdo ? "fdo" : "pdo",
- DeviceObject));
- DebugPrint((2, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n",
- DeviceObject, Irp,
- commonExtension->PreviousState,
- commonExtension->CurrentState));
- switch(irpStack->MinorFunction) {
- case IRP_MN_START_DEVICE: {
- //
- // if this is sent to the FDO we should forward it down the
- // attachment chain before we start the FDO.
- //
- if (isFdo) {
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- }
- else {
- status = STATUS_SUCCESS;
- }
- if (NT_SUCCESS(status)){
- status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject);
- }
- break;
- }
- case IRP_MN_QUERY_DEVICE_RELATIONS: {
- DEVICE_RELATION_TYPE type =
- irpStack->Parameters.QueryDeviceRelations.Type;
- PDEVICE_RELATIONS deviceRelations = NULL;
- if(!isFdo) {
- if(type == TargetDeviceRelation) {
- //
- // Device relations has one entry built in to it's size.
- //
- status = STATUS_INSUFFICIENT_RESOURCES;
- deviceRelations = ExAllocatePoolWithTag(PagedPool,
- sizeof(DEVICE_RELATIONS),
- '2CcS');
- if(deviceRelations != NULL) {
- RtlZeroMemory(deviceRelations,
- sizeof(DEVICE_RELATIONS));
- Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
- deviceRelations->Count = 1;
- deviceRelations->Objects[0] = DeviceObject;
- ObReferenceObject(deviceRelations->Objects[0]);
- status = STATUS_SUCCESS;
- }
- } else {
- //
- // PDO's just complete enumeration requests without altering
- // the status.
- //
- status = Irp->IoStatus.Status;
- }
- break;
- } else if (type == BusRelations) {
- ASSERT(commonExtension->IsInitialized);
- //
- // Make sure we support enumeration
- //
- if(initData->ClassEnumerateDevice == NULL) {
- //
- // Just send the request down to the lower driver. Perhaps
- // It can enumerate children.
- //
- } else {
- //
- // Re-enumerate the device
- //
- status = ClassPnpQueryFdoRelations(DeviceObject, Irp);
- if(!NT_SUCCESS(status)) {
- completeRequest = TRUE;
- break;
- }
- }
- }
- IoCopyCurrentIrpStackLocationToNext(Irp);
- ClassReleaseRemoveLock(DeviceObject, Irp);
- status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
- completeRequest = FALSE;
- break;
- }
- case IRP_MN_QUERY_ID: {
- BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType;
- UNICODE_STRING unicodeString;
- if(isFdo) {
- //
- // FDO's should just forward the query down to the lower
- // device objects
- //
- IoCopyCurrentIrpStackLocationToNext(Irp);
- ClassReleaseRemoveLock(DeviceObject, Irp);
- status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
- completeRequest = FALSE;
- break;
- }
- //
- // PDO's need to give an answer - this is easy for now
- //
- RtlInitUnicodeString(&unicodeString, NULL);
- status = ClassGetPdoId(DeviceObject,
- idType,
- &unicodeString);
- if(status == STATUS_NOT_IMPLEMENTED) {
- //
- // The driver doesn't implement this ID (whatever it is).
- // Use the status out of the IRP so that we don't mangle a
- // response from someone else.
- //
- status = Irp->IoStatus.Status;
- } else if(NT_SUCCESS(status)) {
- Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
- } else {
- Irp->IoStatus.Information = (ULONG_PTR) NULL;
- }
- break;
- }
- case IRP_MN_QUERY_STOP_DEVICE:
- case IRP_MN_QUERY_REMOVE_DEVICE: {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n",
- DeviceObject, Irp,
- ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
- "STOP" : "REMOVE")));
- //
- // If this device is in use for some reason (paging, etc...)
- // then we need to fail the request.
- //
- if(commonExtension->PagingPathCount != 0) {
- DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging "
- "path and cannot be removed\n",
- DeviceObject, Irp));
- status = STATUS_DEVICE_BUSY;
- break;
- }
- //
- // Check with the class driver to see if the query operation
- // can succeed.
- //
- if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
- status = devInfo->ClassStopDevice(DeviceObject,
- irpStack->MinorFunction);
- } else {
- status = devInfo->ClassRemoveDevice(DeviceObject,
- irpStack->MinorFunction);
- }
- if(NT_SUCCESS(status)) {
- //
- // ASSERT that we never get two queries in a row, as
- // this will severly mess up the state machine
- //
- ASSERT(commonExtension->CurrentState != irpStack->MinorFunction);
- commonExtension->PreviousState = commonExtension->CurrentState;
- commonExtension->CurrentState = irpStack->MinorFunction;
- if(isFdo) {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_"
- "%s irp\n", DeviceObject, Irp,
- ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
- "STOP" : "REMOVE")));
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- }
- }
- DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n",
- DeviceObject, Irp, status));
- break;
- }
- case IRP_MN_CANCEL_STOP_DEVICE:
- case IRP_MN_CANCEL_REMOVE_DEVICE: {
- //
- // Check with the class driver to see if the query or cancel
- // operation can succeed.
- //
- if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
- status = devInfo->ClassStopDevice(DeviceObject,
- irpStack->MinorFunction);
- ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should "
- "never be failed\n", NT_SUCCESS(status));
- } else {
- status = devInfo->ClassRemoveDevice(DeviceObject,
- irpStack->MinorFunction);
- ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should "
- "never be failed\n", NT_SUCCESS(status));
- }
- Irp->IoStatus.Status = status;
- //
- // We got a CANCEL - roll back to the previous state only
- // if the current state is the respective QUERY state.
- //
- if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) &&
- (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE)
- ) ||
- ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) &&
- (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
- )
- ) {
- commonExtension->CurrentState =
- commonExtension->PreviousState;
- commonExtension->PreviousState = 0xff;
- }
- if(isFdo) {
- IoCopyCurrentIrpStackLocationToNext(Irp);
- ClassReleaseRemoveLock(DeviceObject, Irp);
- status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
- completeRequest = FALSE;
- } else {
- status = STATUS_SUCCESS;
- }
- break;
- }
- case IRP_MN_STOP_DEVICE: {
- //
- // These all mean nothing to the class driver currently. The
- // port driver will handle all queueing when necessary.
- //
- DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n",
- DeviceObject, Irp,
- (isFdo ? "fdo" : "pdo")
- ));
- ASSERT(commonExtension->PagingPathCount == 0);
- //
- // ISSUE-2000/02/03-peterwie
- // if we stop the timer here then it means no class driver can
- // do i/o in its ClassStopDevice routine. This is because the
- // retry (among other things) is tied into the tick handler
- // and disabling retries could cause the class driver to deadlock.
- // Currently no class driver we're aware of issues i/o in its
- // Stop routine but this is a case we may want to defend ourself
- // against.
- //
- if (DeviceObject->Timer) {
- IoStopTimer(DeviceObject);
- }
- status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE);
- ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should "
- "never be failed\n", NT_SUCCESS(status));
- if(isFdo) {
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- }
- if(NT_SUCCESS(status)) {
- commonExtension->CurrentState = irpStack->MinorFunction;
- commonExtension->PreviousState = 0xff;
- }
- break;
- }
- case IRP_MN_REMOVE_DEVICE:
- case IRP_MN_SURPRISE_REMOVAL: {
- PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
- UCHAR removeType = irpStack->MinorFunction;
- if (commonExtension->PagingPathCount != 0) {
- DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
- }
- //
- // Release the lock for this IRP before calling in.
- //
- ClassReleaseRemoveLock(DeviceObject, Irp);
- lockReleased = TRUE;
- /*
- * If a timer was started on the device, stop it.
- */
- if (DeviceObject->Timer) {
- IoStopTimer(DeviceObject);
- }
- /*
- * "Fire-and-forget" the remove irp to the lower stack.
- * Don't touch the irp (or the irp stack!) after this.
- */
- if (isFdo) {
- IoCopyCurrentIrpStackLocationToNext(Irp);
- status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
- ASSERT(NT_SUCCESS(status));
- completeRequest = FALSE;
- }
- else {
- status = STATUS_SUCCESS;
- }
- /*
- * Do our own cleanup and call the class driver's remove
- * cleanup routine.
- * For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
- * so don't touch the extension after this.
- */
- commonExtension->PreviousState = commonExtension->CurrentState;
- commonExtension->CurrentState = removeType;
- ClassRemoveDevice(DeviceObject, removeType);
- break;
- }
- case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
- switch(irpStack->Parameters.UsageNotification.Type) {
- case DeviceUsageTypePaging: {
- BOOLEAN setPagable;
- if((irpStack->Parameters.UsageNotification.InPath) &&
- (commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
- //
- // Device isn't started. Don't allow adding a
- // paging file, but allow a removal of one.
- //
- status = STATUS_DEVICE_NOT_READY;
- break;
- }
- ASSERT(commonExtension->IsInitialized);
- //
- // need to synchronize this now...
- //
- KeEnterCriticalRegion();
- status = KeWaitForSingleObject(&commonExtension->PathCountEvent,
- Executive, KernelMode,
- FALSE, NULL);
- ASSERT(NT_SUCCESS(status));
- status = STATUS_SUCCESS;
- //
- // If the volume is removable we should try to lock it in
- // place or unlock it once per paging path count
- //
- if (commonExtension->IsFdo){
- status = ClasspEjectionControl(
- DeviceObject,
- Irp,
- InternalMediaLock,
- (BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
- }
- if (!NT_SUCCESS(status)){
- KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
- KeLeaveCriticalRegion();
- break;
- }
- //
- // if removing last paging device, need to set DO_POWER_PAGABLE
- // bit here, and possible re-set it below on failure.
- //
- setPagable = FALSE;
- if (!irpStack->Parameters.UsageNotification.InPath &&
- commonExtension->PagingPathCount == 1
- ) {
- //
- // removing last paging file
- // must have DO_POWER_PAGABLE bits set, but only
- // if noone set the DO_POWER_INRUSH bit
- //
- if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
- "paging file removed, but "
- "DO_POWER_INRUSH was set, so NOT "
- "setting DO_POWER_PAGABLE\n",
- DeviceObject, Irp));
- } else {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
- "paging file removed, "
- "setting DO_POWER_PAGABLE\n",
- DeviceObject, Irp));
- SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
- setPagable = TRUE;
- }
- }
- //
- // forward the irp before finishing handling the
- // special cases
- //
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- //
- // now deal with the failure and success cases.
- // note that we are not allowed to fail the irp
- // once it is sent to the lower drivers.
- //
- if (NT_SUCCESS(status)) {
- IoAdjustPagingPathCount(
- &commonExtension->PagingPathCount,
- irpStack->Parameters.UsageNotification.InPath);
- if (irpStack->Parameters.UsageNotification.InPath) {
- if (commonExtension->PagingPathCount == 1) {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): "
- "Clearing PAGABLE bit\n",
- DeviceObject, Irp));
- CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
- }
- }
- } else {
- //
- // cleanup the changes done above
- //
- if (setPagable == TRUE) {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting "
- "PAGABLE bit due to irp failure\n",
- DeviceObject, Irp));
- CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
- setPagable = FALSE;
- }
- //
- // relock or unlock the media if needed.
- //
- if (commonExtension->IsFdo) {
- ClasspEjectionControl(
- DeviceObject,
- Irp,
- InternalMediaLock,
- (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
- }
- }
- //
- // set the event so the next one can occur.
- //
- KeSetEvent(&commonExtension->PathCountEvent,
- IO_NO_INCREMENT, FALSE);
- KeLeaveCriticalRegion();
- break;
- }
- case DeviceUsageTypeHibernation: {
- IoAdjustPagingPathCount(
- &commonExtension->HibernationPathCount,
- irpStack->Parameters.UsageNotification.InPath
- );
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- if (!NT_SUCCESS(status)) {
- IoAdjustPagingPathCount(
- &commonExtension->HibernationPathCount,
- !irpStack->Parameters.UsageNotification.InPath
- );
- }
- break;
- }
- case DeviceUsageTypeDumpFile: {
- IoAdjustPagingPathCount(
- &commonExtension->DumpPathCount,
- irpStack->Parameters.UsageNotification.InPath
- );
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- if (!NT_SUCCESS(status)) {
- IoAdjustPagingPathCount(
- &commonExtension->DumpPathCount,
- !irpStack->Parameters.UsageNotification.InPath
- );
- }
- break;
- }
- default: {
- status = STATUS_INVALID_PARAMETER;
- break;
- }
- }
- break;
- }
- case IRP_MN_QUERY_CAPABILITIES: {
- DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n",
- DeviceObject, Irp));
- if(!isFdo) {
- status = ClassQueryPnpCapabilities(
- DeviceObject,
- irpStack->Parameters.DeviceCapabilities.Capabilities
- );
- break;
- } else {
- PDEVICE_CAPABILITIES deviceCapabilities;
- PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
- PCLASS_PRIVATE_FDO_DATA fdoData;
- fdoExtension = DeviceObject->DeviceExtension;
- fdoData = fdoExtension->PrivateFdoData;
- deviceCapabilities =
- irpStack->Parameters.DeviceCapabilities.Capabilities;
- //
- // forward the irp before handling the special cases
- //
- status = ClassForwardIrpSynchronous(commonExtension, Irp);
- if (!NT_SUCCESS(status)) {
- break;
- }
- //
- // we generally want to remove the device from the hotplug
- // applet, which requires the SR-OK bit to be set.
- // only when the user specifies that they are capable of
- // safely removing things do we want to clear this bit
- // (saved in WriteCacheEnableOverride)
- //
- // setting of this bit is done either above, or by the
- // lower driver.
- //
- // note: may not be started, so check we have FDO data first.
- //
- if (fdoData &&
- fdoData->HotplugInfo.WriteCacheEnableOverride) {
- if (deviceCapabilities->SurpriseRemovalOK) {
- DebugPrint((1, "Classpnp: Clearing SR-OK bit in "
- "device capabilities due to hotplug "
- "device or media\n"));
- }
- deviceCapabilities->SurpriseRemovalOK = FALSE;
- }
- break;
- } // end QUERY_CAPABILITIES for FDOs
- ASSERT(FALSE);
- break;
- } // end QUERY_CAPABILITIES
- default: {
- if (isFdo){
- IoCopyCurrentIrpStackLocationToNext(Irp);
- ClassReleaseRemoveLock(DeviceObject, Irp);
- status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
- completeRequest = FALSE;
- }
- break;
- }
- }
- }
- else {
- ASSERT(driverExtension);
- status = STATUS_INTERNAL_ERROR;
- }
- if (completeRequest){
- Irp->IoStatus.Status = status;
- if (!lockReleased){
- ClassReleaseRemoveLock(DeviceObject, Irp);
- }
- ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
- DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState));
- }
- else {
- /*
- * The irp is already completed so don't touch it.
- * This may be a remove so don't touch the device extension.
- */
- DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp));
- }
- return status;
- } // end ClassDispatchPnp()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassPnpStartDevice()
- Routine Description:
- Storage class driver routine for IRP_MN_START_DEVICE requests.
- This routine kicks off any device specific initialization
- Arguments:
- DeviceObject - a pointer to the device object
- Irp - a pointer to the io request packet
- Return Value:
- none
- --*/
- NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject)
- {
- PCLASS_DRIVER_EXTENSION driverExtension;
- PCLASS_INIT_DATA initData;
- PCLASS_DEV_INFO devInfo;
- PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
- PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
- BOOLEAN isFdo = commonExtension->IsFdo;
- BOOLEAN isMountedDevice = TRUE;
- UNICODE_STRING interfaceName;
- BOOLEAN timerStarted;
- NTSTATUS status = STATUS_SUCCESS;
- PAGED_CODE();
- driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
- CLASS_DRIVER_EXTENSION_KEY);
- initData = &(driverExtension->InitData);
- if(isFdo) {
- devInfo = &(initData->FdoData);
- } else {
- devInfo = &(initData->PdoData);
- }
- ASSERT(devInfo->ClassInitDevice != NULL);
- ASSERT(devInfo->ClassStartDevice != NULL);
- if (!commonExtension->IsInitialized){
- //
- // perform FDO/PDO specific initialization
- //
- if (isFdo){
- STORAGE_PROPERTY_ID propertyId;
- //
- // allocate a private extension for class data
- //
- if (fdoExtension->PrivateFdoData == NULL) {
- fdoExtension->PrivateFdoData =
- ExAllocatePoolWithTag(NonPagedPool,
- sizeof(CLASS_PRIVATE_FDO_DATA),
- CLASS_TAG_PRIVATE_DATA
- );
- }
- if (fdoExtension->PrivateFdoData == NULL) {
- DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
- "private fdo data\n"));
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- //
- // initialize the struct's various fields.
- //
- RtlZeroMemory(fdoExtension->PrivateFdoData,
- sizeof(CLASS_PRIVATE_FDO_DATA)
- );
- KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer);
- KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc,
- ClasspRetryRequestDpc,
- DeviceObject);
- KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock);
- fdoExtension->PrivateFdoData->Retry.Granularity =
- KeQueryTimeIncrement();
- commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid
- //
- // NOTE: the old interface allowed the class driver to allocate
- // this. this was unsafe for low-memory conditions. allocate one
- // unconditionally now, and modify our internal functions to use
- // our own exclusively as it is the only safe way to do this.
- //
- status = ClasspAllocateReleaseQueueIrp(fdoExtension);
- if (!NT_SUCCESS(status)) {
- DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the "
- "private release queue irp\n"));
- return status;
- }
- //
- // Call port driver to get adapter capabilities.
- //
- propertyId = StorageAdapterProperty;
- status = ClassGetDescriptor(
- commonExtension->LowerDeviceObject,
- &propertyId,
- &fdoExtension->AdapterDescriptor);
- if(!NT_SUCCESS(status)) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
- "[ADAPTER] failed %lx\n", status));
- return status;
- }
- //
- // Call port driver to get device descriptor.
- //
- propertyId = StorageDeviceProperty;
- status = ClassGetDescriptor(
- commonExtension->LowerDeviceObject,
- &propertyId,
- &fdoExtension->DeviceDescriptor);
- if(!NT_SUCCESS(status)) {
- //
- // This DebugPrint is to help third-party driver writers
- //
- DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor "
- "[DEVICE] failed %lx\n", status));
- return status;
- }
- ClasspScanForSpecialInRegistry(fdoExtension);
- ClassScanForSpecial(fdoExtension,
- ClassBadItems,
- ClasspScanForClassHacks);
- //
- // allow perf to be re-enabled after a given number of failed IOs
- // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
- //
- {
- ULONG t = 0;
- ClassGetDeviceParameter(fdoExtension,
- CLASSP_REG_SUBKEY_NAME,
- CLASSP_REG_PERF_RESTORE_VALUE_NAME,
- &t);
- if (t >= CLASS_PERF_RESTORE_MINIMUM) {
- fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
- }
- }
- //
- // compatibility comes first. writable cd media will not
- // get a SYNCH_CACHE on power down.
- //
- if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) {
- SET_FLAG(fdoExtension->PrivateFdoData->HackFlags,
- FDO_HACK_NO_SYNC_CACHE);
- }
- //
- // initialize the hotplug information only after the ScanForSpecial
- // routines, as it relies upon the hack flags.
- //
- status = ClasspInitializeHotplugInfo(fdoExtension);
- if (!NT_SUCCESS(status)) {
- DebugPrint((1, "ClassPnpStartDevice: Could not initialize "
- "hotplug information %lx\n", status));
- return status;
- }
- /*
- * Allocate/initialize TRANSFER_PACKETs and related resources.
- */
- status = InitializeTransferPackets(DeviceObject);
- }
- //
- // ISSUE - drivers need to disable write caching on the media
- // if hotplug and !useroverride. perhaps we should
- // allow registration of a callback to enable/disable
- // write cache instead.
- //
- if (NT_SUCCESS(status)){
- status = devInfo->ClassInitDevice(DeviceObject);
- }
- }
- if (!NT_SUCCESS(status)){
- //
- // Just bail out - the remove that comes down will clean up the
- // initialized scraps.
- //
- return status;
- } else {
- commonExtension->IsInitialized = TRUE;
- if (commonExtension->IsFdo) {
- fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags;
- }
- }
- //
- // If device requests autorun functionality or a once a second callback
- // then enable the once per second timer.
- //
- // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
- // called in the context of the ClassInitDevice callback. If called
- // after then this check will have already been made and the
- // once a second timer will not have been enabled.
- //
- if ((isFdo) &&
- ((initData-…
Large files files are truncated, but you can click here to view the full file