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; BulkUsb_DbgPrint(3, ("FinishDevPoDnIrp - begins\n")); if(NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER) { // // update the cache; // BulkUsb_DbgPrint(3, ("updating cache..\n")); DeviceExtension->DevPower = newState.DeviceState; PoSetPowerState(DeviceObject, DevicePowerState, newState); } PoStartNextPowerIrp(Irp); BulkUsb_DbgPrint(3, ("FinishDevPoDnIrp::")); BulkUsb_IoDecrement(DeviceExtension); BulkUsb_DbgPrint(3, ("FinishDevPoDnIrp - ends\n")); return STATUS_SUCCESS; }
NTSTATUS FinishDevPoUpIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: completion routine for the device power UP irp with minor function IRP_MN_SET_POWER. Arguments: DeviceObject - pointer to device object Irp - I/O request packet DeviceExtension - pointer to device extension Return Value: NT status value --*/ { NTSTATUS ntStatus; // // initialize variables // ntStatus = Irp->IoStatus.Status; BulkUsb_DbgPrint(3, ("FinishDevPoUpIrp - begins\n")); if(Irp->PendingReturned) { IoMarkIrpPending(Irp); } if(!NT_SUCCESS(ntStatus)) { PoStartNextPowerIrp(Irp); BulkUsb_DbgPrint(3, ("FinishDevPoUpIrp::")); BulkUsb_IoDecrement(DeviceExtension); return STATUS_SUCCESS; } SetDeviceFunctional(DeviceObject, Irp, DeviceExtension); BulkUsb_DbgPrint(3, ("FinishDevPoUpIrp - ends\n")); return STATUS_MORE_PROCESSING_REQUIRED; }
VOID PoIrpCompletionFunc( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++ Routine Description: Completion routine for power irp PoRequested in IdleNotificationCallback. Arguments: DeviceObject - pointer to device object MinorFunciton - minor function for the irp. PowerState - irp power state Context - context passed to the completion function IoStatus - status block. Return Value: None --*/ { PIRP_COMPLETION_CONTEXT irpContext; // // initialize variables // if(Context) { irpContext = (PIRP_COMPLETION_CONTEXT) Context; } // // all we do is set the event and decrement the count // if(irpContext) { KeSetEvent(irpContext->Event, 0, FALSE); BulkUsb_DbgPrint(3, ("PoIrpCompletionFunc::")); BulkUsb_IoDecrement(irpContext->DeviceExtension); ExFreePool(irpContext); } return; }
static VOID PoIrpAsyncCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus) { PTDeviceExtension DeviceExtension; DeviceExtension = (PTDeviceExtension) Context; if(DeviceExtension) { BulkUsb_DbgPrint(3, ("file bulkdev: PoIrpAsyncCompletionFunc::")); BulkUsb_IoDecrement(DeviceExtension); } }
NTSTATUS BulkUsb_DispatchSysCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PTDeviceExtension deviceExtension; SYSCTL_IRP_DISPOSITION disposition; NTSTATUS ntStatus; PIO_STACK_LOCATION irpStack; PAGED_CODE(); irpStack = IoGetCurrentIrpStackLocation (Irp); deviceExtension = (PTDeviceExtension) DeviceObject->DeviceExtension; if(REMOVED == deviceExtension->DeviceState) { ntStatus = STATUS_DELETE_PENDING; Irp->IoStatus.Status = ntStatus; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } BulkUsb_DbgPrint(3, ("file bulkwmi: BulkUsb_DispatchSysCtrl::\n")); BulkUsb_IoIncrement(deviceExtension); ntStatus = WmiSystemControl(&deviceExtension->WmiLibInfo, DeviceObject, Irp, &disposition); switch(disposition) { case IrpProcessed: break; case IrpNotCompleted: IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IrpForward: case IrpNotWmi: IoSkipCurrentIrpStackLocation (Irp); ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); break; default: IoSkipCurrentIrpStackLocation (Irp); ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); break; } BulkUsb_DbgPrint(3, ("file bulkwmi: BulkUsb_DispatchSysCtrl::\n")); BulkUsb_IoDecrement(deviceExtension); return ntStatus; }
static VOID PoIrpCompletionFunc(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus) { PTIrpCompletionContext irpContext; //irpContext = NULL; //if(Context) irpContext = (PTIrpCompletionContext) Context; if(irpContext) { KeSetEvent(irpContext->Event, 0, FALSE); BulkUsb_DbgPrint(3, ("file bulkdev: PoIrpCompletionFunc::")); BulkUsb_IoDecrement(irpContext->DeviceExtension); ExFreePool(irpContext); } }
VOID PoIrpAsyncCompletionFunc( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++ Routine Description: Completion routine for power irp PoRequested in IdleNotification RequestComplete routine. Arguments: DeviceObject - pointer to device object MinorFunciton - minor function for the irp. PowerState - irp power state Context - context passed to the completion function IoStatus - status block. Return Value: None --*/ { PDEVICE_EXTENSION DeviceExtension; // // initialize variables // DeviceExtension = (PDEVICE_EXTENSION) Context; // // all we do is decrement the count // BulkUsb_DbgPrint(3, ("PoIrpAsyncCompletionFunc::")); BulkUsb_IoDecrement(DeviceExtension); return; }
VOID SendDeviceIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP SIrp ) /*++ Routine Description: This routine is invoked from the completion routine of the system power irp. This routine will PoRequest a device power irp. The system irp is passed as a context to the the device power irp. Arguments: DeviceObject - pointer to device object SIrp - system power irp. Return Value: None --*/ { NTSTATUS ntStatus; POWER_STATE powState; PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; SYSTEM_POWER_STATE systemState; DEVICE_POWER_STATE devState; PPOWER_COMPLETION_CONTEXT powerContext; // // initialize variables // irpStack = IoGetCurrentIrpStackLocation(SIrp); systemState = irpStack->Parameters.Power.State.SystemState; deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; BulkUsb_DbgPrint(3, ("SendDeviceIrp - begins\n")); // // Read out the D-IRP out of the S->D mapping array captured in QueryCap's. // we can choose deeper sleep states than our mapping but never choose // lighter ones. // devState = deviceExtension->DeviceCapabilities.DeviceState[systemState]; powState.DeviceState = devState; powerContext = (PPOWER_COMPLETION_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(POWER_COMPLETION_CONTEXT)); if(!powerContext) { BulkUsb_DbgPrint(1, ("Failed to alloc memory for powerContext\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; } else { powerContext->DeviceObject = DeviceObject; powerContext->SIrp = SIrp; // // in win2k PoRequestPowerIrp can take fdo or pdo. // ntStatus = PoRequestPowerIrp( deviceExtension->PhysicalDeviceObject, irpStack->MinorFunction, powState, (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine, powerContext, NULL); } if(!NT_SUCCESS(ntStatus)) { if(powerContext) { ExFreePool(powerContext); } PoStartNextPowerIrp(SIrp); SIrp->IoStatus.Status = ntStatus; SIrp->IoStatus.Information = 0; IoCompleteRequest(SIrp, IO_NO_INCREMENT); BulkUsb_DbgPrint(3, ("SendDeviceIrp::")); BulkUsb_IoDecrement(deviceExtension); } BulkUsb_DbgPrint(3, ("SendDeviceIrp - ends\n")); }
NTSTATUS BulkUsb_DispatchDevCtrl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Dispatch routine for IRP_MJ_DEVICE_CONTROL Arguments: DeviceObject - pointer to device object Irp - I/O request packet Return Value: NT status value --*/ { ULONG code; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; ULONG info; NTSTATUS ntStatus; PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; // // initialize variables // info = 0; irpStack = IoGetCurrentIrpStackLocation(Irp); code = irpStack->Parameters.DeviceIoControl.IoControlCode; deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; ioBuffer = Irp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; if(deviceExtension->DeviceState != Working) { BulkUsb_DbgPrint(1, ("Invalid device state\n")); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } BulkUsb_DbgPrint(3, ("BulkUsb_DispatchDevCtrl::")); BulkUsb_IoIncrement(deviceExtension); // // It is true that the client driver cancelled the selective suspend // request in the dispatch routine for create. // But there is no guarantee that it has indeed been completed. // so wait on the NoIdleReqPendEvent and proceed only if this event // is signalled. // BulkUsb_DbgPrint(3, ("Waiting on the IdleReqPendEvent\n")); // // make sure that the selective suspend request has been completed. // if(deviceExtension->SSEnable) { KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, Executive, KernelMode, FALSE, NULL); } switch(code) { case IOCTL_BULKUSB_RESET_PIPE: { PFILE_OBJECT fileObject; PUSBD_PIPE_INFORMATION pipe; pipe = NULL; fileObject = NULL; // // FileObject is the address of the kernel file object to // which the IRP is directed. Drivers use the FileObject // to correlate IRPs in a queue. // fileObject = irpStack->FileObject; if(fileObject == NULL) { ntStatus = STATUS_INVALID_PARAMETER; break; } pipe = (PUSBD_PIPE_INFORMATION) fileObject->FsContext; if(pipe == NULL) { ntStatus = STATUS_INVALID_PARAMETER; } else { ntStatus = BulkUsb_ResetPipe(DeviceObject, pipe); } break; } case IOCTL_BULKUSB_GET_CONFIG_DESCRIPTOR: { ULONG length; if(deviceExtension->UsbConfigurationDescriptor) { length = deviceExtension->UsbConfigurationDescriptor->wTotalLength; if(outputBufferLength >= length) { RtlCopyMemory(ioBuffer, deviceExtension->UsbConfigurationDescriptor, length); info = length; ntStatus = STATUS_SUCCESS; } else { ntStatus = STATUS_BUFFER_TOO_SMALL; } } else { ntStatus = STATUS_UNSUCCESSFUL; } break; } case IOCTL_BULKUSB_RESET_DEVICE: ntStatus = BulkUsb_ResetDevice(DeviceObject); break; default : ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status = ntStatus; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); BulkUsb_DbgPrint(3, ("BulkUsb_DispatchDevCtrl::")); BulkUsb_IoDecrement(deviceExtension); return ntStatus; }
//==================== NTSTATUS BulkUsb_DispatchDevCtrl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { ULONG code; PVOID ioBuffer; ULONG inputBufferLength; ULONG outputBufferLength; ULONG info; NTSTATUS ntStatus; PTDeviceExtension deviceExtension; PIO_STACK_LOCATION irpStack; info = 0; irpStack = IoGetCurrentIrpStackLocation(Irp); code = irpStack->Parameters.DeviceIoControl.IoControlCode; deviceExtension = (PTDeviceExtension) DeviceObject->DeviceExtension; ioBuffer = Irp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength; if(deviceExtension->DeviceState != WORKING) { BulkUsb_DbgPrint(1, ("file bulkdev: Invalid device state\n")); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } BulkUsb_DbgPrint(3, ("file bulkdev: BulkUsb_DispatchDevCtrl::")); BulkUsb_IoIncrement(deviceExtension); BulkUsb_DbgPrint(3, ("file bulkdev: Waiting on the IdleReqPendEvent\n")); if(deviceExtension->SSEnable) { KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, Executive, KernelMode, FALSE, NULL); } switch(code) { case IOCTL_BULKUSB_RESET_PIPE: { PFILE_OBJECT fileObject; PUSBD_PIPE_INFORMATION pipe; pipe = NULL; fileObject = irpStack->FileObject; if(fileObject == NULL) { ntStatus = STATUS_INVALID_PARAMETER; break; } pipe = (PUSBD_PIPE_INFORMATION) fileObject->FsContext; if(pipe == NULL) ntStatus = STATUS_INVALID_PARAMETER; else ntStatus = BulkUsb_ResetPipe(DeviceObject, pipe); break; } case IOCTL_BULKUSB_GET_CONFIG_DESCRIPTOR: { ULONG length; if(deviceExtension->UsbConfigurationDescriptor) { length = deviceExtension->UsbConfigurationDescriptor->wTotalLength; if(outputBufferLength >= length) { RtlCopyMemory(ioBuffer, deviceExtension->UsbConfigurationDescriptor, length); info = length; ntStatus = STATUS_SUCCESS; } else ntStatus = STATUS_BUFFER_TOO_SMALL; } else ntStatus = STATUS_UNSUCCESSFUL; break; } case IOCTL_BULKUSB_RESET_DEVICE: ntStatus = BulkUsb_ResetDevice(DeviceObject); break; default : ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status = ntStatus; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); BulkUsb_DbgPrint(3, ("file bulkdev: BulkUsb_DispatchDevCtrl::")); BulkUsb_IoDecrement(deviceExtension); return ntStatus; }
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; BulkUsb_DbgPrint(3, ("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); BulkUsb_DbgPrint(3, ("SetDeviceFunctional::")); BulkUsb_IoDecrement(DeviceExtension); BulkUsb_DbgPrint(3, ("SetDeviceFunctional - ends\n")); return STATUS_SUCCESS; }
VOID HoldIoRequestsWorkerRoutine( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context ) /*++ Routine Description: This routine waits for the I/O in progress to finish and then sends the device power irp (query/set) down the stack. Arguments: DeviceObject - pointer to device object Context - context passed to the work-item. Return Value: None --*/ { PIRP irp; NTSTATUS ntStatus; PDEVICE_EXTENSION deviceExtension; PWORKER_THREAD_CONTEXT context; BulkUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine - begins\n")); // // initialize variables // deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; context = (PWORKER_THREAD_CONTEXT) Context; irp = (PIRP) context->Irp; // // wait for I/O in progress to finish. // the stop event is signalled when the counter drops to 1. // invoke BulkUsb_IoDecrement twice: once each for the S-Irp and D-Irp. // BulkUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::")); BulkUsb_IoDecrement(deviceExtension); BulkUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::")); BulkUsb_IoDecrement(deviceExtension); KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL); // // Increment twice to restore the count // BulkUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::")); BulkUsb_IoIncrement(deviceExtension); BulkUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine::")); BulkUsb_IoIncrement(deviceExtension); // // now send the Irp down // IoCopyCurrentIrpStackLocationToNext(irp); IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp, deviceExtension, TRUE, TRUE, TRUE); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp); if(!NT_SUCCESS(ntStatus)) { BulkUsb_DbgPrint(1, ("Lower driver fail a power Irp\n")); } IoFreeWorkItem(context->WorkItem); ExFreePool((PVOID)context); BulkUsb_DbgPrint(3, ("HoldIoRequestsWorkerRoutine - ends\n")); }
NTSTATUS HandleDeviceSetPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine services irps of minor type IRP_MN_SET_POWER for the device power state Arguments: DeviceObject - pointer to device object Irp - I/O request packet sent by the power manager Return Value: NT status value --*/ { KIRQL oldIrql; NTSTATUS ntStatus; POWER_STATE newState; PIO_STACK_LOCATION irpStack; PDEVICE_EXTENSION deviceExtension; DEVICE_POWER_STATE newDevState, oldDevState; BulkUsb_DbgPrint(3, ("HandleDeviceSetPower - begins\n")); // // initialize variables // deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(Irp); oldDevState = deviceExtension->DevPower; newState = irpStack->Parameters.Power.State; newDevState = newState.DeviceState; BulkUsb_DbgPrint(3, ("Set request for device power state D%X\n" "Current device power state D%X\n", newDevState - 1, deviceExtension->DevPower - 1)); if(newDevState < oldDevState) { // // adding power // BulkUsb_DbgPrint(3, ("Adding power to the device\n")); // // send the power IRP to the next driver in the stack // IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, (PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp, deviceExtension, TRUE, TRUE, TRUE); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); } else { // // newDevState >= oldDevState // // hold I/O if transition from D0 -> DX (X = 1, 2, 3) // if transition from D1 or D2 to deeper sleep states, // I/O queue is already on hold. // if(PowerDeviceD0 == oldDevState && newDevState > oldDevState) { // // D0 -> DX transition // BulkUsb_DbgPrint(3, ("Removing power from the device\n")); ntStatus = HoldIoRequests(DeviceObject, Irp); if(!NT_SUCCESS(ntStatus)) { PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = ntStatus; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); BulkUsb_DbgPrint(3, ("HandleDeviceSetPower::")); BulkUsb_IoDecrement(deviceExtension); return ntStatus; } else { goto HandleDeviceSetPower_Exit; } } else if(PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState) { // // D0 -> D0 // unblock the queue which may have been blocked processing // query irp // BulkUsb_DbgPrint(3, ("A SetD0 request\n")); KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql); deviceExtension->QueueState = AllowRequests; KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql); ProcessQueuedRequests(deviceExtension); } IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp, deviceExtension, TRUE, TRUE, TRUE); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); if(!NT_SUCCESS(ntStatus)) { BulkUsb_DbgPrint(1, ("Lower drivers failed a power Irp\n")); } } HandleDeviceSetPower_Exit: BulkUsb_DbgPrint(3, ("HandleDeviceSetPower - ends\n")); return STATUS_PENDING; }
VOID DevPoCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++ Routine Description: This is the PoRequest - completion routine for the device power irp. This routine is responsible for completing the system power irp, received as a context. Arguments: DeviceObject - pointer to device object MinorFunction - minor function of the irp. PowerState - power state of the irp. Context - context passed to the completion routine. IoStatus - status of the device power irp. Return Value: None --*/ { PIRP sIrp; PDEVICE_EXTENSION deviceExtension; PPOWER_COMPLETION_CONTEXT powerContext; // // initialize variables // powerContext = (PPOWER_COMPLETION_CONTEXT) Context; sIrp = powerContext->SIrp; deviceExtension = powerContext->DeviceObject->DeviceExtension; BulkUsb_DbgPrint(3, ("DevPoCompletionRoutine - begins\n")); // // copy the D-Irp status into S-Irp // sIrp->IoStatus.Status = IoStatus->Status; // // complete the system Irp // PoStartNextPowerIrp(sIrp); sIrp->IoStatus.Information = 0; IoCompleteRequest(sIrp, IO_NO_INCREMENT); // // cleanup // BulkUsb_DbgPrint(3, ("DevPoCompletionRoutine::")); BulkUsb_IoDecrement(deviceExtension); ExFreePool(powerContext); BulkUsb_DbgPrint(3, ("DevPoCompletionRoutine - ends\n")); }
NTSTATUS SysPoCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: This is the completion routine for the system power irps of minor function types IRP_MN_QUERY_POWER and IRP_MN_SET_POWER. This completion routine sends the corresponding device power irp and returns STATUS_MORE_PROCESSING_REQUIRED. The system irp is passed as a context to the device power irp completion routine and is completed in the device power irp completion routine. Arguments: DeviceObject - pointer to device object Irp - I/O request packet DeviceExtension - pointer to device extension Return Value: NT status value --*/ { NTSTATUS ntStatus; PIO_STACK_LOCATION irpStack; // // initialize variables // ntStatus = Irp->IoStatus.Status; irpStack = IoGetCurrentIrpStackLocation(Irp); BulkUsb_DbgPrint(3, ("SysPoCompletionRoutine - begins\n")); // // lower drivers failed this Irp // if(!NT_SUCCESS(ntStatus)) { PoStartNextPowerIrp(Irp); BulkUsb_DbgPrint(3, ("SysPoCompletionRoutine::")); BulkUsb_IoDecrement(DeviceExtension); return STATUS_SUCCESS; } // // ..otherwise update the cached system power state (IRP_MN_SET_POWER) // if(irpStack->MinorFunction == IRP_MN_SET_POWER) { DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState; } // // queue device irp and return STATUS_MORE_PROCESSING_REQUIRED // SendDeviceIrp(DeviceObject, Irp); BulkUsb_DbgPrint(3, ("SysPoCompletionRoutine - ends\n")); return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS BulkUsb_DispatchPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: The power dispatch routine. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { NTSTATUS ntStatus; PIO_STACK_LOCATION irpStack; PUNICODE_STRING tagString; PDEVICE_EXTENSION deviceExtension; // // initialize the variables // irpStack = IoGetCurrentIrpStackLocation(Irp); deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; // // We don't queue power Irps, we'll only check if the // device was removed, otherwise we'll take appropriate // action and send it to the next lower driver. In general // drivers should not cause long delays while handling power // IRPs. If a driver cannot handle a power IRP in a brief time, // it should return STATUS_PENDING and queue all incoming // IRPs until the IRP completes. // if(Removed == deviceExtension->DeviceState) { // // Even if a driver fails the IRP, it must nevertheless call // PoStartNextPowerIrp to inform the Power Manager that it // is ready to handle another power IRP. // PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } if(NotStarted == deviceExtension->DeviceState) { // // if the device is not started yet, pass it down // PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); } BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPower::")); BulkUsb_IoIncrement(deviceExtension); switch(irpStack->MinorFunction) { case IRP_MN_SET_POWER: // // The Power Manager sends this IRP for one of the // following reasons: // 1) To notify drivers of a change to the system power state. // 2) To change the power state of a device for which // the Power Manager is performing idle detection. // A driver sends IRP_MN_SET_POWER to change the power // state of its device if it's a power policy owner for the // device. // IoMarkIrpPending(Irp); switch(irpStack->Parameters.Power.Type) { case SystemPowerState: HandleSystemSetPower(DeviceObject, Irp); ntStatus = STATUS_PENDING; break; case DevicePowerState: HandleDeviceSetPower(DeviceObject, Irp); ntStatus = STATUS_PENDING; break; } break; case IRP_MN_QUERY_POWER: // // The Power Manager sends a power IRP with the minor // IRP code IRP_MN_QUERY_POWER to determine whether it // can safely change to the specified system power state // (S1-S5) and to allow drivers to prepare for such a change. // If a driver can put its device in the requested state, // it sets status to STATUS_SUCCESS and passes the IRP down. // IoMarkIrpPending(Irp); switch(irpStack->Parameters.Power.Type) { case SystemPowerState: HandleSystemQueryPower(DeviceObject, Irp); ntStatus = STATUS_PENDING; break; case DevicePowerState: HandleDeviceQueryPower(DeviceObject, Irp); ntStatus = STATUS_PENDING; break; } break; case IRP_MN_WAIT_WAKE: // // The minor power IRP code IRP_MN_WAIT_WAKE provides // for waking a device or waking the system. Drivers // of devices that can wake themselves or the system // send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE // only to devices that always wake the system, such as // the power-on switch. // IoMarkIrpPending(Irp); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, (PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine, deviceExtension, TRUE, TRUE, TRUE); PoStartNextPowerIrp(Irp); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); if(!NT_SUCCESS(ntStatus)) { BulkUsb_DbgPrint(1, ("Lower drivers failed the wait-wake Irp")); } ntStatus = STATUS_PENDING; // // push back the count HERE and NOT in completion routine // a pending Wait Wake Irp should not impede stopping the device // BulkUsb_DbgPrint(3, ("IRP_MN_WAIT_WAKE::")); BulkUsb_IoDecrement(deviceExtension); break; case IRP_MN_POWER_SEQUENCE: // // A driver sends this IRP as an optimization to determine // whether its device actually entered a specific power state. // This IRP is optional. Power Manager cannot send this IRP. // default: PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); if(!NT_SUCCESS(ntStatus)) { BulkUsb_DbgPrint(1, ("Lower drivers failed this Irp")); } BulkUsb_DbgPrint(3, ("BulkUsb_DispatchPower::")); BulkUsb_IoDecrement(deviceExtension); break; } return ntStatus; }
NTSTATUS HandleDeviceQueryPower( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++ Routine Description: This routine services irps of minor type IRP_MN_QUERY_POWER for the device power state Arguments: DeviceObject - pointer to device object Irp - I/O request packet sent by the power manager Return Value: NT status value --*/ { NTSTATUS ntStatus; PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; DEVICE_POWER_STATE deviceState; BulkUsb_DbgPrint(3, ("HandleDeviceQueryPower - begins\n")); // // initialize variables // deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(Irp); deviceState = irpStack->Parameters.Power.State.DeviceState; BulkUsb_DbgPrint(3, ("Query for device power state D%X\n" "Current device power state D%X\n", deviceState - 1, deviceExtension->DevPower - 1)); if(deviceExtension->WaitWakeEnable && deviceState > deviceExtension->DeviceCapabilities.DeviceWake) { PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); BulkUsb_DbgPrint(3, ("HandleDeviceQueryPower::")); BulkUsb_IoDecrement(deviceExtension); return ntStatus; } if(deviceState < deviceExtension->DevPower) { ntStatus = STATUS_SUCCESS; } else { ntStatus = HoldIoRequests(DeviceObject, Irp); if(STATUS_PENDING == ntStatus) { return ntStatus; } } // // on error complete the Irp. // on success pass it to the lower layers // PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = ntStatus; Irp->IoStatus.Information = 0; if(!NT_SUCCESS(ntStatus)) { IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { IoSkipCurrentIrpStackLocation(Irp); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); } BulkUsb_DbgPrint(3, ("HandleDeviceQueryPower::")); BulkUsb_IoDecrement(deviceExtension); BulkUsb_DbgPrint(3, ("HandleDeviceQueryPower - ends\n")); return ntStatus; }
NTSTATUS HandleSystemQueryPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine handles the irp with minor function of type IRP_MN_QUERY_POWER for the system power states. Arguments: DeviceObject - pointer to device object Irp - I/O request packet sent by the power manager. Return Value: NT status value --*/ { NTSTATUS ntStatus; PDEVICE_EXTENSION deviceExtension; SYSTEM_POWER_STATE systemState; PIO_STACK_LOCATION irpStack; BulkUsb_DbgPrint(3, ("HandleSystemQueryPower - begins\n")); // // initialize variables // deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(Irp); systemState = irpStack->Parameters.Power.State.SystemState; BulkUsb_DbgPrint(3, ("Query for system power state S%X\n" "Current system power state S%X\n", systemState - 1, deviceExtension->SysPower - 1)); // // Fail a query for a power state incompatible with waking up the system // if((deviceExtension->WaitWakeEnable) && (systemState > deviceExtension->DeviceCapabilities.SystemWake)) { BulkUsb_DbgPrint(1, ("Query for an incompatible system power state\n")); PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); BulkUsb_DbgPrint(3, ("HandleSystemQueryPower::")); BulkUsb_IoDecrement(deviceExtension); return ntStatus; } // // if querying for a lower S-state, issue a wait-wake // if((systemState > deviceExtension->SysPower) && (deviceExtension->WaitWakeEnable)) { IssueWaitWake(deviceExtension); } IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, (PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine, deviceExtension, TRUE, TRUE, TRUE); ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp); BulkUsb_DbgPrint(3, ("HandleSystemQueryPower - ends\n")); return STATUS_PENDING; }