NTSTATUS Serenum_FDOPowerComplete (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) /*++ --*/ { POWER_STATE powerState; POWER_STATE_TYPE powerType; PIO_STACK_LOCATION stack; PFDO_DEVICE_DATA data; UNREFERENCED_PARAMETER(Context); if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } data = (PFDO_DEVICE_DATA)DeviceObject->DeviceExtension; stack = IoGetCurrentIrpStackLocation(Irp); powerType = stack->Parameters.Power.Type; powerState = stack->Parameters.Power.State; switch (stack->MinorFunction) { case IRP_MN_SET_POWER: switch (powerType) { case DevicePowerState: // // Powering Up // ASSERT(powerState.DeviceState < data->DeviceState); data->DeviceState = powerState.DeviceState; PoSetPowerState(data->Self, powerType, powerState); break; default: break; } break; case IRP_MN_QUERY_POWER: ASSERT(IRP_MN_QUERY_POWER != stack->MinorFunction); break; default: // // Basically, this is ASSERT(0) // ASSERT(0xBADBAD == IRP_MN_QUERY_POWER); break; } PoStartNextPowerIrp(Irp); Serenum_DecIoCount(data); return STATUS_SUCCESS; // Continue completion... }
static NTSTATUS vboxUsbPwrIoPostDevCompletion(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pvContext) { PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pvContext; if (pIrp->PendingReturned) { IoMarkIrpPending(pIrp); } NTSTATUS Status = pIrp->IoStatus.Status; Assert(Status == STATUS_SUCCESS); if (NT_SUCCESS(Status)) { PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); switch (pSl->MinorFunction) { case IRP_MN_SET_POWER: { pDevExt->DdiState.PwrState.PowerState.DeviceState = pSl->Parameters.Power.State.DeviceState; PoSetPowerState(pDevExt->pFDO, DevicePowerState, pSl->Parameters.Power.State); break; } default: { break; } } } PoStartNextPowerIrp(pIrp); vboxUsbDdiStateRelease(pDevExt); return STATUS_SUCCESS; }
NTSTATUS NTAPI FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension) { NTSTATUS ntStatus; POWER_STATE newState; PIO_STACK_LOCATION irpStack; FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Entered\n")); ntStatus = Irp->IoStatus.Status; irpStack = IoGetCurrentIrpStackLocation(Irp); newState = irpStack->Parameters.Power.State; if (NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER) { FreeBT_DbgPrint(3, ("FBTUSB: updating cache..\n")); DeviceExtension->DevPower = newState.DeviceState; PoSetPowerState(DeviceObject, DevicePowerState, newState); } PoStartNextPowerIrp(Irp); FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp::")); FreeBT_IoDecrement(DeviceExtension); FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Leaving\n")); return STATUS_SUCCESS; }
NTSTATUS Bus_StartFdo(__in PFDO_DEVICE_DATA FdoData, __in PIRP Irp) { NTSTATUS status; POWER_STATE powerState; UNREFERENCED_PARAMETER(Irp); PAGED_CODE(); status = IoSetDeviceInterfaceState(&FdoData->InterfaceName, TRUE); if (!NT_SUCCESS (status)) { Bus_KdPrint(("IoSetDeviceInterfaceState failed: 0x%x\n", status)); return status; } FdoData->DevicePowerState = PowerDeviceD0; powerState.DeviceState = PowerDeviceD0; PoSetPowerState(FdoData->Self, DevicePowerState, powerState); SET_NEW_PNP_STATE(FdoData, Started); return status; }
NTSTATUS FinishDevPoDnIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: This routine is the completion routine for device power DOWN irp. Arguments: DeviceObject - pointer to device object Irp - I/O request packet DeviceExtension - pointer to device extension Return Value: NT status value --*/ { NTSTATUS ntStatus; POWER_STATE newState; PIO_STACK_LOCATION irpStack; // // initialize variables // ntStatus = Irp->IoStatus.Status; irpStack = IoGetCurrentIrpStackLocation(Irp); newState = irpStack->Parameters.Power.State; MobiUsb_DbgPrint(3, ("file mobipwr: FinishDevPoDnIrp - begins\n")); if(NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER) { // // update the cache; // MobiUsb_DbgPrint(3, ("file mobipwr: updating cache..\n")); DeviceExtension->DevPower = newState.DeviceState; PoSetPowerState(DeviceObject, DevicePowerState, newState); } PoStartNextPowerIrp(Irp); MobiUsb_DbgPrint(3, ("file mobipwr: FinishDevPoDnIrp::")); MobiUsb_IoDecrement(DeviceExtension); MobiUsb_DbgPrint(3, ("file mobipwr: FinishDevPoDnIrp - ends\n")); return STATUS_SUCCESS; }
DECLHIDDEN(VOID) vboxUsbPwrStateInit(PVBOXUSBDEV_EXT pDevExt) { POWER_STATE PowerState; PowerState.SystemState = PowerSystemWorking; PowerState.DeviceState = PowerDeviceD0; PoSetPowerState(pDevExt->pFDO, DevicePowerState, PowerState); pDevExt->DdiState.PwrState.PowerState = PowerState; pDevExt->DdiState.PwrState.PowerDownLevel = PowerDeviceUnspecified; }
static NTSTATUS DDKAPI on_power_state_complete(DEVICE_OBJECT *device_object, IRP *irp, void *context) { libusb_device_t *dev = context; IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp); POWER_STATE power_state = stack_location->Parameters.Power.State; DEVICE_POWER_STATE dev_power_state; if (irp->PendingReturned) { IoMarkIrpPending(irp); } if (NT_SUCCESS(irp->IoStatus.Status)) { if (stack_location->Parameters.Power.Type == SystemPowerState) { USBMSG("S%d %s\n", power_state.SystemState - PowerSystemWorking, dev->device_id); /* save current system state */ dev->power_state.SystemState = power_state.SystemState; /* get supported device power state from the array reported by */ /* IRP_MN_QUERY_CAPABILITIES */ dev_power_state = dev->device_power_states[power_state.SystemState]; /* set the device power state, but don't block the thread */ power_set_device_state(dev, dev_power_state, FALSE); } else /* DevicePowerState */ { USBMSG("D%d %s\n", power_state.DeviceState - PowerDeviceD0, dev->device_id); if (power_state.DeviceState <= dev->power_state.DeviceState) { /* device is powered up, */ /* report device state to Power Manager */ PoSetPowerState(dev->self, DevicePowerState, power_state); } /* save current device state */ dev->power_state.DeviceState = power_state.DeviceState; } } else { USBMSG0("failed\n"); } remove_lock_release(dev); return STATUS_SUCCESS; }
NTSTATUS XenM2BPdoPower(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { PXENM2B_PDO_EXTENSION pPdoExt = (PXENM2B_PDO_EXTENSION)pDeviceObject->DeviceExtension; PIO_STACK_LOCATION pIrpStack; POWER_STATE PowerState; POWER_STATE_TYPE PowerType; NTSTATUS Status = STATUS_SUCCESS; pIrpStack = IoGetCurrentIrpStackLocation(pIrp); PowerType = pIrpStack->Parameters.Power.Type; PowerState = pIrpStack->Parameters.Power.State; switch (pIrpStack->MinorFunction) { case IRP_MN_SET_POWER: TraceDebug(("%s: IRP_MN_SET_POWER\n", __FUNCTION__)); if (PowerType == DevicePowerState) { TraceDebug(("%s: IRP_MN_SET_POWER DevicePowerState:%x\n", __FUNCTION__, PowerState.DeviceState)); PoSetPowerState(pPdoExt->pDevice, DevicePowerState, PowerState); pPdoExt->DevicePowerState = PowerState.DeviceState; } else if (PowerType == SystemPowerState) { TraceDebug(("%s: IRP_MN_SET_POWER SystemPowerState:%x\n", __FUNCTION__, PowerState.SystemState)); pPdoExt->SystemPowerState = PowerState.SystemState; } PoStartNextPowerIrp(pIrp); pIrp->IoStatus.Status = Status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); break; case IRP_MN_QUERY_POWER: TraceDebug(("%s: IRP_MN_QUERY_POWER\n", __FUNCTION__)); PoStartNextPowerIrp(pIrp); pIrp->IoStatus.Status = Status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); break; case IRP_MN_WAIT_WAKE: case IRP_MN_POWER_SEQUENCE: default: PoStartNextPowerIrp(pIrp); Status = pIrp->IoStatus.Status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); break; } return Status; }
static DECLSPEC_NOINLINE NTSTATUS PdoRemoveDevice( IN PXENFILT_PDO Pdo, IN PIRP Irp ) { PXENFILT_FDO Fdo = __PdoGetFdo(Pdo); POWER_STATE PowerState; NTSTATUS status; status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp); if (!NT_SUCCESS(status)) goto fail1; if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0) goto done; __PdoSetDevicePowerState(Pdo, PowerDeviceD3); __PdoSetSystemPowerState(Pdo, PowerSystemShutdown); PowerState.DeviceState = PowerDeviceD3; PoSetPowerState(Pdo->Dx->DeviceObject, DevicePowerState, PowerState); done: if (__PdoIsMissing(Pdo)) { __PdoSetDevicePnpState(Pdo, Deleted); IoReleaseRemoveLockAndWait(&Pdo->Dx->RemoveLock, Irp); } else { __PdoSetDevicePnpState(Pdo, Enumerated); IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp); } status = PdoForwardIrpSynchronously(Pdo, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); if (__PdoIsMissing(Pdo)) { FdoAcquireMutex(Fdo); PdoDestroy(Pdo); FdoReleaseMutex(Fdo); } return status; fail1: Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }
NTSTATUS Bus_StartFdo ( PFDO_DEVICE_DATA FdoData, PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; POWER_STATE powerState; ACPI_STATUS AcpiStatus; PAGED_CODE (); FdoData->Common.DevicePowerState = PowerDeviceD0; powerState.DeviceState = PowerDeviceD0; PoSetPowerState ( FdoData->Common.Self, DevicePowerState, powerState ); SET_NEW_PNP_STATE(FdoData->Common, Started); AcpiStatus = AcpiInitializeSubsystem(); if(ACPI_FAILURE(AcpiStatus)){ DPRINT1("Unable to AcpiInitializeSubsystem\n"); return STATUS_UNSUCCESSFUL; } AcpiStatus = AcpiInitializeTables(NULL, 16, 0); if (ACPI_FAILURE(status)){ DPRINT1("Unable to AcpiInitializeSubsystem\n"); return STATUS_UNSUCCESSFUL; } AcpiStatus = AcpiLoadTables(); if(ACPI_FAILURE(AcpiStatus)){ DPRINT1("Unable to AcpiLoadTables\n"); AcpiTerminate(); return STATUS_UNSUCCESSFUL; } DPRINT("Acpi subsystem init\n"); /* Initialize ACPI bus manager */ AcpiStatus = acpi_init(); if (!ACPI_SUCCESS(AcpiStatus)) { DPRINT1("acpi_init() failed with status 0x%X\n", AcpiStatus); AcpiTerminate(); return STATUS_UNSUCCESSFUL; } status = ACPIEnumerateDevices(FdoData); return status; }
static NTSTATUS DDKAPI on_filter_power_state_complete(DEVICE_OBJECT *device_object, IRP *irp, void *context) { libusb_device_t *dev = context; IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp); POWER_STATE power_state = stack_location->Parameters.Power.State; if (NT_SUCCESS(irp->IoStatus.Status)) { if (stack_location->Parameters.Power.Type == SystemPowerState) { USBMSG("S%d\n", power_state.SystemState - PowerSystemWorking); /* save current system state */ dev->power_state.SystemState = power_state.SystemState; } else /* DevicePowerState */ { USBMSG("D%d\n", power_state.DeviceState - PowerDeviceD0); if (power_state.DeviceState <= dev->power_state.DeviceState) { /* device is powered up, */ /* report device state to Power Manager */ PoSetPowerState(dev->self, DevicePowerState, power_state); } /* save current device state */ dev->power_state.DeviceState = power_state.DeviceState; } } else { USBMSG0("failed\n"); } remove_lock_release(dev); return STATUS_SUCCESS; }
static DECLSPEC_NOINLINE NTSTATUS PdoStopDevice( IN PXENFILT_PDO Pdo, IN PIRP Irp ) { POWER_STATE PowerState; NTSTATUS status; status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp); if (!NT_SUCCESS(status)) goto fail1; if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0) goto done; __PdoSetDevicePowerState(Pdo, PowerDeviceD3); __PdoSetSystemPowerState(Pdo, PowerSystemShutdown); PowerState.DeviceState = PowerDeviceD3; PoSetPowerState(Pdo->Dx->DeviceObject, DevicePowerState, PowerState); done: __PdoSetDevicePnpState(Pdo, Stopped); Irp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, __PdoStopDevice, Pdo, TRUE, TRUE, TRUE); status = IoCallDriver(Pdo->LowerDeviceObject, Irp); return status; fail1: Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }
NTSTATUS NTAPI SetDeviceFunctional(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension) { KIRQL oldIrql; NTSTATUS ntStatus; POWER_STATE newState; PIO_STACK_LOCATION irpStack; DEVICE_POWER_STATE newDevState, oldDevState; ntStatus = Irp->IoStatus.Status; irpStack = IoGetCurrentIrpStackLocation(Irp); newState = irpStack->Parameters.Power.State; newDevState = newState.DeviceState; oldDevState = DeviceExtension->DevPower; FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Entered\n")); // update the cached state DeviceExtension->DevPower = newDevState; // restore appropriate amount of state to our h/w // this driver does not implement partial context // save/restore. PoSetPowerState(DeviceObject, DevicePowerState, newState); if(PowerDeviceD0 == newDevState) { KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql); DeviceExtension->QueueState = AllowRequests; KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql); ProcessQueuedRequests(DeviceExtension); } PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional::")); FreeBT_IoDecrement(DeviceExtension); FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Leaving\n")); return STATUS_SUCCESS; }
static DECLSPEC_NOINLINE NTSTATUS PdoStartDevice( IN PXENFILT_PDO Pdo, IN PIRP Irp ) { POWER_STATE PowerState; NTSTATUS status; status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp); if (!NT_SUCCESS(status)) goto fail1; status = PdoForwardIrpSynchronously(Pdo, Irp); if (!NT_SUCCESS(status)) goto fail2; __PdoSetSystemPowerState(Pdo, PowerSystemWorking); __PdoSetDevicePowerState(Pdo, PowerDeviceD0); PowerState.DeviceState = PowerDeviceD0; PoSetPowerState(Pdo->Dx->DeviceObject, DevicePowerState, PowerState); __PdoSetDevicePnpState(Pdo, Started); IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; fail2: IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp); fail1: Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; }
NTSTATUS PdoPortPower( IN PC0C_PDOPORT_EXTENSION pDevExt, IN PIRP pIrp) { NTSTATUS status; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp); switch (pIrpStack->MinorFunction) { case IRP_MN_SET_POWER: switch (pIrpStack->Parameters.Power.Type) { case DevicePowerState: PoSetPowerState(pDevExt->pDevObj, DevicePowerState, pIrpStack->Parameters.Power.State); status = STATUS_SUCCESS; break; case SystemPowerState: status = STATUS_SUCCESS; break; default: status = STATUS_NOT_SUPPORTED; break; } break; case IRP_MN_QUERY_POWER: status = STATUS_SUCCESS; break; case IRP_MN_WAIT_WAKE: case IRP_MN_POWER_SEQUENCE: default: status = STATUS_NOT_SUPPORTED; break; } if (status != STATUS_NOT_SUPPORTED) pIrp->IoStatus.Status = status; PoStartNextPowerIrp(pIrp); status = pIrp->IoStatus.Status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; }
GENERICAPI NTSTATUS GENERIC_EXPORT InitializeGenericExtension(PGENERIC_EXTENSION pdx, PGENERIC_INIT_STRUCT isp) { // InitializeGenericExtension if (isp->Size < FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) || !isp->DeviceObject || !isp->Ldo || !isp->Pdo || !isp->StartDevice || !isp->StopDevice || !isp->RemoveDevice || isp->DeviceQueue && !isp->StartIo) return STATUS_INVALID_PARAMETER; RtlZeroMemory(pdx, sizeof(GENERIC_EXTENSION)); pdx->DeviceObject = isp->DeviceObject; pdx->LowerDeviceObject = isp->Ldo; pdx->Pdo = isp->Pdo; pdx->StartDevice = isp->StartDevice; pdx->StopDevice = isp->StopDevice; pdx->RemoveDevice = isp->RemoveDevice; if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, OkayToRemove) + sizeof(PQUERYFUNCTION)) { // set OkayToStop & OkayToRemove pointers pdx->OkayToStop = isp->OkayToStop; pdx->OkayToRemove = isp->OkayToRemove; } // set OkayToStop & OkayToRemove pointers if ((pdx->dqReadWrite = isp->DeviceQueue)) { // queue reads & writes if (!isp->StartIo) return STATUS_INVALID_PARAMETER; InitializeQueue(pdx->dqReadWrite, isp->StartIo); } // queue reads & writes if ((pdx->RemoveLock = isp->RemoveLock)) IoInitializeRemoveLock(pdx->RemoveLock, 0, 0, 0); pdx->state = STOPPED; pdx->devpower = PowerDeviceD0; pdx->syspower = PowerSystemWorking; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pdx->DeviceObject, DevicePowerState, state); // Capture the mini-driver name for messages. This needs to be in ANSI because // unicode conversions at or above DISPATCH_LEVEL are not allowed if (!isp->DebugName.Length) strcpy(pdx->DebugName, "GENERIC"); else { // convert debug name ANSI_STRING asname = {0, sizeof(pdx->DebugName) - 1, pdx->DebugName}; RtlUnicodeStringToAnsiString(&asname, &isp->DebugName, FALSE); pdx->DebugName[asname.Length] = 0; } // convert debug name if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) + sizeof(ULONG)) pdx->Flags = isp->Flags & GENERIC_CLIENT_FLAGS; if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, RestoreDeviceContext) + sizeof(PCONTEXTFUNCTION)) { // get power helper functions pdx->QueryPower = isp->QueryPower; pdx->SaveDeviceContext = isp->SaveDeviceContext; pdx->RestoreDeviceContext = isp->RestoreDeviceContext; } // get power helper functions if (isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, PerfBoundary) + sizeof(DEVICE_POWER_STATE)) pdx->PerfBoundary = isp->PerfBoundary; else pdx->PerfBoundary = PowerDeviceUnspecified; if (pdx->PerfBoundary == PowerDeviceUnspecified) pdx->PerfBoundary = PowerDeviceMaximum; // inhibit POWER_SEQUENCE optimization // Initialize variables related to asynchrounous IOCTL management. if (pdx->Flags & GENERIC_PENDING_IOCTLS) { // driver may cache asyncronous IOCTLs InitializeListHead(&pdx->PendingIoctlList); pdx->IoctlAbortStatus = 0; // We need to initialize our IOCTL spin lock sometime, but just once. // Acquiring the cancel spin lock to guard this operation is a bit of // a hack, I suppose, but note that a class driver like this one never // gets an actual chance to initialize, so it's not my fault... KIRQL oldirql; IoAcquireCancelSpinLock(&oldirql); // any global spin lock would do if (!IoctlListLockInitialized) { // initialize global lock IoctlListLockInitialized = TRUE; KeInitializeSpinLock(&IoctlListLock); } // initialize global lock IoReleaseCancelSpinLock(oldirql); } // driver may cache asynchronous IOCTLs // Initialize to manage registered device interfaces ExInitializeFastMutex(&pdx->iflock); InitializeListHead(&pdx->iflist); // Indicate we handle power IRPs at PASSIVE_LEVEL pdx->DeviceObject->Flags |= DO_POWER_PAGABLE; KdPrint(("GENERIC - Initializing for %s\n", pdx->DebugName)); // If requested to do so, register an AutoLaunch interface if (pdx->Flags & GENERIC_AUTOLAUNCH) GenericRegisterInterface(pdx, &GUID_AUTOLAUNCH_NOTIFY); // Register a power management interface GenericRegisterInterface(pdx, &GUID_GENERIC_POWER); #ifdef _X86_ win98 = IsWin98(); #endif return STATUS_SUCCESS; } // InitializeGenericExtension
/*++//////////////////////////////////////////////////////////////////////////// ClasspPowerDownCompletion() Routine Description: This routine is used for intermediate completion of a power up request. PowerUp requires four requests to be sent to the lower driver in sequence. * The queue is "power locked" to ensure that the class driver power-up work can be done before request processing resumes. * The power irp is sent down the stack for any filter drivers and the port driver to return power and resume command processing for the device. Since the queue is locked, no queued irps will be sent immediately. * A start unit command is issued to the device with appropriate flags to override the "power locked" queue. * The queue is "power unlocked" to start processing requests again. This routine uses the function in the srb which just completed to determine which state it is in. Arguments: DeviceObject - the device object being powered up Irp - the IO_REQUEST_PACKET containing the power request Srb - the SRB used to perform port/class operations. Return Value: STATUS_MORE_PROCESSING_REQUIRED or STATUS_SUCCESS --*/ NTSTATUS NTAPI ClasspPowerDownCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID CompletionContext ) { PCLASS_POWER_CONTEXT context = CompletionContext; PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; DebugPrint((1, "ClasspPowerDownCompletion: Device Object %p, " "Irp %p, Context %p\n", DeviceObject, Irp, context)); ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); ASSERT(context->Options.PowerDown == TRUE); ASSERT(context->Options.HandleSpinDown); if(Irp->PendingReturned) { IoMarkIrpPending(Irp); } context->PowerChangeState.PowerDown2++; switch(context->PowerChangeState.PowerDown2) { case PowerDownDeviceLocked2: { PCDB cdb; DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp)); if((context->Options.LockQueue == TRUE) && (!NT_SUCCESS(Irp->IoStatus.Status))) { DebugPrint((1, "(%p)\tIrp status was %lx\n", Irp, Irp->IoStatus.Status)); DebugPrint((1, "(%p)\tSrb status was %lx\n", Irp, context->Srb.SrbStatus)); Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; // // Lock was not successful - throw down the power IRP // by itself and don't try to spin down the drive or unlock // the queue. // context->InUse = FALSE; context = NULL; // // Set the new power state // fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState; // // Indicate to Po that we've been successfully powered down // so it can do it's notification stuff. // IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, ClasspStartNextPowerIrpCompletion, NULL, TRUE, TRUE, TRUE); PoSetPowerState(DeviceObject, currentStack->Parameters.Power.Type, currentStack->Parameters.Power.State); fdoExtension->PowerDownInProgress = FALSE; PoCallDriver(commonExtension->LowerDeviceObject, Irp); ClassReleaseRemoveLock(commonExtension->DeviceObject, Irp); return STATUS_MORE_PROCESSING_REQUIRED; } else { context->QueueLocked = (UCHAR) context->Options.LockQueue; } if (!TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_SYNC_CACHE)) { // // send SCSIOP_SYNCHRONIZE_CACHE // context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; context->Srb.TimeOutValue = fdoExtension->TimeOutValue; context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE | SRB_FLAGS_BYPASS_LOCKED_QUEUE; context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; context->Srb.DataTransferLength = 0; context->Srb.CdbLength = 10; cdb = (PCDB) context->Srb.Cdb; RtlZeroMemory(cdb, sizeof(CDB)); cdb->SYNCHRONIZE_CACHE10.OperationCode = SCSIOP_SYNCHRONIZE_CACHE; IoSetCompletionRoutine(Irp, ClasspPowerDownCompletion, context, TRUE, TRUE, TRUE); nextStack->Parameters.Scsi.Srb = &(context->Srb); nextStack->MajorFunction = IRP_MJ_SCSI; status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); break; } else { DebugPrint((1, "(%p)\tPower Down: not sending SYNCH_CACHE\n", DeviceObject)); context->PowerChangeState.PowerDown2++; context->Srb.SrbStatus = SRB_STATUS_SUCCESS; // and fall through.... } // no break in case the device doesn't like synch_cache commands } case PowerDownDeviceFlushed2: { PCDB cdb; DebugPrint((1, "(%p)\tPreviously send SCSIOP_SYNCHRONIZE_CACHE\n", Irp)); // // SCSIOP_SYNCHRONIZE_CACHE was sent // if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) { BOOLEAN retry; DebugPrint((1, "(%p)\tError occured when issuing " "SYNCHRONIZE_CACHE command to device. " "Srb %p, Status %lx\n", Irp, &context->Srb, context->Srb.SrbStatus)); ASSERT(!(TEST_FLAG(context->Srb.SrbStatus, SRB_STATUS_QUEUE_FROZEN))); ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI); context->RetryInterval = 0; retry = ClassInterpretSenseInfo( commonExtension->DeviceObject, &context->Srb, IRP_MJ_SCSI, IRP_MJ_POWER, MAXIMUM_RETRIES - context->RetryCount, &status, &context->RetryInterval); if((retry == TRUE) && (context->RetryCount-- != 0)) { DebugPrint((1, "(%p)\tRetrying failed request\n", Irp)); // // decrement the state so we come back through here // the next time. // context->PowerChangeState.PowerDown2--; RetryPowerRequest(commonExtension->DeviceObject, Irp, context); break; } DebugPrint((1, "(%p)\tSYNCHRONIZE_CACHE not retried\n", Irp)); context->RetryCount = MAXIMUM_RETRIES; } // end !SRB_STATUS_SUCCESS // // note: we are purposefully ignoring any errors. if the drive // doesn't support a synch_cache, then we're up a creek // anyways. // DebugPrint((1, "(%p)\tSending stop unit to device\n", Irp)); // // Issue the start unit command to the device. // context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; context->Srb.TimeOutValue = START_UNIT_TIMEOUT; context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE | SRB_FLAGS_BYPASS_LOCKED_QUEUE; context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; context->Srb.DataTransferLength = 0; context->Srb.CdbLength = 6; cdb = (PCDB) context->Srb.Cdb; RtlZeroMemory(cdb, sizeof(CDB)); cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; cdb->START_STOP.Start = 0; cdb->START_STOP.Immediate = 1; IoSetCompletionRoutine(Irp, ClasspPowerDownCompletion, context, TRUE, TRUE, TRUE); nextStack->Parameters.Scsi.Srb = &(context->Srb); nextStack->MajorFunction = IRP_MJ_SCSI; status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); break; } case PowerDownDeviceStopped2: { BOOLEAN ignoreError = TRUE; // // stop was sent // if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) { BOOLEAN retry; DebugPrint((1, "(%p)\tError occured when issueing STOP_UNIT " "command to device. Srb %p, Status %lx\n", Irp, &context->Srb, context->Srb.SrbStatus)); ASSERT(!(TEST_FLAG(context->Srb.SrbStatus, SRB_STATUS_QUEUE_FROZEN))); ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI); context->RetryInterval = 0; retry = ClassInterpretSenseInfo( commonExtension->DeviceObject, &context->Srb, IRP_MJ_SCSI, IRP_MJ_POWER, MAXIMUM_RETRIES - context->RetryCount, &status, &context->RetryInterval); if((retry == TRUE) && (context->RetryCount-- != 0)) { DebugPrint((1, "(%p)\tRetrying failed request\n", Irp)); // // decrement the state so we come back through here // the next time. // context->PowerChangeState.PowerDown2--; RetryPowerRequest(commonExtension->DeviceObject, Irp, context); break; } DebugPrint((1, "(%p)\tSTOP_UNIT not retried\n", Irp)); context->RetryCount = MAXIMUM_RETRIES; } // end !SRB_STATUS_SUCCESS DebugPrint((1, "(%p)\tPreviously sent stop unit\n", Irp)); // // some operations, such as a physical format in progress, // should not be ignored and should fail the power operation. // if (!NT_SUCCESS(status)) { PSENSE_DATA senseBuffer = context->Srb.SenseInfoBuffer; if (TEST_FLAG(context->Srb.SrbStatus, SRB_STATUS_AUTOSENSE_VALID) && ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) && (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_FORMAT_IN_PROGRESS) ) { ignoreError = FALSE; context->FinalStatus = STATUS_DEVICE_BUSY; status = context->FinalStatus; } } if (NT_SUCCESS(status) || ignoreError) { // // Issue the actual power request to the lower driver. // Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, ClasspPowerDownCompletion, context, TRUE, TRUE, TRUE); status = PoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((1, "(%p)\tPoCallDriver returned %lx\n", Irp, status)); break; } // else fall through w/o sending the power irp, since the device // is reporting an error that would be "really bad" to power down // during. } case PowerDownDeviceOff2: { // // SpinDown request completed ... whether it succeeded or not is // another matter entirely. // DebugPrint((1, "(%p)\tPreviously sent power irp\n", Irp)); if (context->QueueLocked) { DebugPrint((1, "(%p)\tUnlocking queue\n", Irp)); context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; context->Srb.DataTransferLength = 0; context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE; context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE; nextStack->Parameters.Scsi.Srb = &(context->Srb); nextStack->MajorFunction = IRP_MJ_SCSI; IoSetCompletionRoutine(Irp, ClasspPowerDownCompletion, context, TRUE, TRUE, TRUE); status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); break; } } case PowerDownDeviceUnlocked2: { // // This is the end of the dance. Free the srb and complete the // request finally. We're ignoring possible intermediate // error conditions .... // if (context->QueueLocked == FALSE) { DebugPrint((1, "(%p)\tFall through (queue not locked)\n", Irp)); } else { DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp)); ASSERT(NT_SUCCESS(Irp->IoStatus.Status)); ASSERT(context->Srb.SrbStatus == SRB_STATUS_SUCCESS); } DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp)); context->InUse = FALSE; status = context->FinalStatus; // allow failure to propogate context = NULL; if(Irp->PendingReturned) { IoMarkIrpPending(Irp); } Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; if (NT_SUCCESS(status)) { // // Set the new power state // fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState; } DebugPrint((1, "(%p)\tStarting next power irp\n", Irp)); ClassReleaseRemoveLock(DeviceObject, Irp); PoStartNextPowerIrp(Irp); fdoExtension->PowerDownInProgress = FALSE; return status; } case PowerDownDeviceInitial2: { NT_ASSERT(context->PowerChangeState.PowerDown2 != PowerDownDeviceInitial2); break; } } return STATUS_MORE_PROCESSING_REQUIRED; } // end ClasspPowerDownCompletion()
/*++//////////////////////////////////////////////////////////////////////////// ClasspPowerUpCompletion() Routine Description: This routine is used for intermediate completion of a power up request. PowerUp requires four requests to be sent to the lower driver in sequence. * The queue is "power locked" to ensure that the class driver power-up work can be done before request processing resumes. * The power irp is sent down the stack for any filter drivers and the port driver to return power and resume command processing for the device. Since the queue is locked, no queued irps will be sent immediately. * A start unit command is issued to the device with appropriate flags to override the "power locked" queue. * The queue is "power unlocked" to start processing requests again. This routine uses the function in the srb which just completed to determine which state it is in. Arguments: DeviceObject - the device object being powered up Irp - the IO_REQUEST_PACKET containing the power request Srb - the SRB used to perform port/class operations. Return Value: STATUS_MORE_PROCESSING_REQUIRED or STATUS_SUCCESS --*/ NTSTATUS NTAPI ClasspPowerUpCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID CompletionContext ) { PCLASS_POWER_CONTEXT context = CompletionContext; PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED; DebugPrint((1, "ClasspPowerUpCompletion: Device Object %p, Irp %p, " "Context %p\n", DeviceObject, Irp, context)); ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); ASSERT(context->Options.PowerDown == FALSE); ASSERT(context->Options.HandleSpinUp); if(Irp->PendingReturned) { IoMarkIrpPending(Irp); } context->PowerChangeState.PowerUp++; switch(context->PowerChangeState.PowerUp) { case PowerUpDeviceLocked: { DebugPrint((1, "(%p)\tPreviously sent power lock\n", Irp)); // // Issue the actual power request to the lower driver. // IoCopyCurrentIrpStackLocationToNext(Irp); // // If the lock wasn't successful then just bail out on the power // request unless we can ignore failed locks // if((context->Options.LockQueue == TRUE) && (!NT_SUCCESS(Irp->IoStatus.Status))) { DebugPrint((1, "(%p)\tIrp status was %lx\n", Irp, Irp->IoStatus.Status)); DebugPrint((1, "(%p)\tSrb status was %lx\n", Irp, context->Srb.SrbStatus)); // // Lock was not successful - throw down the power IRP // by itself and don't try to spin up the drive or unlock // the queue. // context->InUse = FALSE; context = NULL; // // Set the new power state // fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState; Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, ClasspStartNextPowerIrpCompletion, NULL, TRUE, TRUE, TRUE); // // Indicate to Po that we've been successfully powered up so // it can do it's notification stuff. // PoSetPowerState(DeviceObject, currentStack->Parameters.Power.Type, currentStack->Parameters.Power.State); PoCallDriver(commonExtension->LowerDeviceObject, Irp); ClassReleaseRemoveLock(commonExtension->DeviceObject, Irp); return STATUS_MORE_PROCESSING_REQUIRED; } else { context->QueueLocked = (UCHAR) context->Options.LockQueue; } Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; context->PowerChangeState.PowerUp = PowerUpDeviceLocked; IoSetCompletionRoutine(Irp, ClasspPowerUpCompletion, context, TRUE, TRUE, TRUE); status = PoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((2, "(%p)\tPoCallDriver returned %lx\n", Irp, status)); break; } case PowerUpDeviceOn: { PCDB cdb; if(NT_SUCCESS(Irp->IoStatus.Status)) { DebugPrint((1, "(%p)\tSending start unit to device\n", Irp)); // // Issue the start unit command to the device. // context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); context->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; context->Srb.DataTransferLength = 0; context->Srb.TimeOutValue = START_UNIT_TIMEOUT; context->Srb.SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE; if(context->Options.LockQueue) { SET_FLAG(context->Srb.SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE); } context->Srb.CdbLength = 6; cdb = (PCDB) (context->Srb.Cdb); RtlZeroMemory(cdb, sizeof(CDB)); cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; cdb->START_STOP.Start = 1; context->PowerChangeState.PowerUp = PowerUpDeviceOn; IoSetCompletionRoutine(Irp, ClasspPowerUpCompletion, context, TRUE, TRUE, TRUE); nextStack->Parameters.Scsi.Srb = &(context->Srb); nextStack->MajorFunction = IRP_MJ_SCSI; status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((2, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); } else { // // we're done. // context->FinalStatus = Irp->IoStatus.Status; goto ClasspPowerUpCompletionFailure; } break; } case PowerUpDeviceStarted: { // 3 // // First deal with an error if one occurred. // if(SRB_STATUS(context->Srb.SrbStatus) != SRB_STATUS_SUCCESS) { BOOLEAN retry; DebugPrint((1, "%p\tError occured when issuing START_UNIT " "command to device. Srb %p, Status %x\n", Irp, &context->Srb, context->Srb.SrbStatus)); ASSERT(!(TEST_FLAG(context->Srb.SrbStatus, SRB_STATUS_QUEUE_FROZEN))); ASSERT(context->Srb.Function == SRB_FUNCTION_EXECUTE_SCSI); context->RetryInterval = 0; retry = ClassInterpretSenseInfo( commonExtension->DeviceObject, &context->Srb, IRP_MJ_SCSI, IRP_MJ_POWER, MAXIMUM_RETRIES - context->RetryCount, &status, &context->RetryInterval); if((retry == TRUE) && (context->RetryCount-- != 0)) { DebugPrint((1, "(%p)\tRetrying failed request\n", Irp)); // // Decrement the state so we come back through here the // next time. // context->PowerChangeState.PowerUp--; RetryPowerRequest(commonExtension->DeviceObject, Irp, context); break; } // reset retries context->RetryCount = MAXIMUM_RETRIES; } ClasspPowerUpCompletionFailure: DebugPrint((1, "(%p)\tPreviously spun device up\n", Irp)); if (context->QueueLocked) { DebugPrint((1, "(%p)\tUnlocking queue\n", Irp)); context->Srb.Function = SRB_FUNCTION_UNLOCK_QUEUE; context->Srb.SrbFlags = SRB_FLAGS_BYPASS_LOCKED_QUEUE; context->Srb.SrbStatus = context->Srb.ScsiStatus = 0; context->Srb.DataTransferLength = 0; nextStack->Parameters.Scsi.Srb = &(context->Srb); nextStack->MajorFunction = IRP_MJ_SCSI; context->PowerChangeState.PowerUp = PowerUpDeviceStarted; IoSetCompletionRoutine(Irp, ClasspPowerUpCompletion, context, TRUE, TRUE, TRUE); status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); DebugPrint((1, "(%p)\tIoCallDriver returned %lx\n", Irp, status)); break; } // Fall-through to next case... } case PowerUpDeviceUnlocked: { // // This is the end of the dance. Free the srb and complete the // request finally. We're ignoring possible intermediate // error conditions .... // if (context->QueueLocked) { DebugPrint((1, "(%p)\tPreviously unlocked queue\n", Irp)); ASSERT(NT_SUCCESS(Irp->IoStatus.Status)); ASSERT(context->Srb.SrbStatus == SRB_STATUS_SUCCESS); } else { DebugPrint((1, "(%p)\tFall-through (queue not locked)\n", Irp)); } DebugPrint((1, "(%p)\tFreeing srb and completing\n", Irp)); context->InUse = FALSE; status = context->FinalStatus; Irp->IoStatus.Status = status; context = NULL; // // Set the new power state // if(NT_SUCCESS(status)) { fdoExtension->DevicePowerState = currentStack->Parameters.Power.State.DeviceState; } // // Indicate to Po that we've been successfully powered up so // it can do it's notification stuff. // PoSetPowerState(DeviceObject, currentStack->Parameters.Power.Type, currentStack->Parameters.Power.State); DebugPrint((1, "(%p)\tStarting next power irp\n", Irp)); ClassReleaseRemoveLock(DeviceObject, Irp); PoStartNextPowerIrp(Irp); return status; } case PowerUpDeviceInitial: { NT_ASSERT(context->PowerChangeState.PowerUp != PowerUpDeviceInitial); break; } } return STATUS_MORE_PROCESSING_REQUIRED; } // end ClasspPowerUpCompletion()
NTSTATUS Bus_StartFdo ( __in PFDO_DEVICE_DATA FdoData, __in PIRP Irp ) /*++ Routine Description: Initialize and start the bus controller. Get the resources by parsing the list and map them if required. Arguments: DeviceData - Pointer to the FDO's device extension. Irp - Pointer to the irp. Return Value: NT Status is returned. --*/ { NTSTATUS status; POWER_STATE powerState; PAGED_CODE (); // // Check the function driver source to learn // about parsing resource list. // // // Enable device interface. If the return status is // STATUS_OBJECT_NAME_EXISTS means we are enabling the interface // that was already enabled, which could happen if the device // is stopped and restarted for resource rebalancing. // status = IoSetDeviceInterfaceState(&FdoData->InterfaceName, TRUE); if (!NT_SUCCESS (status)) { Bus_KdPrint (FdoData, BUS_DBG_PNP_TRACE, ("IoSetDeviceInterfaceState failed: 0x%x\n", status)); return status; } // // Set the device power state to fully on. Also if this Start // is due to resource rebalance, you should restore the device // to the state it was before you stopped the device and relinquished // resources. // FdoData->DevicePowerState = PowerDeviceD0; powerState.DeviceState = PowerDeviceD0; PoSetPowerState ( FdoData->Self, DevicePowerState, powerState ); SET_NEW_PNP_STATE(FdoData, Started); // // Register with WMI // status = Bus_WmiRegistration(FdoData); if (!NT_SUCCESS (status)) { Bus_KdPrint (FdoData, BUS_DBG_SS_ERROR, ("StartFdo: Bus_WmiRegistration failed (%x)\n", status)); } return status; }
// for pdo NTSTATUS DoPdoPnP(PDEVICE_OBJECT pDevice,PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; PPdoExt pPdoExt = static_cast<PPdoExt>(pDevice->DeviceExtension); PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(pIrp); switch(pIoStack->MinorFunction) { case IRP_MN_START_DEVICE: // set power state pPdoExt->m_devPowerState = PowerDeviceD0; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pDevice,DevicePowerState,state); // set pnp state directly case IRP_MN_STOP_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: SetNewPnpState(pPdoExt,pIoStack->MinorFunction); break; // check prev state case IRP_MN_CANCEL_REMOVE_DEVICE: if(pPdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) { RestorePnpState(pPdoExt); } break; // the same case IRP_MN_CANCEL_STOP_DEVICE: if(pPdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) { RestorePnpState(pPdoExt); } break; // remove case IRP_MN_REMOVE_DEVICE: { // delete only if we have reported the device physical removal if(pPdoExt->m_bReportMissing) { SetNewPnpState(pPdoExt,IRP_MN_REMOVE_DEVICE); PDEVICE_OBJECT pFdo = pPdoExt->m_pParentFdo; if(pFdo) { PFdoExt pFdoExt = static_cast<PFdoExt>(pFdo->DeviceExtension); // update fdo's pointer ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); pFdoExt->m_pEnumPdo = NULL; ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); } // delete device IoDeleteDevice(pDevice); } // if it's present if(pPdoExt->m_bPresent) { // set it as stopped SetNewPnpState(pPdoExt,IRP_MN_STOP_DEVICE); } } break; // query caps case IRP_MN_QUERY_CAPABILITIES: { PDEVICE_CAPABILITIES pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities; // version check if(pCaps->Version != 1 || pCaps->Size < sizeof(DEVICE_CAPABILITIES)) { status = STATUS_UNSUCCESSFUL; break; } IO_STATUS_BLOCK ioStatus; KEVENT pnpEvent; PDEVICE_OBJECT pTargetObject; PIO_STACK_LOCATION pIrpStack; PIRP pPnpIrp; DEVICE_CAPABILITIES parentCaps; RtlZeroMemory(&parentCaps,sizeof(DEVICE_CAPABILITIES)); parentCaps.Size = sizeof(DEVICE_CAPABILITIES); parentCaps.Version = 1; parentCaps.Address = -1; parentCaps.UINumber = -1; KeInitializeEvent(&pnpEvent,NotificationEvent,FALSE); pTargetObject = IoGetAttachedDeviceReference( static_cast<PFdoExt>(pPdoExt->m_pParentFdo->DeviceExtension)->m_pLowerDevice); // get parent fdo's caps pPnpIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,pTargetObject,NULL,0,NULL,&pnpEvent,&ioStatus); if(pPnpIrp == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { pPnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; pIrpStack = IoGetNextIrpStackLocation(pPnpIrp); RtlZeroMemory(pIrpStack,sizeof(IO_STACK_LOCATION)); pIrpStack->MajorFunction = IRP_MJ_PNP; pIrpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; pIrpStack->Parameters.DeviceCapabilities.Capabilities = pCaps; status = IoCallDriver(pTargetObject,pPnpIrp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&pnpEvent,Executive,KernelMode,FALSE,NULL); status = ioStatus.Status; } } // dec the ref of the fdo's stack upper device ObDereferenceObject(pTargetObject); // copy the device state RtlCopyMemory(pCaps->DeviceState,parentCaps.DeviceState,(PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE)); // set our own supported device state pCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0; if(pCaps->DeviceState[PowerSystemSleeping1] != PowerDeviceD0) pCaps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; if(pCaps->DeviceState[PowerSystemSleeping2] != PowerDeviceD0) pCaps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; if(pCaps->DeviceState[PowerSystemSleeping3] != PowerDeviceD0) pCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; // donot support d1 and d2 pCaps->DeviceD1 = pCaps->DeviceD2 = FALSE; // no wake pCaps->DeviceWake = PowerDeviceUnspecified; pCaps->SystemWake = PowerSystemUnspecified; pCaps->WakeFromD0 = FALSE; pCaps->WakeFromD1 = FALSE; pCaps->WakeFromD2 = FALSE; pCaps->WakeFromD3 = FALSE; // no latency pCaps->D1Latency = 0; pCaps->D2Latency = 0; pCaps->D3Latency = 0; // can eject pCaps->EjectSupported = TRUE; // don't disable pCaps->HardwareDisabled = FALSE; // can be removed pCaps->Removable = TRUE; // don't display surprise remove warning dlg pCaps->SurpriseRemovalOK = TRUE; // no unique id pCaps->UniqueID = FALSE; // nead user action for install pCaps->SilentInstall = FALSE; // bus address pCaps->Address = 0; // ui display number pCaps->UINumber = 0; } break; // query pdo id case IRP_MN_QUERY_ID: { switch(pIoStack->Parameters.QueryId.IdType) { case BusQueryInstanceID: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,10,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlStringCchPrintfW(static_cast<PWCHAR>(buffer),10,L"%04d",0); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryInstanceID\n"); } break; case BusQueryDeviceID: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,PDO_DEVICE_ID_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(buffer,PDO_DEVICE_ID,PDO_DEVICE_ID_LENGTH); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryDeviceID\n"); } break; case BusQueryHardwareIDs: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,PDO_HARDWARE_IDS_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(buffer,PDO_HARDWARE_IDS,PDO_HARDWARE_IDS_LENGTH); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryHardwareIDs\n"); } break; case BusQueryCompatibleIDs: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,PDO_COMPATIBLE_IDS_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(buffer,PDO_COMPATIBLE_IDS,PDO_COMPATIBLE_IDS_LENGTH); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryCompatibleIDs\n"); } break; } } break; // query text case IRP_MN_QUERY_DEVICE_TEXT: { switch (pIoStack->Parameters.QueryDeviceText.DeviceTextType) { case DeviceTextDescription: if(!pIrp->IoStatus.Information) { PVOID buffer = ExAllocatePoolWithTag (PagedPool,PDO_TEXT_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlStringCchPrintfW(static_cast<PWCHAR>(buffer),PDO_TEXT_LENGTH,L"%ws",PDO_TEXT); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tDeviceTextDescription\n"); } break; default: status = pIrp->IoStatus.Status; break; } } break; // boot resource case IRP_MN_QUERY_RESOURCES: { PCM_RESOURCE_LIST pResList = static_cast<PCM_RESOURCE_LIST>(ExAllocatePoolWithTag(PagedPool, sizeof(CM_RESOURCE_LIST),'suBT')); if(pResList) { // shareed busnumber resource RtlZeroMemory(pResList,sizeof(CM_RESOURCE_LIST)); pResList->Count = 1; pResList->List[0].BusNumber = 0; pResList->List[0].InterfaceType = Internal; pResList->List[0].PartialResourceList.Count = 1; pResList->List[0].PartialResourceList.Revision = 1; pResList->List[0].PartialResourceList.Version = 1; pResList->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareShared; pResList->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeBusNumber; pResList->List[0].PartialResourceList.PartialDescriptors[0].u.BusNumber.Length = 1; pIrp->IoStatus.Information = PtrToUlong(pResList); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } break; // resource requirements case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: { PIO_RESOURCE_REQUIREMENTS_LIST pList = static_cast<PIO_RESOURCE_REQUIREMENTS_LIST>( ExAllocatePoolWithTag(PagedPool,sizeof(IO_RESOURCE_REQUIREMENTS_LIST),'suBT')); if(pList) { RtlZeroMemory(pList,sizeof(IO_RESOURCE_REQUIREMENTS_LIST)); pList->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); pList->AlternativeLists = 1; pList->InterfaceType = InterfaceTypeUndefined; pList->BusNumber = 0; pList->List[0].Version = 1; pList->List[0].Revision = 1; pList->List[0].Count = 1; pList->List[0].Descriptors[0].Option = IO_RESOURCE_PREFERRED; pList->List[0].Descriptors[0].ShareDisposition = CmResourceShareShared; pList->List[0].Descriptors[0].Type = CmResourceTypeBusNumber; pList->List[0].Descriptors[0].u.BusNumber.MaxBusNumber = 0x10; pList->List[0].Descriptors[0].u.BusNumber.Length = 1; pIrp->IoStatus.Information = PtrToUlong(pList); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } break; // bus info case IRP_MN_QUERY_BUS_INFORMATION: { PPNP_BUS_INFORMATION busInfo; busInfo = static_cast<PPNP_BUS_INFORMATION>(ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION),'suBT')); if (busInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } busInfo->BusTypeGuid = GUID_TIAMO_BUS; busInfo->LegacyBusType = Internal; busInfo->BusNumber = 0; pIrp->IoStatus.Information = PtrToUlong(busInfo); } break; // usage case IRP_MN_DEVICE_USAGE_NOTIFICATION: status = STATUS_UNSUCCESSFUL; break; case IRP_MN_EJECT: { // device physical removed pPdoExt->m_bPresent = FALSE; } break; //case IRP_MN_QUERY_INTERFACE: // break; // target relations case IRP_MN_QUERY_DEVICE_RELATIONS: { if(pIoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) { /*switch(pIoStack->Parameters.QueryDeviceRelations.Type) { case EjectionRelations: devDebugPrint("\tquery EjectionRelations\n"); break; case PowerRelations: devDebugPrint("\tquery PowerRelations\n"); break; case RemovalRelations: devDebugPrint("\tquery RemovalRelations\n"); break; case BusDeviceRelation: devDebugPrint("\tquery BusDeviceRelation\n"); break; case SingleBusRelations: devDebugPrint("\tquery SingleBusRelations\n"); break; }*/ break; } PDEVICE_RELATIONS pRel = static_cast<PDEVICE_RELATIONS>(ExAllocatePoolWithTag(PagedPool,sizeof(DEVICE_RELATIONS),'suBT')); if(!pRel) { status = STATUS_INSUFFICIENT_RESOURCES; break; } pRel->Count = 1; pRel->Objects[0] = pDevice; ObReferenceObject(pDevice); status = STATUS_SUCCESS; pIrp->IoStatus.Information = PtrToUlong(pRel); } break; default: status = pIrp->IoStatus.Status; break; } // pdo should complete the irp pIrp->IoStatus.Status = status; IoCompleteRequest (pIrp, IO_NO_INCREMENT); return status; }
NTSTATUS SetDeviceFunctional( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: This routine processes queue of pending irps. Arguments: DeviceObject - pointer to device object Irp - I/O request packet DeviceExtension - pointer to device extension Return Value: NT status value --*/ { KIRQL oldIrql; NTSTATUS ntStatus; POWER_STATE newState; PIO_STACK_LOCATION irpStack; DEVICE_POWER_STATE newDevState, oldDevState; // // initialize variables // ntStatus = Irp->IoStatus.Status; irpStack = IoGetCurrentIrpStackLocation(Irp); newState = irpStack->Parameters.Power.State; newDevState = newState.DeviceState; oldDevState = DeviceExtension->DevPower; MobiUsb_DbgPrint(3, ("file mobipwr: SetDeviceFunctional - begins\n")); // // update the cached state // DeviceExtension->DevPower = newDevState; // // restore appropriate amount of state to our h/w // this driver does not implement partial context // save/restore. // PoSetPowerState(DeviceObject, DevicePowerState, newState); if(PowerDeviceD0 == newDevState) { // // empty existing queue of all pending irps. // KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql); DeviceExtension->QueueState = AllowRequests; KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql); ProcessQueuedRequests(DeviceExtension); } PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); MobiUsb_DbgPrint(3, ("file mobipwr: SetDeviceFunctional::")); MobiUsb_IoDecrement(DeviceExtension); MobiUsb_DbgPrint(3, ("file mobipwr: SetDeviceFunctional - ends\n")); return STATUS_SUCCESS; }
NTSTATUS NTAPI PortClsPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStack; PPCLASS_DEVICE_EXTENSION DeviceExtension; PQUERY_POWER_CONTEXT PwrContext; POWER_STATE PowerState; NTSTATUS Status = STATUS_SUCCESS; DPRINT("PortClsPower called\n"); // get currrent stack location IoStack = IoGetCurrentIrpStackLocation(Irp); if (IoStack->MinorFunction != IRP_MN_SET_POWER && IoStack->MinorFunction != IRP_MN_QUERY_POWER) { // just forward the request Status = PcForwardIrpSynchronous(DeviceObject, Irp); // start next power irp PoStartNextPowerIrp(Irp); // complete request Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } // get device extension DeviceExtension = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension; // get current request type if (IoStack->Parameters.Power.Type == DevicePowerState) { // request for device power state if (DeviceExtension->DevicePowerState == IoStack->Parameters.Power.State.DeviceState) { // nothing has changed if (IoStack->MinorFunction == IRP_MN_QUERY_POWER) { // only forward query requests Status = PcForwardIrpSynchronous(DeviceObject, Irp); } // start next power irp PoStartNextPowerIrp(Irp); // complete request Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } if (IoStack->MinorFunction == IRP_MN_QUERY_POWER) { // check if there is a registered adapter power management if (DeviceExtension->AdapterPowerManagement) { // it is query if the change can be changed PowerState = *((POWER_STATE*)&IoStack->Parameters.Power.State.DeviceState); Status = DeviceExtension->AdapterPowerManagement->QueryPowerChangeState(PowerState); // sanity check PC_ASSERT(Status == STATUS_SUCCESS); } // only forward query requests PcForwardIrpSynchronous(DeviceObject, Irp); // start next power irp PoStartNextPowerIrp(Irp); // complete request Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } else { // set power state PowerState = *((POWER_STATE*)&IoStack->Parameters.Power.State.DeviceState); PoSetPowerState(DeviceObject, DevicePowerState, PowerState); // check if there is a registered adapter power management if (DeviceExtension->AdapterPowerManagement) { // notify of a power change state DeviceExtension->AdapterPowerManagement->PowerChangeState(PowerState); } // FIXME call all registered IPowerNotify interfaces via ISubdevice interface // store new power state DeviceExtension->DevicePowerState = IoStack->Parameters.Power.State.DeviceState; // complete request Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } } else { // sanity check PC_ASSERT(IoStack->Parameters.Power.Type == SystemPowerState); if (IoStack->MinorFunction == IRP_MN_QUERY_POWER) { // mark irp as pending IoMarkIrpPending(Irp); // allocate power completion context PwrContext = (PQUERY_POWER_CONTEXT)AllocateItem(NonPagedPool, sizeof(QUERY_POWER_CONTEXT), TAG_PORTCLASS); if (!PwrContext) { // no memory PoStartNextPowerIrp(Irp); // complete and forget Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } // setup power context PwrContext->Irp = Irp; PwrContext->DeviceObject = DeviceObject; // pass the irp down PowerState = *((POWER_STATE*)IoStack->Parameters.Power.State.SystemState); Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject, IoStack->MinorFunction, PowerState, PwrCompletionFunction, (PVOID)PwrContext, NULL); // check for success if (!NT_SUCCESS(Status)) { // failed Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } // done return STATUS_PENDING; } else { // set power request DeviceExtension->SystemPowerState = IoStack->Parameters.Power.State.SystemState; // only forward query requests Status = PcForwardIrpSynchronous(DeviceObject, Irp); // start next power irp PoStartNextPowerIrp(Irp); // complete request Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); // done return Status; } } }
NTSTATUS NTAPI PciPdoIrpStartDevice(IN PIRP Irp, IN PIO_STACK_LOCATION IoStackLocation, IN PPCI_PDO_EXTENSION DeviceExtension) { NTSTATUS Status; BOOLEAN Changed, DoReset; POWER_STATE PowerState; PAGED_CODE(); DoReset = FALSE; /* Begin entering the start phase */ Status = PciBeginStateTransition((PVOID)DeviceExtension, PciStarted); if (!NT_SUCCESS(Status)) return Status; /* Check if this is a VGA device */ if (((DeviceExtension->BaseClass == PCI_CLASS_PRE_20) && (DeviceExtension->SubClass == PCI_SUBCLASS_PRE_20_VGA)) || ((DeviceExtension->BaseClass == PCI_CLASS_DISPLAY_CTLR) && (DeviceExtension->SubClass == PCI_SUBCLASS_VID_VGA_CTLR))) { /* Always force it on */ DeviceExtension->CommandEnables |= (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); } /* Check if native IDE is enabled and it owns the I/O ports */ if (DeviceExtension->IoSpaceUnderNativeIdeControl) { /* Then don't allow I/O access */ DeviceExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE; } /* Always enable bus mastering */ DeviceExtension->CommandEnables |= PCI_ENABLE_BUS_MASTER; /* Check if the OS assigned resources differ from the PCI configuration */ Changed = PciComputeNewCurrentSettings(DeviceExtension, IoStackLocation->Parameters. StartDevice.AllocatedResources); if (Changed) { /* Remember this for later */ DeviceExtension->MovedDevice = TRUE; } else { /* All good */ DPRINT1("PCI - START not changing resource settings.\n"); } /* Check if the device was sleeping */ if (DeviceExtension->PowerState.CurrentDeviceState != PowerDeviceD0) { /* Power it up */ Status = PciSetPowerManagedDevicePowerState(DeviceExtension, PowerDeviceD0, FALSE); if (!NT_SUCCESS(Status)) { /* Powerup fail, fail the request */ PciCancelStateTransition((PVOID)DeviceExtension, PciStarted); return STATUS_DEVICE_POWER_FAILURE; } /* Tell the power manager that the device is powered up */ PowerState.DeviceState = PowerDeviceD0; PoSetPowerState(DeviceExtension->PhysicalDeviceObject, DevicePowerState, PowerState); /* Update internal state */ DeviceExtension->PowerState.CurrentDeviceState = PowerDeviceD0; /* This device's resources and decodes will need to be reset */ DoReset = TRUE; } /* Update resource information now that the device is powered up and active */ Status = PciSetResources(DeviceExtension, DoReset, TRUE); if (!NT_SUCCESS(Status)) { /* That failed, so cancel the transition */ PciCancelStateTransition((PVOID)DeviceExtension, PciStarted); } else { /* Fully commit, as the device is now started up and ready to go */ PciCommitStateTransition((PVOID)DeviceExtension, PciStarted); } /* Return the result of the start request */ return Status; }
/* [trobinso MOD 4/16/2010] * If running as a filter, do not act as power policy owner. */ NTSTATUS dispatch_power(libusb_device_t *dev, IRP *irp) { IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp); POWER_STATE power_state; NTSTATUS status; status = remove_lock_acquire(dev); if (!NT_SUCCESS(status)) { irp->IoStatus.Status = status; PoStartNextPowerIrp(irp); IoCompleteRequest(irp, IO_NO_INCREMENT); return status; } if (stack_location->MinorFunction == IRP_MN_SET_POWER) { power_state = stack_location->Parameters.Power.State; if (stack_location->Parameters.Power.Type == SystemPowerState) { USBMSG("IRP_MN_SET_POWER: S%d %s\n", power_state.SystemState - PowerSystemWorking, dev->device_id); } else { USBMSG("IRP_MN_SET_POWER: D%d %s\n", power_state.DeviceState - PowerDeviceD0, dev->device_id); if (power_state.DeviceState > dev->power_state.DeviceState) { /* device is powered down, report device state to the */ /* Power Manager before sending the IRP down */ /* (power up is handled by the completion routine) */ PoSetPowerState(dev->self, DevicePowerState, power_state); } } /* TODO: should PoStartNextPowerIrp() be called here or from the */ /* completion routine? */ PoStartNextPowerIrp(irp); IoCopyCurrentIrpStackLocationToNext(irp); if (!dev->is_filter && !dev->disallow_power_control) { IoSetCompletionRoutine(irp, on_power_state_complete, dev, TRUE, /* on success */ TRUE, /* on error */ TRUE);/* on cancel */ } else { IoSetCompletionRoutine(irp, on_filter_power_state_complete, dev, TRUE, /* on success */ TRUE, /* on error */ TRUE);/* on cancel */ } return PoCallDriver(dev->next_stack_device, irp); } else { /* pass all other power IRPs down without setting a completion routine */ PoStartNextPowerIrp(irp); IoSkipCurrentIrpStackLocation(irp); status = PoCallDriver(dev->next_stack_device, irp); remove_lock_release(dev); return status; } }
NTSTATUS Bus_PDO_Power ( PPDO_DEVICE_DATA PdoData, PIRP Irp ) /*++ Handles power Irps sent to the PDOs. Typically a bus driver, that is not a power policy owner for the device, does nothing more than starting the next power IRP and completing this one. Arguments: PdoData - Pointer to the PDO device extension. Irp - Pointer to the irp. Return Value: NT status is returned. --*/ { NTSTATUS status; PIO_STACK_LOCATION stack; POWER_STATE powerState; POWER_STATE_TYPE powerType; stack = IoGetCurrentIrpStackLocation (Irp); powerType = stack->Parameters.Power.Type; powerState = stack->Parameters.Power.State; switch (stack->MinorFunction) { case IRP_MN_SET_POWER: Bus_KdPrint_Cont(PdoData, BUS_DBG_POWER_TRACE, ("\tSetting %s power state to %s\n", ((powerType == SystemPowerState) ? "System" : "Device"), ((powerType == SystemPowerState) ? \ DbgSystemPowerString(powerState.SystemState) : \ DbgDevicePowerString(powerState.DeviceState)))); switch (powerType) { case DevicePowerState: PoSetPowerState (PdoData->Self, powerType, powerState); PdoData->DevicePowerState = powerState.DeviceState; status = STATUS_SUCCESS; break; case SystemPowerState: PdoData->SystemPowerState = powerState.SystemState; status = STATUS_SUCCESS; break; default: status = STATUS_NOT_SUPPORTED; break; } break; case IRP_MN_QUERY_POWER: status = STATUS_SUCCESS; break; case IRP_MN_WAIT_WAKE: // // We cannot support wait-wake because we are root-enumerated // driver, and our parent, the PnP manager, doesn't support wait-wake. // If you are a bus enumerated device, and if your parent bus supports // wait-wake, you should send a wait/wake IRP (PoRequestPowerIrp) // in response to this request. // If you want to test the wait/wake logic implemented in the function // driver (toaster.sys), you could do the following simulation: // a) Mark this IRP pending. // b) Set a cancel routine. // c) Save this IRP in the device extension // d) Return STATUS_PENDING. // Later on if you suspend and resume your system, your BUS_FDO_POWER // will be called to power the bus. In response to IRP_MN_SET_POWER, if the // powerstate is PowerSystemWorking, complete this Wake IRP. // If the function driver, decides to cancel the wake IRP, your cancel routine // will be called. There you just complete the IRP with STATUS_CANCELLED. // case IRP_MN_POWER_SEQUENCE: default: status = STATUS_NOT_SUPPORTED; break; } if (status != STATUS_NOT_SUPPORTED) { Irp->IoStatus.Status = status; } PoStartNextPowerIrp(Irp); status = Irp->IoStatus.Status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; }
NTSTATUS NTAPI PcmciaPower(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PPCMCIA_COMMON_EXTENSION Common = DeviceObject->DeviceExtension; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS Status; switch (IrpSp->MinorFunction) { case IRP_MN_QUERY_POWER: /* I don't see any reason that we should care */ DPRINT("PCMCIA: IRP_MN_QUERY_POWER\n"); Status = STATUS_SUCCESS; break; case IRP_MN_POWER_SEQUENCE: DPRINT("PCMCIA: IRP_MN_POWER_SEQUENCE\n"); RtlCopyMemory(IrpSp->Parameters.PowerSequence.PowerSequence, &Common->PowerSequence, sizeof(POWER_SEQUENCE)); Status = STATUS_SUCCESS; break; case IRP_MN_WAIT_WAKE: /* Not really sure about this */ DPRINT("PCMCIA: IRP_MN_WAIT_WAKE\n"); Status = STATUS_NOT_SUPPORTED; break; case IRP_MN_SET_POWER: DPRINT("PCMCIA: IRP_MN_SET_POWER\n"); if (IrpSp->Parameters.Power.Type == SystemPowerState) { Common->SystemPowerState = IrpSp->Parameters.Power.State.SystemState; Status = STATUS_SUCCESS; } else { Common->DevicePowerState = IrpSp->Parameters.Power.State.DeviceState; /* Update the POWER_SEQUENCE struct */ if (Common->DevicePowerState <= PowerDeviceD1) Common->PowerSequence.SequenceD1++; if (Common->DevicePowerState <= PowerDeviceD2) Common->PowerSequence.SequenceD2++; if (Common->DevicePowerState <= PowerDeviceD3) Common->PowerSequence.SequenceD3++; /* Start the underlying device if we are handling this for a PDO */ if (!Common->IsFDO) Status = PcmciaPdoSetPowerState((PPCMCIA_PDO_EXTENSION)Common); else Status = STATUS_SUCCESS; } /* Report that we changed state to the Power Manager */ PoSetPowerState(DeviceObject, IrpSp->Parameters.Power.Type, IrpSp->Parameters.Power.State); break; default: DPRINT1("PCMCIA: Invalid MN code in MJ_POWER handler %x\n", IrpSp->MinorFunction); ASSERT(FALSE); Status = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
/*++//////////////////////////////////////////////////////////////////////////// ClasspPowerHandler() Routine Description: This routine reduces the number of useless spinups and spindown requests sent to a given device by ignoring transitions to power states we are currently in. ISSUE-2000/02/20-henrygab - by ignoring spin-up requests, we may be allowing the drive Arguments: DeviceObject - the device object which is transitioning power states Irp - the power irp Options - a set of flags indicating what the device handles Return Value: --*/ NTSTATUS NTAPI ClasspPowerHandler( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN CLASS_POWER_OPTIONS Options // ISSUE-2000/02/20-henrygab - pass pointer, not whole struct ) { PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION nextIrpStack; PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; PCLASS_POWER_CONTEXT context; if (!commonExtension->IsFdo) { // // certain assumptions are made here, // particularly: having the fdoExtension // DebugPrint((0, "ClasspPowerHandler: Called for PDO %p???\n", DeviceObject)); ASSERT(!"PDO using ClasspPowerHandler"); return STATUS_NOT_SUPPORTED; } DebugPrint((1, "ClasspPowerHandler: Power irp %p to %s %p\n", Irp, (commonExtension->IsFdo ? "fdo" : "pdo"), DeviceObject)); switch(irpStack->MinorFunction) { case IRP_MN_SET_POWER: { PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; DebugPrint((1, "(%p)\tIRP_MN_SET_POWER\n", Irp)); DebugPrint((1, "(%p)\tSetting %s state to %d\n", Irp, (irpStack->Parameters.Power.Type == SystemPowerState ? "System" : "Device"), irpStack->Parameters.Power.State.SystemState)); switch (irpStack->Parameters.Power.ShutdownType){ case PowerActionSleep: case PowerActionHibernate: if (fdoData->HotplugInfo.MediaRemovable || fdoData->HotplugInfo.MediaHotplug){ /* * We are suspending and this drive is either hot-pluggable * or contains removeable media. * Set the media dirty bit, since the media may change while * we are suspended. */ SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME); } break; default: break; } break; } default: { DebugPrint((1, "(%p)\tIrp minor code = %#x\n", Irp, irpStack->MinorFunction)); break; } } if (irpStack->Parameters.Power.Type != DevicePowerState || irpStack->MinorFunction != IRP_MN_SET_POWER) { DebugPrint((1, "(%p)\tSending to lower device\n", Irp)); goto ClasspPowerHandlerCleanup; } nextIrpStack = IoGetNextIrpStackLocation(Irp); // // already in exact same state, don't work to transition to it. // if(irpStack->Parameters.Power.State.DeviceState == fdoExtension->DevicePowerState) { DebugPrint((1, "(%p)\tAlready in device state %x\n", Irp, fdoExtension->DevicePowerState)); goto ClasspPowerHandlerCleanup; } // // or powering down from non-d0 state (device already stopped) // NOTE -- we're not sure whether this case can exist or not (the // power system may never send this sort of request) but it's trivial // to deal with. // if ((irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0) && (fdoExtension->DevicePowerState != PowerDeviceD0)) { DebugPrint((1, "(%p)\tAlready powered down to %x???\n", Irp, fdoExtension->DevicePowerState)); fdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState; goto ClasspPowerHandlerCleanup; } // // or going into a hibernation state when we're in the hibernation path. // If the device is spinning then we should leave it spinning - if it's not // then the dump driver will start it up for us. // if((irpStack->Parameters.Power.State.DeviceState == PowerDeviceD3) && (irpStack->Parameters.Power.ShutdownType == PowerActionHibernate) && (commonExtension->HibernationPathCount != 0)) { DebugPrint((1, "(%p)\tdoing nothing for hibernation request for " "state %x???\n", Irp, fdoExtension->DevicePowerState)); fdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState; goto ClasspPowerHandlerCleanup; } // // or when not handling powering up and are powering up // if ((!Options.HandleSpinUp) && (irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0)) { DebugPrint((2, "(%p)\tNot handling spinup to state %x\n", Irp, fdoExtension->DevicePowerState)); fdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState; goto ClasspPowerHandlerCleanup; } // // or when not handling powering down and are powering down // if ((!Options.HandleSpinDown) && (irpStack->Parameters.Power.State.DeviceState != PowerDeviceD0)) { DebugPrint((2, "(%p)\tNot handling spindown to state %x\n", Irp, fdoExtension->DevicePowerState)); fdoExtension->DevicePowerState = irpStack->Parameters.Power.State.DeviceState; goto ClasspPowerHandlerCleanup; } context = &(fdoExtension->PowerContext); #if DBG // // Mark the context as in use. We should be synchronizing this but // since it's just for debugging purposes we don't worry too much. // ASSERT(context->InUse == FALSE); #endif RtlZeroMemory(context, sizeof(CLASS_POWER_CONTEXT)); context->InUse = TRUE; nextIrpStack->Parameters.Scsi.Srb = &(context->Srb); nextIrpStack->MajorFunction = IRP_MJ_SCSI; context->FinalStatus = STATUS_SUCCESS; context->Srb.Length = sizeof(SCSI_REQUEST_BLOCK); context->Srb.OriginalRequest = Irp; context->Srb.SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE; context->Srb.Function = SRB_FUNCTION_LOCK_QUEUE; context->Srb.SenseInfoBuffer = commonExtension->PartitionZeroExtension->SenseData; context->Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE; context->RetryCount = MAXIMUM_RETRIES; context->Options = Options; context->DeviceObject = DeviceObject; context->Irp = Irp; if(irpStack->Parameters.Power.State.DeviceState == PowerDeviceD0) { ASSERT(Options.HandleSpinUp); DebugPrint((2, "(%p)\tpower up - locking queue\n", Irp)); // // We need to issue a queue lock request so that we // can spin the drive back up after the power is restored // but before any requests are processed. // context->Options.PowerDown = FALSE; context->PowerChangeState.PowerUp = PowerUpDeviceInitial; context->CompletionRoutine = ClasspPowerUpCompletion; } else { ASSERT(Options.HandleSpinDown); fdoExtension->PowerDownInProgress = TRUE; DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp)); PoSetPowerState(DeviceObject, irpStack->Parameters.Power.Type, irpStack->Parameters.Power.State); context->Options.PowerDown = TRUE; context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2; context->CompletionRoutine = ClasspPowerDownCompletion; } // // we are not dealing with port-allocated sense in these routines. // ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE)); // // we are always returning STATUS_PENDING, so we need to always // set the irp as pending. // IoMarkIrpPending(Irp); if(Options.LockQueue) { // // Send the lock irp down. // IoSetCompletionRoutine(Irp, context->CompletionRoutine, context, TRUE, TRUE, TRUE); IoCallDriver(lowerDevice, Irp); } else { // // Call the completion routine directly. It won't care what the // status of the "lock" was - it will just go and do the next // step of the operation. // context->CompletionRoutine(DeviceObject, Irp, context); } return STATUS_PENDING; ClasspPowerHandlerCleanup: ClassReleaseRemoveLock(DeviceObject, Irp); DebugPrint((1, "(%p)\tStarting next power irp\n", Irp)); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, ClasspStartNextPowerIrpCompletion, NULL, TRUE, TRUE, TRUE); return PoCallDriver(lowerDevice, Irp); } // end ClasspPowerHandler()
NTSTATUS NTAPI PortClsPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS Status; PPCLASS_DEVICE_EXTENSION DeviceExt; PIO_STACK_LOCATION IoStack; POWER_STATE PowerState; IResourceList* resource_list = NULL; //ULONG Index; //PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor, UnPartialDescriptor; DeviceExt = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension; IoStack = IoGetCurrentIrpStackLocation(Irp); DPRINT("PortClsPnp called %u\n", IoStack->MinorFunction); //PC_ASSERT(DeviceExt); switch (IoStack->MinorFunction) { case IRP_MN_START_DEVICE: DPRINT("IRP_MN_START_DEVICE\n"); // Create the resource list Status = PcNewResourceList( &resource_list, NULL, PagedPool, IoStack->Parameters.StartDevice.AllocatedResourcesTranslated, IoStack->Parameters.StartDevice.AllocatedResources); if (!NT_SUCCESS(Status)) { DPRINT("PcNewResourceList failed [0x%8x]\n", Status); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } // forward irp to lower device object Status = PcForwardIrpSynchronous(DeviceObject, Irp); if (!NT_SUCCESS(Status)) { // lower device object failed to start resource_list->Release(); // complete the request IoCompleteRequest(Irp, IO_NO_INCREMENT); // return result return Status; } // sanity check //PC_ASSERT(DeviceExt->StartDevice); // Call the StartDevice routine DPRINT("Calling StartDevice at 0x%8p\n", DeviceExt->StartDevice); Status = DeviceExt->StartDevice(DeviceObject, Irp, resource_list); if (!NT_SUCCESS(Status)) { DPRINT("StartDevice returned a failure code [0x%8x]\n", Status); Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; } // Assign the resource list to our extension DeviceExt->resources = resource_list; // store device power state DeviceExt->DevicePowerState = PowerDeviceD0; DeviceExt->SystemPowerState = PowerSystemWorking; // notify power manager of current state PowerState = *((POWER_STATE*)&DeviceExt->DevicePowerState); PoSetPowerState(DeviceObject, DevicePowerState, PowerState); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; case IRP_MN_REMOVE_DEVICE: // Clean up DPRINT("IRP_MN_REMOVE_DEVICE\n"); // sanity check PC_ASSERT(DeviceExt); // FIXME more cleanup */ if (DeviceExt->resources) { // free resource list */ DeviceExt->resources->Release(); // set to null DeviceExt->resources = NULL; } // Forward request Status = PcForwardIrpSynchronous(DeviceObject, Irp); return PcCompleteIrp(DeviceObject, Irp, Status); case IRP_MN_QUERY_INTERFACE: DPRINT("IRP_MN_QUERY_INTERFACE\n"); Status = PcForwardIrpSynchronous(DeviceObject, Irp); return PcCompleteIrp(DeviceObject, Irp, Status); case IRP_MN_QUERY_DEVICE_RELATIONS: DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n"); Status = PcForwardIrpSynchronous(DeviceObject, Irp); return PcCompleteIrp(DeviceObject, Irp, Status); case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); Status = PcForwardIrpSynchronous(DeviceObject, Irp); return PcCompleteIrp(DeviceObject, Irp, Status); case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n"); Status = PcForwardIrpSynchronous(DeviceObject, Irp); return PcCompleteIrp(DeviceObject, Irp, Status); case IRP_MN_READ_CONFIG: DPRINT("IRP_MN_READ_CONFIG\n"); Status = PcForwardIrpSynchronous(DeviceObject, Irp); return PcCompleteIrp(DeviceObject, Irp, Status); } DPRINT("unhandled function %u\n", IoStack->MinorFunction); Status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
GENERICAPI NTSTATUS InitializeGenericExtension(PGENERIC_EXTENSION pdx, PGENERIC_INIT_STRUCT isp) { // InitializeGenericExtension if(isp->Size < FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) || !isp->DeviceObject || !isp->Ldo || !isp->Pdo || !isp->StartDevice || !isp->StopDevice || !isp->RemoveDevice || isp->DeviceQueue && !isp->StartIo) return STATUS_INVALID_PARAMETER; RtlZeroMemory(pdx, sizeof(GENERIC_EXTENSION)); pdx->DeviceObject = isp->DeviceObject; pdx->LowerDeviceObject = isp->Ldo; pdx->Pdo = isp->Pdo; pdx->StartDevice = isp->StartDevice; pdx->StopDevice = isp->StopDevice; pdx->RemoveDevice = isp->RemoveDevice; if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, OkayToRemove) + sizeof(PQUERYFUNCTION)) { // set OkayToStop & OkayToRemove pointers pdx->OkayToStop = isp->OkayToStop; pdx->OkayToRemove = isp->OkayToRemove; } // set OkayToStop & OkayToRemove pointers if((pdx->RemoveLock = isp->RemoveLock)) IoInitializeRemoveLock(pdx->RemoveLock, 0, 0, 0); pdx->state = STOPPED; pdx->devpower = PowerDeviceD0; pdx->syspower = PowerSystemWorking; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pdx->DeviceObject, DevicePowerState, state); // In version 1.3, I added support for multiple IRP queues if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, NumberOfQueues) + sizeof(ULONG) && isp->NumberOfQueues) { // multiple queues ULONG i; if(isp->DeviceQueue || isp->StartIo) return STATUS_INVALID_PARAMETER; // can't mix new and old ways of identifying queues if(isp->Size < FIELD_OFFSET(GENERIC_INIT_STRUCT, Queues) + isp->NumberOfQueues * 2 * sizeof(PVOID)) return STATUS_INVALID_PARAMETER; // init structure not big enough for (i = 0; i < isp->NumberOfQueues; ++i) if(!isp->Queues[i].DeviceQueue || !isp->Queues[i].StartIo) return STATUS_INVALID_PARAMETER; // none of the entries can be NULL pdx->nqueues = isp->NumberOfQueues; pdx->queues = (PDEVQUEUE*) ExAllocatePoolWithTag(NonPagedPool, isp->NumberOfQueues * sizeof(PDEVQUEUE), SPOT_TAG); if(!pdx->queues) return STATUS_INSUFFICIENT_RESOURCES; for (i = 0; i < isp->NumberOfQueues; ++i) { // for each queue pdx->queues[i] = isp->Queues[i].DeviceQueue; InitializeQueue(pdx->queues[i], isp->Queues[i].StartIo); } // for each queue } // multiple queues else if(isp->DeviceQueue) { // single queue pdx->nqueues = 1; pdx->queues = (PDEVQUEUE*) ExAllocatePoolWithTag(NonPagedPool, sizeof(PDEVQUEUE), SPOT_TAG); if(!pdx->queues) return STATUS_INSUFFICIENT_RESOURCES; pdx->queues[0] = isp->DeviceQueue; InitializeQueue(pdx->queues[0], isp->StartIo); } // single queue // In version 1.9, I added support for FlushPendingIo. // In version 1.10, GetDevicePowerState if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, Queues)) { // additional reserved fields pdx->FlushPendingIo = isp->FlushPendingIo; pdx->GetDevicePowerState = isp->GetDevicePowerState; } // additional reserved fields // Capture the mini-driver name for messages. This needs to be in ANSI because // unicode conversions at or above DISPATCH_LEVEL are not allowed. In retrospect, I // should have made the field in the INIT struct be in ANSI to start with... if(!isp->DebugName.Length) strcpy(pdx->DebugName, "GENERIC"); else { // convert debug name ANSI_STRING asname = {0, sizeof(pdx->DebugName) - 1, pdx->DebugName}; RtlUnicodeStringToAnsiString(&asname, &isp->DebugName, FALSE); pdx->DebugName[asname.Length] = 0; } // convert debug name if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, Flags) + sizeof(ULONG)) pdx->Flags = isp->Flags & GENERIC_CLIENT_FLAGS; if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, RestoreDeviceContext) + sizeof(PCONTEXTFUNCTION)) { // get power helper functions pdx->QueryPower = isp->QueryPower; pdx->SaveDeviceContext = isp->SaveDeviceContext; pdx->RestoreDeviceContext = isp->RestoreDeviceContext; } // get power helper functions if(isp->Size >= FIELD_OFFSET(GENERIC_INIT_STRUCT, PerfBoundary) + sizeof(DEVICE_POWER_STATE)) pdx->PerfBoundary = isp->PerfBoundary; else pdx->PerfBoundary = PowerDeviceUnspecified; if(pdx->PerfBoundary == PowerDeviceUnspecified) pdx->PerfBoundary = PowerDeviceMaximum; // inhibit POWER_SEQUENCE optimization // Initialize variables related to asynchrounous IOCTL management. In version 2.0, this // is now always done rather than depending on a flag in the init struct. InitializeListHead(&pdx->PendingIoctlList); pdx->IoctlAbortStatus = 0; KeInitializeSpinLock(&pdx->IoctlListLock); // Initialize to manage registered device interfaces KeInitializeEvent(&pdx->iflock, SynchronizationEvent, TRUE); InitializeListHead(&pdx->iflist); // Indicate we handle power IRPs at PASSIVE_LEVEL pdx->DeviceObject->Flags |= DO_POWER_PAGABLE; KdPrint(("GENERIC - Initializing for %s\n", pdx->DebugName)); // If device honors paging-path notifications, initialize a synchronization // event in the signalled state to act as a simple mutex (SP-7) if(pdx->Flags & GENERIC_USAGE_PAGING) KeInitializeEvent(&pdx->evPagingPath, SynchronizationEvent, TRUE); // If requested to do so, register an AutoLaunch interface if(pdx->Flags & GENERIC_AUTOLAUNCH) GenericRegisterInterface(pdx, &GUID_AUTOLAUNCH_NOTIFY); // Register a power management interface GenericRegisterInterface(pdx, &GUID_GENERIC_POWER); #ifdef _X86_ win98 = IsWin98(); #endif return STATUS_SUCCESS; } // InitializeGenericExtension
// fdo pnp NTSTATUS DoFdoPnP(PDEVICE_OBJECT pDevice,PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; PFdoExt pFdoExt = static_cast<PFdoExt>(pDevice->DeviceExtension); // nead call next driver BOOLEAN bCallNext = TRUE; PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(pIrp); // inc io count IncIoCount(pFdoExt); // save minor code UCHAR uMinorCode = pIoStack->MinorFunction; switch(uMinorCode) { case IRP_MN_START_DEVICE: { // send down first status = SendIrpToLowerDeviceSyn(pFdoExt->m_pLowerDevice,pIrp); if(NT_SUCCESS(status)) { // set device power state pFdoExt->m_devPowerState = PowerDeviceD0; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pDevice,DevicePowerState,state); // set device interface state status = IoSetDeviceInterfaceState(&pFdoExt->m_symbolicName,TRUE); // set device pnp state SetNewPnpState(pFdoExt,IRP_MN_START_DEVICE); } // complete the irp pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp,IO_NO_INCREMENT); // do not call down the device stack bCallNext = FALSE; } break; // set pnp state directly case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: SetNewPnpState(pFdoExt,uMinorCode); break; // check for current pnp state,and restore it case IRP_MN_CANCEL_REMOVE_DEVICE: if(pFdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) RestorePnpState(pFdoExt); break; // the same case IRP_MN_CANCEL_STOP_DEVICE: if(pFdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) RestorePnpState(pFdoExt); break; // remove case IRP_MN_REMOVE_DEVICE: { // normal remove if(pFdoExt->m_ulCurrentPnpState != IRP_MN_SURPRISE_REMOVAL) { // just stop device interface if(pFdoExt->m_symbolicName.Buffer) { // set device interface false IoSetDeviceInterfaceState(&pFdoExt->m_symbolicName,FALSE); RtlFreeUnicodeString(&pFdoExt->m_symbolicName); } } // update pnp state SetNewPnpState(pFdoExt,IRP_MN_REMOVE_DEVICE); // dec outstandingio by 2 DecIoCount(pFdoExt); DecIoCount(pFdoExt); // wait other irps finish KeWaitForSingleObject(&pFdoExt->m_evRemove,Executive,KernelMode,FALSE,NULL); // check pdo ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); // if the pdo is present if(pFdoExt->m_pEnumPdo) { PPdoExt pPdoExt = static_cast<PPdoExt>(pFdoExt->m_pEnumPdo->DeviceExtension); // surprise removal.update those field if(pPdoExt->m_ulCurrentPnpState == IRP_MN_SURPRISE_REMOVAL) { pPdoExt->m_pParentFdo = NULL; pPdoExt->m_bReportMissing = TRUE; pFdoExt->m_pEnumPdo = NULL; } // delete the pdo device IoDeleteDevice(pFdoExt->m_pEnumPdo); } ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); pIrp->IoStatus.Status = STATUS_SUCCESS; // call next driver,do not need to wait the finish IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pFdoExt->m_pLowerDevice,pIrp); // first detach it from the device stack IoDetachDevice(pFdoExt->m_pLowerDevice); // then delete it,note that the device extension will become invalid,so dec need to check the minor code carefully IoDeleteDevice(pDevice); bCallNext = FALSE; } break; // stop case IRP_MN_STOP_DEVICE: DecIoCount(pFdoExt); KeWaitForSingleObject(&pFdoExt->m_evStop,Executive,KernelMode,FALSE,NULL); IncIoCount(pFdoExt); SetNewPnpState(pFdoExt,IRP_MN_STOP_DEVICE); break; // query bus relations case IRP_MN_QUERY_DEVICE_RELATIONS: { // only care bus relations if (BusRelations != pIoStack->Parameters.QueryDeviceRelations.Type) { /*switch(pIoStack->Parameters.QueryDeviceRelations.Type) { case EjectionRelations: devDebugPrint("\tquery EjectionRelations\n"); break; case PowerRelations: devDebugPrint("\tquery PowerRelations\n"); break; case RemovalRelations: devDebugPrint("\tquery RemovalRelations\n"); break; case TargetDeviceRelation: devDebugPrint("\tquery TargetDeviceRelation\n"); break; case SingleBusRelations: devDebugPrint("\tquery SingleBusRelations\n"); break; }*/ break; } // old relations PDEVICE_RELATIONS pOldRel = static_cast<PDEVICE_RELATIONS>(ULongToPtr(pIrp->IoStatus.Information)); ULONG ulNewCount = 0; ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); // no pdo if(!pFdoExt->m_pEnumPdo) { devDebugPrint("\tBusRelations no device plugin \n"); ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); break; } PPdoExt pPdoExt = static_cast<PPdoExt>(pFdoExt->m_pEnumPdo->DeviceExtension); // if the pdo is not present if(!pPdoExt->m_bPresent) { // then we report it as missing pPdoExt->m_bReportMissing = TRUE; } else { // report the pdo ObReferenceObject(pFdoExt->m_pEnumPdo); ulNewCount ++; } // add the old count if(pOldRel) ulNewCount += pOldRel->Count; // allocate paged memory ULONG len = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (ulNewCount - 1); PDEVICE_RELATIONS pRel = static_cast<PDEVICE_RELATIONS>(ExAllocatePoolWithTag(PagedPool,len,'suBT')); // do not set the status,we should continue with the orignal devices that the upper devices reported if(!pRel) break; // copy old value if(pOldRel) { RtlCopyMemory(pRel,pOldRel,len - sizeof(PDEVICE_OBJECT)); if(pPdoExt->m_bPresent) pRel->Objects[pOldRel->Count] = pFdoExt->m_pEnumPdo; // free the previous buffer ExFreePool(pOldRel); } else { // the device is present if(pPdoExt->m_bPresent) pRel->Objects[0] = pFdoExt->m_pEnumPdo; } pRel->Count = ulNewCount; pIrp->IoStatus.Information = PtrToUlong(pRel); devDebugPrint("\tBusRelations pdo present %d,report %d\n",pPdoExt->m_bPresent,ulNewCount); ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); } break; // surprise removal case IRP_MN_SURPRISE_REMOVAL: { // set pnp state SetNewPnpState(pFdoExt,IRP_MN_SURPRISE_REMOVAL); // stop the fdo if(pFdoExt->m_symbolicName.Buffer) { // set device interface IoSetDeviceInterfaceState(&pFdoExt->m_symbolicName,FALSE); RtlFreeUnicodeString(&pFdoExt->m_symbolicName); } // update pdo's field ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); PPdoExt pPdoExt = static_cast<PPdoExt>(pFdoExt->m_pEnumPdo->DeviceExtension); pPdoExt->m_pParentFdo = NULL; pPdoExt->m_bReportMissing = TRUE; ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); } break; default: status = pIrp->IoStatus.Status; break; } // nead call lower device if(bCallNext) { pIrp->IoStatus.Status = status; IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pFdoExt->m_pLowerDevice,pIrp); } // specail check for remove irp if(uMinorCode != IRP_MN_REMOVE_DEVICE) DecIoCount(pFdoExt); return status; }