/*++ Copyright (c) 2000-2001 Microsoft Corporation Module Name: dispatch.c Abstract: ACPI BIOS Simulator / Generic 3rd Party Operation Region Provider Pnp / Power handler module Author(s): Vincent Geglia Michael T. Murphy Chris Burgess Environment: Kernel mode Notes: Revision History: --*/ // // General includes // #include "ntddk.h" // // Specific includes // #include "acpisim.h" #include "dispatch.h" #include "util.h" // // Private function prototypes // NTSTATUS AcpisimPnpStartDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpQueryStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpCancelStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpQueryRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpCancelRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpSurpriseRemoval ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPnpQueryCapabilities ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPowerQueryPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPowerSetPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimPowerSIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimQueryPowerDIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimSetPowerDIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); NTSTATUS AcpisimForwardIrpAndWait ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS AcpisimIssuePowerDIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); NTSTATUS AcpisimCompleteSIrp ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ); NTSTATUS AcpisimD0Completion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); VOID AcpisimInitDevPowerStateTable ( IN PDEVICE_OBJECT DeviceObject ); // // Pnp minor dispatch table // IRP_DISPATCH_TABLE PnpDispatchTable[] = { IRP_MN_START_DEVICE, "Pnp/START_DEVICE", AcpisimPnpStartDevice, IRP_MN_STOP_DEVICE, "Pnp/STOP_DEVICE", AcpisimPnpStopDevice, IRP_MN_QUERY_STOP_DEVICE, "Pnp/QUERY_STOP_DEVICE", AcpisimPnpQueryStopDevice, IRP_MN_CANCEL_STOP_DEVICE, "Pnp/CANCEL_STOP_DEVICE", AcpisimPnpCancelStopDevice, IRP_MN_REMOVE_DEVICE, "Pnp/REMOVE_DEVICE", AcpisimPnpRemoveDevice, IRP_MN_QUERY_REMOVE_DEVICE, "Pnp/QUERY_REMOVE_DEVICE", AcpisimPnpQueryRemoveDevice, IRP_MN_CANCEL_REMOVE_DEVICE,"Pnp/CANCEL_REMOVE_DEVICE", AcpisimPnpCancelRemoveDevice, IRP_MN_SURPRISE_REMOVAL, "Pnp/SURPRISE_REMOVAL", AcpisimPnpSurpriseRemoval, IRP_MN_QUERY_CAPABILITIES, "Pnp/QUERY_CAPABILITIIES", AcpisimPnpQueryCapabilities }; // // Power minor dispatch table // IRP_DISPATCH_TABLE PowerDispatchTable[] = { IRP_MN_QUERY_POWER, "Power/QUERY_POWER", AcpisimPowerQueryPower, IRP_MN_SET_POWER, "Power/SET_POWER", AcpisimPowerSetPower }; NTSTATUS AcpisimDispatchPnp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the pnp IRP handler. It checks the minor code, and passes on to the appropriate minor handler. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP processing --*/ { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG count = 0; DBG_PRINT (DBG_INFO, "Entering AcpisimDispatchPnp.\n"); while (count < sizeof (PnpDispatchTable) / sizeof (IRP_DISPATCH_TABLE)) { if (irpsp->MinorFunction == PnpDispatchTable[count].IrpFunction) { DBG_PRINT (DBG_INFO, "Recognized PnP IRP 0x%x '%s'.\n", irpsp->MinorFunction, PnpDispatchTable[count].IrpName); status = PnpDispatchTable[count].IrpHandler (DeviceObject, Irp); goto EndAcpisimDispatchPnp; } count ++; } DBG_PRINT (DBG_INFO, "Unrecognized PnP IRP 0x%x, pass it on.\n", irpsp->MinorFunction); IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (deviceextension->NextDevice, Irp); EndAcpisimDispatchPnp: DBG_PRINT (DBG_INFO, "Exiting AcpisimDispatchPnp.\n"); return status; } NTSTATUS AcpisimDispatchPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the power IRP handler. It checks the minor code, and passes on to the appropriate minor handler. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP processing --*/ { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG count = 0; DBG_PRINT (DBG_INFO, "Entering AcpisimDispatchPower.\n"); while (count < sizeof (PowerDispatchTable) / sizeof (IRP_DISPATCH_TABLE)) { if (irpsp->MinorFunction == PowerDispatchTable[count].IrpFunction) { DBG_PRINT (DBG_INFO, "Recognized Power IRP 0x%x '%s'.\n", irpsp->MinorFunction, PowerDispatchTable[count].IrpName); status = PowerDispatchTable[count].IrpHandler (DeviceObject, Irp); goto EndAcpisimDispatchPower; } count ++; } DBG_PRINT (DBG_INFO, "Unrecognized Power IRP 0x%x, pass it on.\n", irpsp->MinorFunction); PoStartNextPowerIrp (Irp); IoSkipCurrentIrpStackLocation (Irp); status = PoCallDriver (deviceextension->NextDevice, Irp); EndAcpisimDispatchPower: DBG_PRINT (DBG_INFO, "Exiting AcpisimDispatchPower.\n"); return status; } NTSTATUS AcpisimPnpStartDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Start Device handler. It enables the device interface and registers the operation region handler. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP_MN_START_DEVICE processing --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); KIRQL oldirql; DBG_PRINT (DBG_INFO, "Entering AcpisimPnpStartDevice.\n"); // // We handle this IRP on the way back up. // status = AcpisimForwardIrpAndWait (DeviceObject, Irp); ASSERT (NT_SUCCESS (status)); if ((status != STATUS_SUCCESS && status != STATUS_PENDING) || !NT_SUCCESS (Irp->IoStatus.Status)) { DBG_PRINT (DBG_ERROR, "Error processing, or lower driver failed start IRP. IoCallDriver = %lx, Irp->IoStatus.Status = %lx\n", status, Irp->IoStatus.Status); goto EndAcpisimPnpStartDevice; } // // Check to see if we are already started. If we are, // just return success since we aren't using resources // anyway. // if (deviceextension->PnpState == PNP_STATE_STARTED) { status = STATUS_SUCCESS; goto EndAcpisimPnpStartDevice; } // // Enable our device interface // status = AcpisimEnableDisableDeviceInterface (DeviceObject, TRUE); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "Error enabling device interface. Fail the start. Status = %lx.\n", status); Irp->IoStatus.Status = status; goto EndAcpisimPnpStartDevice; } AcpisimSetDevExtFlags (DeviceObject, DE_FLAG_INTERFACE_ENABLED); // // Typically, we would check the state of our hardware, and // set our internal power state to reflect the current state // of the hardware. However, in this case we are a virtual // device, and it is safe to assume we are in D0 when we // receive IRP_MN_START_DEVICE. // AcpisimUpdatePowerState (DeviceObject, POWER_STATE_WORKING); AcpisimUpdateDevicePowerState (DeviceObject, PowerDeviceD0); // // Finally, we can register our operation region handler. // status = AcpisimRegisterOpRegionHandler (DeviceObject); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "Couldn't register op region handler (%lx). Fail start IRP.\n", status); goto EndAcpisimPnpStartDevice; } AcpisimSetDevExtFlags (DeviceObject, DE_FLAG_OPREGION_REGISTERED); EndAcpisimPnpStartDevice: // // If we completed the start successfully, change our pnp state // to PNP_STARTED // if (NT_SUCCESS (status)) { AcpisimUpdatePnpState (DeviceObject, PNP_STATE_STARTED); } else { AcpisimUpdatePnpState (DeviceObject, PNP_STATE_STOPPED); } // // Because we are handling this IRP "on the way up", we need // to complete it when we are done working with it. // IoCompleteRequest (Irp, IO_NO_INCREMENT); DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpStartDevice.\n"); return status; } NTSTATUS AcpisimPnpStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Stop Device handler. It checks to see if there are any outstanding requests, and fails the stop IRP if there are. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP_MN_STOP_DEVICE processing --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); DBG_PRINT (DBG_INFO, "Entering AcpisimPnpStopDevice.\n"); // // BUGBUG - We currently don't handle the case where // there is still an outstanding request at stop // time. If we were to do things correctly, we'd // complete any outstanding requests in the driver // with an appropriate error code. In this // particular case, if a request happened to squeak // by our check at QUERY STOP time, it is likely // the request would not be completed at all. // // // Oh, and we had better not have LESS then 2 count // or we've got a bug somewhere. // if (deviceextension->OutstandingIrpCount < 2) { DBG_PRINT (DBG_WARN, "Possible internal consistency error - OutstandingIrpCount too low.\n"); } ASSERT (deviceextension->OutstandingIrpCount == 2); IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; status = IoCallDriver (deviceextension->NextDevice, Irp); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "IRP_MN_STOP forwarding failed (%lx).\n", status); goto EndAcpisimPnpStopDevice; } AcpisimUpdatePnpState (DeviceObject, PNP_STATE_STOPPED); EndAcpisimPnpStopDevice: DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpStopDevice.\n"); return status; } NTSTATUS AcpisimPnpQueryStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Query Stop Device handler. If there are any outstanding requests, it vetos the IRP. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP_MN_QUERY_STOP_DEVICE processing --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); DBG_PRINT (DBG_INFO, "Entering AcpisimPnpQueryStopDevice.\n"); // // Let existing IRPs in the driver complete before we say OK. // But to do this, we need to get the OutstandingIrpsCount // right. Subtract 2 since we are biased to 1, and we have an // additional 1 for the QUERY_STOP IRP. // AcpisimDecrementIrpCount (DeviceObject); AcpisimDecrementIrpCount (DeviceObject); status = KeWaitForSingleObject (&deviceextension->IrpsCompleted, Executive, KernelMode, FALSE, 0); InterlockedIncrement (&deviceextension->OutstandingIrpCount); InterlockedIncrement (&deviceextension->OutstandingIrpCount); KeResetEvent (&deviceextension->IrpsCompleted); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "KeWaitForSingleObject failed (%lx). IRP_MN_QUERY_STOP failed.\n", status); IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; status = IoCallDriver (deviceextension->NextDevice, Irp); ASSERT (NT_SUCCESS (status)); goto EndPnpQueryStopDevice; } // // We can stop - change our state to stopping, and pass it on. // IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; status = IoCallDriver (deviceextension->NextDevice, Irp); AcpisimUpdatePnpState (DeviceObject, PNP_STATE_STOP_PENDING); EndPnpQueryStopDevice: DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpQueryStopDevice.\n"); return status; } NTSTATUS AcpisimPnpCancelStopDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Cancel Stop Device handler. It does nothing more then returns the pnp state to started. This is a virtual device so there is no work to do. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: STATUS_SUCCESS --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; DBG_PRINT (DBG_INFO, "Entering AcpisimPnpCancelStopDevice.\n"); status = AcpisimForwardIrpAndWait (DeviceObject, Irp); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "IRP_MN_CANCEL_STOP forwarding failed (%lx).\n", status); goto EndPnpCancelStopDevice; } status = STATUS_SUCCESS; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, 0); AcpisimUpdatePnpState (DeviceObject, PNP_STATE_STARTED); EndPnpCancelStopDevice: DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpCancelStopDevice.\n"); return status; } NTSTATUS AcpisimPnpRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Remove Device handler. It de-registers the operation region handler, detaches the device object, and deletes it if all goes well. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: status of removal operation --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); PDEVICE_OBJECT nextdevice = deviceextension->NextDevice; DBG_PRINT (DBG_INFO, "Entering AcpisimPnpRemoveDevice.\n"); // // BUGBUG - We currently don't handle the case where // there is still an outstanding request at remove // time. If we were to do things correctly, we'd // complete any outstanding requests in the driver // with an appropriate error code. In this // particular case, if a request happened to squeak // by our check at QUERY REMOVE time, it is likely // the request would not be completed at all. // // // Our OutstandingIrpCount logic is biased to 1. So // if we are processing a remove IRP, and there are // no other requests in the driver, OustandingIrpCount // had better be 2. if (deviceextension->OutstandingIrpCount < 2) { DBG_PRINT (DBG_WARN, "Possible internal consistency error - OutstandingIrpCount too low.\n"); } ASSERT (deviceextension->OutstandingIrpCount == 2); // // Ok, we are ready to remove the device. Shut down the // interface, deregister the opregion handler, and // delete the device object. // status = AcpisimEnableDisableDeviceInterface (DeviceObject, FALSE); ASSERT (NT_SUCCESS (status)); if (NT_SUCCESS (status)) { AcpisimClearDevExtFlags (DeviceObject, DE_FLAG_INTERFACE_ENABLED); } status = AcpisimUnRegisterOpRegionHandler (DeviceObject); ASSERT (NT_SUCCESS (status)); if (NT_SUCCESS (status)) { AcpisimClearDevExtFlags (DeviceObject, DE_FLAG_OPREGION_REGISTERED); } RtlFreeUnicodeString (&deviceextension->InterfaceString); IoDetachDevice (deviceextension->NextDevice); IoDeleteDevice (DeviceObject); // // Now, pass it on... // IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; status = IoCallDriver (nextdevice, Irp); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "Passing remove IRP onto next driver failed for some reason (%lx).\n", status); } DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpRemoveDevice.\n"); return status; } NTSTATUS AcpisimPnpQueryRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Query Remove Device handler. It waits for existing requests in the driver to finish, and then completes the IRP successfully. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: Status of query remove device operation --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); DBG_PRINT (DBG_INFO, "Entering AcpisimPnpQueryRemoveDevice.\n"); // // Make sure our state is correct // ASSERT (deviceextension->OutstandingIrpCount >= 2); // // Let existing IRPs in the driver complete before we say OK. // But to do this, we need to get the OutstandingIrpsCount // right. Subtract 2 since we are biased to 1, and we have an // additional 1 for the QUERY_STOP IRP. // AcpisimDecrementIrpCount (DeviceObject); AcpisimDecrementIrpCount (DeviceObject); status = KeWaitForSingleObject (&deviceextension->IrpsCompleted, Executive, KernelMode, FALSE, 0); InterlockedIncrement (&deviceextension->OutstandingIrpCount); InterlockedIncrement (&deviceextension->OutstandingIrpCount); KeResetEvent (&deviceextension->IrpsCompleted); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "KeWaitForSingleObject failed (%lx). IRP_MN_QUERY_REMOVE failed.\n", status); IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; status = IoCallDriver (deviceextension->NextDevice, Irp); ASSERT (NT_SUCCESS (status)); goto EndPnpQueryRemoveDevice; } // // We can remove - change our state to remove pending, and pass it on. // IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; status = IoCallDriver (deviceextension->NextDevice, Irp); AcpisimUpdatePnpState (DeviceObject, PNP_STATE_REMOVE_PENDING); EndPnpQueryRemoveDevice: DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpQueryRemoveDevice.\n"); return status; } NTSTATUS AcpisimPnpCancelRemoveDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Cancel Remove Device handler. It does nothing more then returns the pnp state to started. This is a virtual device so there is no work to do. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: STATUS_SUCCESS --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; DBG_PRINT (DBG_INFO, "Entering AcpisimPnpCancelRemoveDevice.\n"); status = AcpisimForwardIrpAndWait (DeviceObject, Irp); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "IRP_MN_CANCEL_REMOVE forwarding failed (%lx).\n", status); goto EndPnpCancelRemoveDevice; } status = STATUS_SUCCESS; Irp->IoStatus.Status = status; IoCompleteRequest (Irp, 0); AcpisimUpdatePnpState (DeviceObject, PNP_STATE_STARTED); EndPnpCancelRemoveDevice: DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpCancelRemoveDevice.\n"); return status; } NTSTATUS AcpisimPnpSurpriseRemoval ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Pnp Surprise Remove handler. It basically updates the state, and passes the IRP on. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: STATUS_SUCCESS --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); DBG_PRINT (DBG_INFO, "Entering AcpisimPnpSurpriseRemoval.\n"); // // Again, because we are a virtual device, handling // surprise remove is really a no-op. Just update // our state, and succeed the IRP. // AcpisimUpdatePnpState (DeviceObject, PNP_STATE_SURPRISE_REMOVAL); IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = STATUS_SUCCESS; status = IoCallDriver (deviceextension->NextDevice, Irp); ASSERT (NT_SUCCESS (status)); DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpSurpriseRemoval.\n"); return status; } NTSTATUS AcpisimPnpQueryCapabilities ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine handles IRP_MN_QUERY_CAPABILITIES. We need this information to build our power state table correctly. All we do here is set a completion routine, as we need to gather this data after the PDO has filled out DeviceState. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: Status of operation --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); PIO_STACK_LOCATION irpsp; UCHAR count = 0; DBG_PRINT (DBG_INFO, "Entering AcpisimPnpQueryCapabilities.\n"); // // Fill out the power mapping table with a default // AcpisimInitDevPowerStateTable (DeviceObject); // // Handle this IRP after the PDO has filled out the structure // status = AcpisimForwardIrpAndWait (DeviceObject, Irp); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "Somebody failed the QUERY_CAPABILITIES IRP...\n"); goto EndAcpisimPnpQueryCapabilities; } irpsp = IoGetCurrentIrpStackLocation (Irp); // // Update our power mappings with what we found in the device // capabilities structure. We only use valid mappings, e.g. // PowerDeviceUnspecified is ignored. // DBG_PRINT (DBG_INFO, "Device mappings:\n"); for (count = 0; count < 6; count ++) { if (irpsp->Parameters.DeviceCapabilities.Capabilities->DeviceState[count + 1] != PowerDeviceUnspecified) { deviceextension->PowerMappings[count] = irpsp->Parameters.DeviceCapabilities.Capabilities->DeviceState [count + 1]; } DBG_PRINT (DBG_INFO, "S%d --> D%d\n", count, deviceextension->PowerMappings[count] - 1); } status = STATUS_SUCCESS; Irp->IoStatus.Status = status; EndAcpisimPnpQueryCapabilities: IoCompleteRequest (Irp, IO_NO_INCREMENT); DBG_PRINT (DBG_INFO, "Exiting AcpisimPnpQueryCapabilities.\n"); return status; } NTSTATUS AcpisimPowerQueryPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the QUERY Power handler. It determines if the power IRP is an S or D IRP, and passes it on to the proper handler. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: Status returned from power handler --*/ { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); NTSTATUS status = STATUS_UNSUCCESSFUL; DBG_PRINT (DBG_INFO, "Entering AcpisimPowerQueryPower.\n"); switch (irpsp->Parameters.Power.Type) { case SystemPowerState: status = AcpisimPowerSIrp (DeviceObject, Irp); break; case DevicePowerState: status = AcpisimQueryPowerDIrp (DeviceObject, Irp); break; default: DBG_PRINT (DBG_ERROR, "Undefined QUERY Power IRP type. Ignoring.\n"); IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (deviceextension->NextDevice, Irp); } DBG_PRINT (DBG_INFO, "Exiting AcpisimPowerQueryPower.\n"); return status; } NTSTATUS AcpisimPowerSetPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the SET Power handler. It determines if the power IRP is an S or D IRP, and passes it on to the proper handler. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: Status returned from power handler --*/ { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); NTSTATUS status = STATUS_UNSUCCESSFUL; DBG_PRINT (DBG_INFO, "Entering AcpisimPowerSetPower.\n"); switch (irpsp->Parameters.Power.Type) { case SystemPowerState: status = AcpisimPowerSIrp (DeviceObject, Irp); break; case DevicePowerState: status = AcpisimSetPowerDIrp (DeviceObject, Irp); break; default: DBG_PRINT (DBG_ERROR, "Undefined SET Power IRP type. Ignoring.\n"); IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (deviceextension->NextDevice, Irp); } DBG_PRINT (DBG_INFO, "Exiting AcpisimPowerSetPower.\n"); return status; } NTSTATUS AcpisimPowerSIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the power handler for S IRPs. It sets a completion routine, which will queue a D IRP. We don't do anything unless it is a D IRP. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: Status returned from power handler --*/ { PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); DBG_PRINT (DBG_INFO, "Entering AcpisimPowerSIrp.\n"); IoMarkIrpPending (Irp); IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, AcpisimIssuePowerDIrp, 0, TRUE, TRUE, TRUE); PoCallDriver (deviceextension->NextDevice, Irp); DBG_PRINT (DBG_INFO, "Exiting AcpisimPowerSIrp.\n"); return STATUS_PENDING; } NTSTATUS AcpisimQueryPowerDIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the QUERY Power DIrp handler. Validate the state, and say yes. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: Status returned from power handler --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); DBG_PRINT (DBG_INFO, "Entering AcpisimQueryPowerDIrp.\n"); // // Here, we are supposed to figure out if we can go to the // power state specified by the IRP. Since we are a virtual // device, we don't have a good reason to not go to a different // power state. Update our state, and wait to complete requests. // AcpisimDecrementIrpCount (DeviceObject); AcpisimDecrementIrpCount (DeviceObject); AcpisimDecrementIrpCount (DeviceObject); status = KeWaitForSingleObject (&deviceextension->IrpsCompleted, Executive, KernelMode, FALSE, 0); InterlockedIncrement (&deviceextension->OutstandingIrpCount); InterlockedIncrement (&deviceextension->OutstandingIrpCount); KeResetEvent (&deviceextension->IrpsCompleted); ASSERT (NT_SUCCESS (status)); // // Validate the D IRP // switch (irpsp->Parameters.Power.State.DeviceState) { case PowerDeviceD0: case PowerDeviceD1: case PowerDeviceD2: case PowerDeviceD3: AcpisimUpdatePowerState (DeviceObject, POWER_STATE_POWER_PENDING); status = STATUS_SUCCESS; break; default: ASSERT (0); DBG_PRINT (DBG_ERROR, "AcpisimQueryPowerDIrp: Illegal or unknown PowerDeviceState. Failing.\n"); status = STATUS_INVALID_DEVICE_REQUEST; } PoStartNextPowerIrp (Irp); IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = status; status = PoCallDriver (deviceextension->NextDevice, Irp); ASSERT (NT_SUCCESS (status)); DBG_PRINT (DBG_INFO, "Leaving AcpisimQueryPowerDIrp.\n"); return status; } NTSTATUS AcpisimSetPowerDIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); POWER_STATE powerstate; DBG_PRINT (DBG_INFO, "Entering AcpisimSetPowerDIrp.\n"); // // Validate the D IRP // switch (irpsp->Parameters.Power.State.DeviceState) { // // For D0, if we are powered down, we need to pass the IRP down, and // set a completion routine. We need the PDO to succeed the power // up before we do. // case PowerDeviceD0: if (deviceextension->PowerState != POWER_STATE_WORKING) { IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, AcpisimD0Completion, 0, TRUE, TRUE, TRUE); IoMarkIrpPending (Irp); PoCallDriver (deviceextension->NextDevice, Irp); status = STATUS_PENDING; goto EndAcpisimSetPowerDIrp; } break; case PowerDeviceD1: powerstate.DeviceState = PowerDeviceD1; PoSetPowerState (DeviceObject, DevicePowerState, powerstate); AcpisimUpdatePowerState (DeviceObject, POWER_STATE_POWERED_DOWN); AcpisimUpdateDevicePowerState (DeviceObject, irpsp->Parameters.Power.State.DeviceState); status = STATUS_SUCCESS; break; case PowerDeviceD2: powerstate.DeviceState = PowerDeviceD2; PoSetPowerState (DeviceObject, DevicePowerState, powerstate); AcpisimUpdatePowerState (DeviceObject, POWER_STATE_POWERED_DOWN); AcpisimUpdateDevicePowerState (DeviceObject, irpsp->Parameters.Power.State.DeviceState); status = STATUS_SUCCESS; break; case PowerDeviceD3: powerstate.DeviceState = PowerDeviceD3; PoSetPowerState (DeviceObject, DevicePowerState, powerstate); AcpisimUpdatePowerState (DeviceObject, POWER_STATE_POWERED_DOWN); AcpisimUpdateDevicePowerState (DeviceObject, irpsp->Parameters.Power.State.DeviceState); status = STATUS_SUCCESS; break; default: ASSERT (0); DBG_PRINT (DBG_ERROR, "AcpisimSetPowerDIrp: Illegal or unknown PowerDeviceState. Failing.\n"); status = STATUS_INVALID_DEVICE_REQUEST; } PoStartNextPowerIrp (Irp); IoSkipCurrentIrpStackLocation (Irp); Irp->IoStatus.Status = status; status = PoCallDriver (deviceextension->NextDevice, Irp); ASSERT (NT_SUCCESS (status)); EndAcpisimSetPowerDIrp: DBG_PRINT (DBG_INFO, "Leaving AcpisimSetPowerDIrp.\n"); return status; } NTSTATUS AcpisimCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This is the generic Irp completion routine for when we want to wait for an IRP to be completed by the PDO and do post-completion work. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Context - Context passed in by IoSetCompletionRoutine. Return Value: STATUS_MORE_PROCESSING_REQUIRED --*/ { DBG_PRINT (DBG_INFO, "Entering AcpisimCompletionRoutine.\n"); KeSetEvent (Context, 0, FALSE); DBG_PRINT (DBG_INFO, "Exiting AcpisimCompletionRoutine.\n"); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS AcpisimForwardIrpAndWait ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This forwards the IRP down the device stack, sets a completion routine, and waits on the completion event. Useful for doing IRP post-completion, based on the result of the completion. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: The status set in the IRP when the IRP was completed. --*/ { KEVENT context; NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); DBG_PRINT (DBG_INFO, "Entering AcpisimForwardIrpAndWait.\n"); KeInitializeEvent (&context, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, AcpisimCompletionRoutine, &context, TRUE, TRUE, TRUE); status = IoCallDriver (deviceextension->NextDevice, Irp); if (status == STATUS_PENDING) { KeWaitForSingleObject (&context, Executive, KernelMode, FALSE, NULL); status = Irp->IoStatus.Status; } DBG_PRINT (DBG_INFO, "Exiting AcpisimForwardIrpAndWait.\n"); return status; } NTSTATUS AcpisimIssuePowerDIrp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This is the S-IRP completion routine. It examines the completed IRP, and if there are no problems, asks the power manager to send us the appropriate D-IRP. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Context - Context passed into IoSetCompletionRoutine Return Value: Status of requesting D-IRP operation. --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); POWER_STATE powerstate; PPOWER_CONTEXT context = NULL; DBG_PRINT (DBG_INFO, "Entering AcpisimIssuePowerDIrp.\n"); powerstate.DeviceState = PowerDeviceUnspecified; // // Make sure this IRP wasn't failed by the PDO or Lower FFDO // if (!NT_SUCCESS (Irp->IoStatus.Status)) { DBG_PRINT (DBG_INFO, "AcpisimIssuePowerDIrp: Lower FFDO, BFDO, or PDO failed this IRP (%lx).\n", status); status = Irp->IoStatus.Status; goto EndAcpisimIssuePowerDIrp; } if (NT_SUCCESS (Irp->IoStatus.Status)) { // // Ok, everybody is agreeing to this S state. Send ourselves // the appropriate D IRP. // // // Make sure this is an S Irp // ASSERT (irpsp->Parameters.Power.Type == SystemPowerState); if (irpsp->Parameters.Power.Type != SystemPowerState) { DBG_PRINT (DBG_ERROR, "Didn't recieve an S Irp when we expected to, or somebody messed up the IRP. Fail it.\n"); status = STATUS_INVALID_DEVICE_REQUEST; goto EndAcpisimIssuePowerDIrp; } ASSERT (irpsp->MinorFunction == IRP_MN_QUERY_POWER || irpsp->MinorFunction == IRP_MN_SET_POWER); if (irpsp->MinorFunction != IRP_MN_QUERY_POWER && irpsp->MinorFunction != IRP_MN_SET_POWER) { DBG_PRINT (DBG_ERROR, "Irp isn't SET or QUERY. Not sure why this wasn't caught earlier (somebody probably messed it up).\nWe don't support any other type. Fail it.\n"); status = STATUS_INVALID_DEVICE_REQUEST; goto EndAcpisimIssuePowerDIrp; } // // Make sure the S IRP is valid // if (irpsp->Parameters.Power.State.SystemState >= PowerSystemMaximum) { ASSERT (0); DBG_PRINT (DBG_ERROR, "Received an undefined S IRP, or somebody messed up the IRP. Fail it.\n"); status = STATUS_INVALID_DEVICE_REQUEST; goto EndAcpisimIssuePowerDIrp; } // // Use our power mapping table to convert S-->D state // powerstate.DeviceState = deviceextension->PowerMappings [irpsp->Parameters.Power.State.SystemState - 1]; DBG_PRINT (DBG_INFO, "S%d --> D%d\n", irpsp->Parameters.Power.State.SystemState - 1, powerstate.DeviceState - 1); // // We need a context to pass a pointer to the S IRP to the D IRP handler // and a pointer to the device object. // context = ExAllocatePoolWithTag (NonPagedPool, sizeof (POWER_CONTEXT)+4, POWER_CONTEXT_TAG); if (!context) { DBG_PRINT (DBG_ERROR, "Unable to allocate memory for the context.\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto EndAcpisimIssuePowerDIrp; } context->SIrp = Irp; context->Context = DeviceObject; // // Send the D Irp // status = PoRequestPowerIrp (deviceextension->Pdo, irpsp->MinorFunction, powerstate, AcpisimCompleteSIrp, context, NULL); ASSERT (NT_SUCCESS (status)); if (!NT_SUCCESS (status)) { DBG_PRINT (DBG_ERROR, "AcpisimIssuePowerDIrp: PoRequestPowerIrp failed (%lx).\n"); goto EndAcpisimIssuePowerDIrp; } } status = STATUS_MORE_PROCESSING_REQUIRED; EndAcpisimIssuePowerDIrp: // // We need to complete the request if something went wrong. Also note, // it is not necessary to assume our state is S0/D0 again. The power // manager will send us an S0 IRP. // if (!NT_SUCCESS (status) && status != STATUS_MORE_PROCESSING_REQUIRED) { DBG_PRINT (DBG_ERROR, "AcpisimIssuePowerDIrp: Something bad happened. Just complete the S Irp with an error."); PoStartNextPowerIrp (Irp); Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); IoReleaseRemoveLock (&deviceextension->RemoveLock, Irp); AcpisimDecrementIrpCount (DeviceObject); if (context) { ExFreePool (context); } } DBG_PRINT (DBG_INFO, "Exiting AcpisimIssuePowerDIrp.\n"); return status; } NTSTATUS AcpisimCompleteSIrp ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) /*++ Routine Description: This is the S-Irp completion routine set by PoRequestPowerIrp. Arguments: DeviceObject - pointer to the FDO MinorFunction - type of request PowerState - type of IRP Context - Context passed into PoRequestPowerIrp IoStatus - IoStatus block of completed D Irp Return Value: STATUS_SUCCESS --*/ { PPOWER_CONTEXT context = (PPOWER_CONTEXT) Context; PDEVICE_OBJECT deviceobject = context->Context; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (deviceobject); PIRP sirp = context->SIrp; DBG_PRINT (DBG_INFO, "Entering AcpisimCompleteSIrp.\n"); // // Propagate the device power IRP's status in the system power IRP // sirp->IoStatus.Status = IoStatus->Status; // // Tell the power manager we are done with this IRP // PoStartNextPowerIrp (sirp); IoCompleteRequest (sirp, IO_NO_INCREMENT); IoReleaseRemoveLock (&deviceextension->RemoveLock, sirp); ExFreePool (Context); // // Normally our dispatch routine decrements IRP counts, // but since it was returned STATUS_PENDING, it wasn't // decremented earlier // AcpisimDecrementIrpCount (deviceobject); DBG_PRINT (DBG_INFO, "Exiting AcpisimCompleteSIrp.\n"); return STATUS_SUCCESS; } NTSTATUS AcpisimD0Completion ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: This is the D0 Irp completion routine Arguments: DeviceObject - pointer to the FDO MinorFunction - type of request Context - Context passed into IoSetCompletionRoutine Return Value: Error status or STATUS_MORE_PROCESSING_REQUIRED --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); POWER_STATE powerstate; DBG_PRINT (DBG_INFO, "Entering AcpisimD0Completion.\n"); // // Make sure this IRP wasn't failed by the PDO or Lower FFDO // if (!NT_SUCCESS (Irp->IoStatus.Status)) { DBG_PRINT (DBG_INFO, "AcpisimD0Completion: Lower FFDO, BFDO, or PDO failed this IRP (%lx).\n", status); status = Irp->IoStatus.Status; goto EndAcpisimD0Completion; } // // This is where we do actual D0 transition work. Since this // is a virtual device, the only thing we do is change our // internal state. // AcpisimUpdatePowerState (DeviceObject, POWER_STATE_WORKING); AcpisimUpdateDevicePowerState (DeviceObject, irpsp->Parameters.Power.State.DeviceState); powerstate.DeviceState = PowerDeviceD0; PoSetPowerState (DeviceObject, DevicePowerState, powerstate); status = STATUS_MORE_PROCESSING_REQUIRED; EndAcpisimD0Completion: PoStartNextPowerIrp (Irp); IoCompleteRequest (Irp, IO_NO_INCREMENT); IoReleaseRemoveLock (&deviceextension->RemoveLock, Irp); AcpisimDecrementIrpCount (DeviceObject); DBG_PRINT (DBG_INFO, "Exiting AcpisimD0Completion.\n"); return status; } VOID AcpisimInitDevPowerStateTable ( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine fills out the power mapping structure with defaults. We simply default to using D3 in any non-S0 state. Arguments: DeviceObject - pointer to the FDO Return Value: None --*/ { PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); UCHAR count; deviceextension->PowerMappings[0] = PowerDeviceD0; for (count = 1; count < 5; count ++) { deviceextension->PowerMappings[count] = PowerDeviceD3; } } NTSTATUS AcpisimDispatchIoctl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the handler for IOCTL requests. We just call the supplied function to handle the IOCTL, or pass it on if the handler doesn't handle it. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP processing --*/ { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); NTSTATUS status = STATUS_UNSUCCESSFUL; ULONG count = 0; DBG_PRINT (DBG_INFO, "Entering AcpisimDispatchIoctl\n"); status = AcpisimHandleIoctl (DeviceObject, Irp); if (status == STATUS_NOT_SUPPORTED) { // // IOCTL wasn't handled, pass it on... // IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (AcpisimLibGetNextDevice (DeviceObject), Irp); } else { // // IOCTL was handled, complete it. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); } DBG_PRINT (DBG_INFO, "Exiting AcpisimDispatchIoctl\n"); return status; } NTSTATUS AcpisimDispatchSystemControl ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the handler for System Control requests. Since we currently don't support any System Control calls, we are just going to pass them on to the next driver. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IoCallDriver --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; DBG_PRINT (DBG_INFO, "Entering AcpisimDispatchSystemControl\n"); IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (AcpisimLibGetNextDevice (DeviceObject), Irp); DBG_PRINT (DBG_INFO, "Exiting AcpisimDispatchSystemControl\n"); return status; } NTSTATUS AcpisimCreateClose ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the handler for CreateFile and CloseHandle requests. We do nothing except update our internal extension to track the number of outstanding handles. Arguments: DeviceObject - pointer to the device object the IRP pertains to Irp - pointer to the IRP Return Value: result of IRP processing --*/ { NTSTATUS status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (Irp); PDEVICE_EXTENSION deviceextension = AcpisimGetDeviceExtension (DeviceObject); ASSERT (irpsp->MajorFunction == IRP_MJ_CREATE || irpsp->MajorFunction == IRP_MJ_CLOSE); switch (irpsp->MajorFunction) { case IRP_MJ_CREATE: InterlockedIncrement (&deviceextension->HandleCount); status = STATUS_SUCCESS; break; case IRP_MJ_CLOSE: InterlockedDecrement (&deviceextension->HandleCount); status = STATUS_SUCCESS; break; default: DBG_PRINT (DBG_ERROR, "AcpisimCreateClose - unexpected Irp type.\n"); status = STATUS_INVALID_DEVICE_REQUEST; break; } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, 0); return STATUS_SUCCESS; }