VBoxGuest-win-pnp.cpp revision a57b3586d0f1a87e0024e318f3c8dad382113611
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/* $Id$ */
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * VBoxGuest-win-pnp - Windows Plug'n'Play specifics.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync */
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/*
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2010-2013 Oracle Corporation
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync *
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * available from http://www.virtualbox.org. This file is free software;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include "VBoxGuest-win.h"
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include "VBoxGuestInternal.h"
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <VBox/err.h>
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <VBox/log.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <VBox/version.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <VBox/VBoxGuestLib.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/*******************************************************************************
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync* Defined Constants And Macros *
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync*******************************************************************************/
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncRT_C_DECLS_BEGIN
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncstatic NTSTATUS vbgdNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncstatic NTSTATUS vbgdNtPnPIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncstatic VOID vbgdNtShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncRT_C_DECLS_END
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync#ifdef ALLOC_PRAGMA
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync# pragma alloc_text(PAGE, vbgdNtPnP)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync# pragma alloc_text(PAGE, vbgdNtPower)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync# pragma alloc_text(PAGE, vbgdNtSendIrpSynchronously)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync# pragma alloc_text(PAGE, vbgdNtShowDeviceResources)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync#endif
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/**
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * Irp completion routine for PnP Irps we send.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync *
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param pDevObj Device object.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param pIrp Request packet.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param event Semaphore.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @return NT status code
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync */
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncstatic NTSTATUS vbgdNtPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync{
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync KeSetEvent(pEvent, 0, FALSE);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync return STATUS_MORE_PROCESSING_REQUIRED;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync}
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/**
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * Helper to send a PnP IRP and wait until it's done.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync *
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param pDevObj Device object.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param pIrp Request packet.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param fStrict When set, returns an error if the IRP gives an error.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @return NT status code
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync */
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncstatic NTSTATUS vbgdNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync{
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync KEVENT Event;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync IoCopyCurrentIrpStackLocationToNext(pIrp);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vbgdNtPnpIrpComplete,
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync &Event, TRUE, TRUE, TRUE);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync NTSTATUS rc = IoCallDriver(pDevObj, pIrp);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync if (rc == STATUS_PENDING)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync {
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync rc = pIrp->IoStatus.Status;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync }
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync if (!fStrict
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync && (rc == STATUS_NOT_SUPPORTED || rc == STATUS_INVALID_DEVICE_REQUEST))
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync {
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync rc = STATUS_SUCCESS;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync }
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync Log(("VBoxGuest::vbgdNtSendIrpSynchronously: Returning 0x%x\n", rc));
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync return rc;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync}
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync/**
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * PnP Request handler.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync *
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param pDevObj Device object.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync * @param pIrp Request packet.
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync */
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsyncNTSTATUS vbgdNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync{
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync#ifdef LOG_ENABLED
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync static char *s_apszFnctName[] =
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync {
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_START_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_REMOVE_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_REMOVE_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_CANCEL_REMOVE_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_STOP_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_STOP_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_CANCEL_STOP_DEVICE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_DEVICE_RELATIONS",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_INTERFACE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_CAPABILITIES",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_RESOURCES",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_DEVICE_TEXT",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_0xE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_READ_CONFIG",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_WRITE_CONFIG",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_EJECT",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_SET_LOCK",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_ID",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_PNP_DEVICE_STATE",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_QUERY_BUS_INFORMATION",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_DEVICE_USAGE_NOTIFICATION",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync "IRP_MN_SURPRISE_REMOVAL",
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync };
67c26773eca4a576449ffa8f289fa344fc7b8176vboxsync Log(("VBoxGuest::vbgdNtGuestPnp: MinorFunction: %s\n",
pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName)) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
#endif
NTSTATUS rc = STATUS_SUCCESS;
switch (pStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE\n"));
/* This must be handled first by the lower driver. */
rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
if ( NT_SUCCESS(rc)
&& NT_SUCCESS(pIrp->IoStatus.Status))
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
pStack->Parameters.StartDevice.AllocatedResources));
if (!pStack->Parameters.StartDevice.AllocatedResources)
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
pDevExt, pDevExt ? pDevExt->win.s.pNextLowerDriver : NULL));
rc = STATUS_UNSUCCESSFUL;
}
else
{
rc = vbgdNtInit(pDevObj, pIrp);
}
}
if (NT_ERROR(rc))
{
Log(("VBoxGuest::vbgdNtGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc));
/* Need to unmap memory in case of errors ... */
vbgdNtUnmapVMMDevMemory(pDevExt);
}
break;
}
case IRP_MN_CANCEL_REMOVE_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
/* This must be handled first by the lower driver. */
rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGREMOVE)
{
/* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
}
/* Complete the IRP. */
break;
}
case IRP_MN_SURPRISE_REMOVAL:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED);
/* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE.
* This request is not expected for VBoxGuest.
*/
LogRel(("VBoxGuest: unexpected device removal\n"));
/* Pass to the lower driver. */
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
/* Do not complete the IRP. */
return rc;
}
case IRP_MN_QUERY_REMOVE_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
#ifdef VBOX_REBOOT_ON_UNINSTALL
Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
rc = STATUS_UNSUCCESSFUL;
#endif
if (NT_SUCCESS(rc))
{
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGREMOVE);
/* This IRP passed down to lower driver. */
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
/* we must not do anything the IRP after doing IoSkip & CallDriver
* since the driver below us will complete (or already have completed) the IRP.
* I.e. just return the status we got from IoCallDriver */
return rc;
}
/* Complete the IRP on failure. */
break;
}
case IRP_MN_REMOVE_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: REMOVE_DEVICE\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED);
/* Free hardware resources. */
/* @todo this should actually free I/O ports, interrupts, etc. */
rc = vbgdNtCleanup(pDevObj);
Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup rc = 0x%08X\n", rc));
/*
* We need to send the remove down the stack before we detach,
* but we don't need to wait for the completion of this operation
* (and to register a completion routine).
*/
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
IoDetachDevice(pDevExt->win.s.pNextLowerDriver);
Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
/* Destroy device extension and clean up everything else. */
VBoxGuestDeleteDevExt(pDevExt);
/* Remove DOS device + symbolic link. */
UNICODE_STRING win32Name;
RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
IoDeleteSymbolicLink(&win32Name);
Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
/* Last action: Delete our device! pDevObj is *not* failed
* anymore after this call! */
IoDeleteDevice(pDevObj);
Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Device removed!\n"));
/* Propagating rc from IoCallDriver. */
return rc; /* Make sure that we don't do anything below here anymore! */
}
case IRP_MN_CANCEL_STOP_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
/* This must be handled first by the lower driver. */
rc = vbgdNtSendIrpSynchronously(pDevExt->win.s.pNextLowerDriver, pIrp, TRUE);
if (NT_SUCCESS(rc) && pDevExt->win.s.devState == PENDINGSTOP)
{
/* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
pDevExt->win.s.devState = pDevExt->win.s.prevDevState;
}
/* Complete the IRP. */
break;
}
case IRP_MN_QUERY_STOP_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
#ifdef VBOX_REBOOT_ON_UNINSTALL
Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
#endif
if (NT_SUCCESS(rc))
{
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP);
/* This IRP passed down to lower driver. */
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
/* we must not do anything with the IRP after doing IoSkip & CallDriver
* since the driver below us will complete (or already have completed) the IRP.
* I.e. just return the status we got from IoCallDriver */
return rc;
}
/* Complete the IRP on failure. */
break;
}
case IRP_MN_STOP_DEVICE:
{
Log(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n"));
VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED);
/* Free hardware resources. */
/* @todo this should actually free I/O ports, interrupts, etc. */
rc = vbgdNtCleanup(pDevObj);
Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
/* Pass to the lower driver. */
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
return rc;
}
default:
{
IoSkipCurrentIrpStackLocation(pIrp);
rc = IoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
return rc;
}
}
pIrp->IoStatus.Status = rc;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
Log(("VBoxGuest::vbgdNtGuestPnp: Returning with rc = 0x%x\n", rc));
return rc;
}
/**
* Handle the power completion event.
*
* @returns NT status code.
* @param pDevObj Targetted device object.
* @param pIrp IO request packet.
* @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
*/
static NTSTATUS vbgdNtPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
{
PIO_STACK_LOCATION pIrpSp;
PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pContext;
ASSERT(pDevExt);
ASSERT(pDevExt->signature == DEVICE_EXTENSION_SIGNATURE);
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
if (pIrpSp)
{
ASSERT(pIrpSp->MajorFunction == IRP_MJ_POWER);
if (NT_SUCCESS(pIrp->IoStatus.Status))
{
switch (pIrpSp->MinorFunction)
{
case IRP_MN_SET_POWER:
switch (pIrpSp->Parameters.Power.Type)
{
case DevicePowerState:
switch (pIrpSp->Parameters.Power.State.DeviceState)
{
case PowerDeviceD0:
break;
}
break;
}
break;
}
}
}
return STATUS_SUCCESS;
}
/**
* Handle the Power requests.
*
* @returns NT status code
* @param pDevObj device object
* @param pIrp IRP
*/
NTSTATUS vbgdNtPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
POWER_STATE PowerState = pStack->Parameters.Power.State;
POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
Log(("VBoxGuest::vbgdNtGuestPower\n"));
switch (pStack->MinorFunction)
{
case IRP_MN_SET_POWER:
{
Log(("VBoxGuest::vbgdNtGuestPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
switch (enmPowerType)
{
case SystemPowerState:
{
Log(("VBoxGuest::vbgdNtGuestPower: SystemPowerState, action = %d, state = %d/%d\n",
enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
switch (enmPowerAction)
{
case PowerActionSleep:
/* System now is in a working state. */
if (PowerState.SystemState == PowerSystemWorking)
{
if ( pDevExt
&& pDevExt->win.s.LastSystemPowerAction == PowerActionHibernate)
{
Log(("VBoxGuest::vbgdNtGuestPower: Returning from hibernation!\n"));
int rc = VBoxGuestReinitDevExtAfterHibernation(pDevExt,
vbgdNtVersionToOSType(g_enmVbgdNtVer));
if (RT_FAILURE(rc))
Log(("VBoxGuest::vbgdNtGuestPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
}
}
break;
case PowerActionShutdownReset:
{
Log(("VBoxGuest::vbgdNtGuestPower: Power action reset!\n"));
/* Tell the VMM that we no longer support mouse pointer integration. */
VMMDevReqMouseStatus *pReq = NULL;
int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
VMMDevReq_SetMouseStatus);
if (RT_SUCCESS(vrc))
{
pReq->mouseFeatures = 0;
pReq->pointerXPos = 0;
pReq->pointerYPos = 0;
vrc = VbglGRPerform(&pReq->header);
if (RT_FAILURE(vrc))
{
Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
"vrc = %Rrc\n", vrc));
}
VbglGRFree(&pReq->header);
}
/* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
* power action and would assert/crash when we already cleaned up all the stuff! */
break;
}
case PowerActionShutdown:
case PowerActionShutdownOff:
{
Log(("VBoxGuest::vbgdNtGuestPower: Power action shutdown!\n"));
if (PowerState.SystemState >= PowerSystemShutdown)
{
Log(("VBoxGuest::vbgdNtGuestPower: Telling the VMMDev to close the VM ...\n"));
VMMDevPowerStateRequest *pReq = pDevExt->win.s.pPowerStateRequest;
int vrc = VERR_NOT_IMPLEMENTED;
if (pReq)
{
pReq->header.requestType = VMMDevReq_SetPowerStatus;
pReq->powerState = VMMDevPowerState_PowerOff;
vrc = VbglGRPerform(&pReq->header);
}
if (RT_FAILURE(vrc))
Log(("VBoxGuest::PowerStateRequest: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
/* No need to do cleanup here; at this point we should've been
* turned off by VMMDev already! */
}
break;
}
case PowerActionHibernate:
Log(("VBoxGuest::vbgdNtGuestPower: Power action hibernate!\n"));
break;
}
/*
* Save the current system power action for later use.
* This becomes handy when we return from hibernation for example.
*/
if (pDevExt)
pDevExt->win.s.LastSystemPowerAction = enmPowerAction;
break;
}
default:
break;
}
break;
}
default:
break;
}
/*
* Whether we are completing or relaying this power IRP,
* we must call PoStartNextPowerIrp.
*/
PoStartNextPowerIrp(pIrp);
/*
* Send the IRP down the driver stack, using PoCallDriver
* (not IoCallDriver, as for non-power irps).
*/
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,
vbgdNtPowerComplete,
(PVOID)pDevExt,
TRUE,
TRUE,
TRUE);
return PoCallDriver(pDevExt->win.s.pNextLowerDriver, pIrp);
}