VBoxGuest-win-pnp.cpp revision b0a3d0ec5780199a2f379da63c59ccf48f1a73b9
/** @file
*
* VBoxGuest-win-pnp - Windows Plug'n'Play specifics.
*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "VBoxGuest-win.h"
#include "VBoxGuestInternal.h"
#include <VBox/VBoxGuestLib.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
extern winVersion_t g_winVersion;
static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
#ifdef ALLOC_PRAGMA
#endif
#define LOG_ENABLED
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Irp completion routine for PnP Irps we send.
*
* @param pDevObj Device object.
* @param pIrp Request packet.
* @param event Semaphore.
* @return NT status code
*/
{
return STATUS_MORE_PROCESSING_REQUIRED;
}
/**
* Helper to send a PnP IRP and wait until it's done.
*
* @param pDevObj Device object.
* @param pIrp Request packet.
* @param fStrict When set, returns an error if the IRP gives an error.
* @return NT status code
*/
static NTSTATUS vboxguestwinSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
{
if (rc == STATUS_PENDING)
{
}
if (!fStrict
{
rc = STATUS_SUCCESS;
}
return rc;
}
/**
* PnP Request handler.
*
* @param pDevObj Device object.
* @param pIrp Request packet.
*/
{
#ifdef LOG_ENABLED
static char* aszFnctName[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
};
Log(("VBoxGuest::vboxguestwinGuestPnp: MinorFunction: %s\n",
: "Unknown"));
#endif
switch (pStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE\n"));
/* This must be handled first by the lower driver. */
if ( NT_SUCCESS(rc)
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
}
else
{
}
}
{
/* Need to unmap memory in case of errors ... */
}
break;
}
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n"));
/* This must be handled first by the lower driver. */
{
/* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
}
/* Complete the IRP. */
break;
}
case IRP_MN_SURPRISE_REMOVAL:
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n"));
/* 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. */
/* Do not complete the IRP. */
return rc;
}
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_REMOVE_DEVICE\n"));
#ifdef VBOX_REBOOT_ON_UNINSTALL
Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
#endif /* VBOX_REBOOT_ON_UNINSTALL */
if (NT_SUCCESS(rc))
{
/* This IRP passed down to lower driver. */
Log(("VBoxGuest::vboxguestwinGuestPnp: 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::vboxguestwinVBoxGuestPnP: REMOVE_DEVICE\n"));
/* Free hardware resources. */
/* @todo this should actually free I/O ports, interrupts, etc. */
/*
* 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).
*/
Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Removing device ...\n"));
/* Destroy device extension and clean up everything else. */
/* Remove DOS device + symbolic link. */
Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Deleting device ...\n"));
/* Last action: Delete our device! pDevObj is *not* failed
* anymore after this call! */
Log(("VBoxGuest::vboxguestwinGuestPnp: REMOVE_DEVICE: Device removed!\n"));
/* Propagating rc from IoCallDriver. */
return rc; /* Make sure that we don't do anything below here anymore! */
}
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: CANCEL_STOP_DEVICE\n"));
/* This must be handled first by the lower driver. */
{
/* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
}
/* Complete the IRP. */
break;
}
case IRP_MN_QUERY_STOP_DEVICE:
{
Log(("VBoxGuest::vboxguestwinVBoxGuestPnP: QUERY_STOP_DEVICE\n"));
#ifdef VBOX_REBOOT_ON_UNINSTALL
Log(("VBoxGuest::vboxguestwinGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
#endif /* VBOX_REBOOT_ON_UNINSTALL */
if (NT_SUCCESS(rc))
{
/* This IRP passed down to lower driver. */
Log(("VBoxGuest::vboxguestwinGuestPnp: 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::vboxguestwinVBoxGuestPnP: STOP_DEVICE\n"));
/* Free hardware resources. */
/* @todo this should actually free I/O ports, interrupts, etc. */
/* Pass to the lower driver. */
return rc;
}
default:
{
return 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.
*/
{
if (pIrpSp)
{
{
switch (pIrpSp->MinorFunction)
{
case IRP_MN_SET_POWER:
{
case DevicePowerState:
{
case PowerDeviceD0:
break;
}
break;
}
break;
}
}
}
return STATUS_SUCCESS;
}
/**
* Handle the Power requests.
*
* @returns NT status code
* @param pDevObj device object
* @param pIrp IRP
*/
{
Log(("VBoxGuest::vboxguestwinGuestPower\n"));
switch (pStack->MinorFunction)
{
case IRP_MN_SET_POWER:
{
switch (powerType)
{
case SystemPowerState:
{
Log(("VBoxGuest::vboxguestwinGuestPower: SystemPowerState, action = %d, state = %d\n", powerAction, powerState));
switch (powerAction)
{
case PowerActionSleep:
/* System now is in a working state. */
{
if ( pDevExt
{
Log(("VBoxGuest::vboxguestwinGuestPower: Returning from hibernation!\n"));
if (RT_FAILURE(rc))
}
}
break;
case PowerActionShutdownReset:
{
Log(("VBoxGuest::vboxguestwinGuestPower: Power action reset!\n"));
/* Tell the VMM that we no longer support mouse pointer integration. */
int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
if (RT_SUCCESS(vrc))
{
pReq->mouseFeatures = 0;
pReq->pointerXPos = 0;
pReq->pointerYPos = 0;
if (RT_FAILURE(vrc))
{
Log(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev. "
"vrc = %Rrc\n", vrc));
}
}
/* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
break;
}
case PowerActionShutdown:
case PowerActionShutdownOff:
{
Log(("VBoxGuest::vboxguestwinGuestPower: Power action shutdown!\n"));
{
Log(("VBoxGuest::vboxguestwinGuestPower: Telling the VMMDev to close the VM ...\n"));
int vrc = VERR_NOT_IMPLEMENTED;
if (pReq)
{
}
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::vboxguestwinGuestPower: 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)
break;
}
default:
break;
}
break;
}
default:
break;
}
/*
* Whether we are completing or relaying this power IRP,
* we must call PoStartNextPowerIrp.
*/
/*
* Send the IRP down the driver stack,
* using PoCallDriver (not IoCallDriver, as for non-power irps).
*/
TRUE,
TRUE,
TRUE);
}