summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp
parentInitial commit. (diff)
downloadvirtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz
virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp')
-rw-r--r--src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp417
1 files changed, 417 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp
new file mode 100644
index 00000000..d75a9873
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp
@@ -0,0 +1,417 @@
+/* $Id: VBoxUsbPwr.cpp $ */
+/** @file
+ * USB Power state Handling
+ */
+
+/*
+ * Copyright (C) 2011-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * 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.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#include "VBoxUsbCmn.h"
+
+#include <iprt/assert.h>
+
+DECLHIDDEN(VOID) vboxUsbPwrStateInit(PVBOXUSBDEV_EXT pDevExt)
+{
+ POWER_STATE PowerState;
+ PowerState.SystemState = PowerSystemWorking;
+ PowerState.DeviceState = PowerDeviceD0;
+ PoSetPowerState(pDevExt->pFDO, DevicePowerState, PowerState);
+ pDevExt->DdiState.PwrState.PowerState = PowerState;
+ pDevExt->DdiState.PwrState.PowerDownLevel = PowerDeviceUnspecified;
+}
+
+static NTSTATUS vboxUsbPwrMnDefault(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ NTSTATUS Status;
+ PoStartNextPowerIrp(pIrp);
+ IoSkipCurrentIrpStackLocation(pIrp);
+ Status = PoCallDriver(pDevExt->pLowerDO, pIrp);
+ Assert(NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED);
+ vboxUsbDdiStateRelease(pDevExt);
+ return Status;
+}
+
+static NTSTATUS vboxUsbPwrMnPowerSequence(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ AssertFailed();
+ return vboxUsbPwrMnDefault(pDevExt, pIrp);
+}
+
+typedef struct VBOXUSB_PWRDEV_CTX
+{
+ PVBOXUSBDEV_EXT pDevExt;
+ PIRP pIrp;
+} VBOXUSB_PWRDEV_CTX, *PVBOXUSB_PWRDEV_CTX;
+
+static VOID vboxUsbPwrIoDeviceCompletion(IN PDEVICE_OBJECT pDeviceObject,
+ IN UCHAR MinorFunction,
+ IN POWER_STATE PowerState,
+ IN PVOID pvContext,
+ IN PIO_STATUS_BLOCK pIoStatus)
+{
+ RT_NOREF3(pDeviceObject, MinorFunction, PowerState);
+ PVBOXUSB_PWRDEV_CTX pDevCtx = (PVBOXUSB_PWRDEV_CTX)pvContext;
+ PVBOXUSBDEV_EXT pDevExt = pDevCtx->pDevExt;
+ PIRP pIrp = pDevCtx->pIrp;
+ pIrp->IoStatus.Status = pIoStatus->Status;
+ pIrp->IoStatus.Information = 0;
+
+ PoStartNextPowerIrp(pIrp);
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ vboxUsbDdiStateRelease(pDevExt);
+
+ vboxUsbMemFree(pDevCtx);
+}
+
+static NTSTATUS vboxUsbPwrIoRequestDev(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ POWER_STATE PwrState;
+ PwrState.SystemState = pSl->Parameters.Power.State.SystemState;
+ PwrState.DeviceState = pDevExt->DdiState.DevCaps.DeviceState[PwrState.SystemState];
+
+ NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
+ PVBOXUSB_PWRDEV_CTX pDevCtx = (PVBOXUSB_PWRDEV_CTX)vboxUsbMemAlloc(sizeof (*pDevCtx));
+ Assert(pDevCtx);
+ if (pDevCtx)
+ {
+ pDevCtx->pDevExt = pDevExt;
+ pDevCtx->pIrp = pIrp;
+
+ Status = PoRequestPowerIrp(pDevExt->pPDO, pSl->MinorFunction, PwrState,
+ vboxUsbPwrIoDeviceCompletion, pDevCtx, NULL);
+ Assert(NT_SUCCESS(Status));
+ if (NT_SUCCESS(Status))
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ vboxUsbMemFree(pDevCtx);
+ }
+
+ PoStartNextPowerIrp(pIrp);
+ pIrp->IoStatus.Status = Status;
+ pIrp->IoStatus.Information = 0;
+ vboxUsbDdiStateRelease(pDevExt);
+
+ /* the "real" Status is stored in pIrp->IoStatus.Status,
+ * return success here to complete the Io */
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS vboxUsbPwrIoPostSysCompletion(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pvContext)
+{
+ RT_NOREF1(pDevObj);
+ PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pvContext;
+ NTSTATUS Status = pIrp->IoStatus.Status;
+ Assert(Status == STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ {
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ switch (pSl->MinorFunction)
+ {
+ case IRP_MN_SET_POWER:
+ pDevExt->DdiState.PwrState.PowerState.SystemState = pSl->Parameters.Power.State.SystemState;
+ break;
+
+ default:
+ break;
+ }
+
+ return vboxUsbPwrIoRequestDev(pDevExt, pIrp);
+ }
+
+ PoStartNextPowerIrp(pIrp);
+ vboxUsbDdiStateRelease(pDevExt);
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS vboxUsbPwrIoPostSys(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ IoMarkIrpPending(pIrp);
+ IoCopyCurrentIrpStackLocationToNext(pIrp);
+ IoSetCompletionRoutine(pIrp, vboxUsbPwrIoPostSysCompletion, pDevExt, TRUE, TRUE, TRUE);
+ NTSTATUS Status = PoCallDriver(pDevExt->pLowerDO, pIrp);
+ Assert(NT_SUCCESS(Status)); NOREF(Status);
+ return STATUS_PENDING;
+}
+
+static NTSTATUS vboxUsbPwrQueryPowerSys(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ /*PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ SYSTEM_POWER_STATE enmSysPState = pSl->Parameters.Power.State.SystemState;*/
+
+ return vboxUsbPwrIoPostSys(pDevExt, pIrp);
+}
+
+static NTSTATUS vboxUsbPwrIoPostDevCompletion(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pvContext)
+{
+ RT_NOREF1(pDevObj);
+ PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pvContext;
+
+ if (pIrp->PendingReturned)
+ IoMarkIrpPending(pIrp);
+
+ NTSTATUS Status = pIrp->IoStatus.Status;
+ Assert(Status == STATUS_SUCCESS);
+ if (NT_SUCCESS(Status))
+ {
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ switch (pSl->MinorFunction)
+ {
+ case IRP_MN_SET_POWER:
+ pDevExt->DdiState.PwrState.PowerState.DeviceState = pSl->Parameters.Power.State.DeviceState;
+ PoSetPowerState(pDevExt->pFDO, DevicePowerState, pSl->Parameters.Power.State);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ PoStartNextPowerIrp(pIrp);
+ vboxUsbDdiStateRelease(pDevExt);
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS vboxUsbPwrIoPostDev(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ IoMarkIrpPending(pIrp);
+ IoCopyCurrentIrpStackLocationToNext(pIrp);
+ IoSetCompletionRoutine(pIrp, vboxUsbPwrIoPostDevCompletion, pDevExt, TRUE, TRUE, TRUE);
+ NTSTATUS Status = PoCallDriver(pDevExt->pLowerDO, pIrp);
+ Assert(NT_SUCCESS(Status)); RT_NOREF_PV(Status);
+ return STATUS_PENDING;
+}
+
+typedef struct VBOXUSB_IOASYNC_CTX
+{
+ PIO_WORKITEM pWrkItem;
+ PIRP pIrp;
+} VBOXUSB_IOASYNC_CTX, *PVBOXUSB_IOASYNC_CTX;
+
+static VOID vboxUsbPwrIoWaitCompletionAndPostAsyncWorker(IN PDEVICE_OBJECT pDeviceObject, IN PVOID pvContext)
+{
+ PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
+ PVBOXUSB_IOASYNC_CTX pCtx = (PVBOXUSB_IOASYNC_CTX)pvContext;
+ PIRP pIrp = pCtx->pIrp;
+
+ vboxUsbPwrIoPostDev(pDevExt, pIrp);
+
+ IoFreeWorkItem(pCtx->pWrkItem);
+ vboxUsbMemFree(pCtx);
+}
+
+static NTSTATUS vboxUsbPwrIoWaitCompletionAndPostAsync(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
+ PVBOXUSB_IOASYNC_CTX pCtx = (PVBOXUSB_IOASYNC_CTX)vboxUsbMemAlloc(sizeof (*pCtx));
+ Assert(pCtx);
+ if (pCtx)
+ {
+ PIO_WORKITEM pWrkItem = IoAllocateWorkItem(pDevExt->pFDO);
+ Assert(pWrkItem);
+ if (pWrkItem)
+ {
+ pCtx->pWrkItem = pWrkItem;
+ pCtx->pIrp = pIrp;
+ IoMarkIrpPending(pIrp);
+ IoQueueWorkItem(pWrkItem, vboxUsbPwrIoWaitCompletionAndPostAsyncWorker, DelayedWorkQueue, pCtx);
+ return STATUS_PENDING;
+ }
+ vboxUsbMemFree(pCtx);
+ }
+ return Status;
+}
+
+static NTSTATUS vboxUsbPwrQueryPowerDev(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ DEVICE_POWER_STATE enmDevPState = pSl->Parameters.Power.State.DeviceState;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (enmDevPState >= pDevExt->DdiState.PwrState.PowerState.DeviceState)
+ {
+ Status = vboxUsbPwrIoWaitCompletionAndPostAsync(pDevExt, pIrp);
+ Assert(NT_SUCCESS(Status));
+ if (NT_SUCCESS(Status))
+ return Status;
+ }
+
+ pIrp->IoStatus.Status = Status;
+ pIrp->IoStatus.Information = 0;
+
+ PoStartNextPowerIrp(pIrp);
+
+ if (NT_SUCCESS(Status))
+ {
+ IoSkipCurrentIrpStackLocation(pIrp);
+ Status = PoCallDriver(pDevExt->pLowerDO, pIrp);
+ }
+ else
+ {
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+
+ vboxUsbDdiStateRelease(pDevExt);
+
+ return Status;
+}
+
+static NTSTATUS vboxUsbPwrMnQueryPower(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ switch (pSl->Parameters.Power.Type)
+ {
+ case SystemPowerState:
+ return vboxUsbPwrQueryPowerSys(pDevExt, pIrp);
+
+ case DevicePowerState:
+ return vboxUsbPwrQueryPowerDev(pDevExt, pIrp);
+
+ default:
+ AssertFailed();
+ return vboxUsbPwrMnDefault(pDevExt, pIrp);
+
+ }
+}
+
+static NTSTATUS vboxUsbPwrSetPowerSys(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ /*PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ SYSTEM_POWER_STATE enmSysPState = pSl->Parameters.Power.State.SystemState;*/
+
+ return vboxUsbPwrIoPostSys(pDevExt, pIrp);
+}
+
+static NTSTATUS vboxUsbPwrSetPowerDev(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ DEVICE_POWER_STATE enmDevPState = pSl->Parameters.Power.State.DeviceState;
+ DEVICE_POWER_STATE enmCurDevPState = pDevExt->DdiState.PwrState.PowerState.DeviceState;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (enmDevPState > enmCurDevPState && enmCurDevPState == PowerDeviceD0)
+ {
+ Status = vboxUsbPwrIoWaitCompletionAndPostAsync(pDevExt, pIrp);
+ Assert(NT_SUCCESS(Status));
+ if (NT_SUCCESS(Status))
+ return Status;
+ }
+
+ PoStartNextPowerIrp(pIrp);
+
+ if (NT_SUCCESS(Status))
+ {
+ IoCopyCurrentIrpStackLocationToNext(pIrp);
+ IoSetCompletionRoutine(pIrp, vboxUsbPwrIoPostDevCompletion, pDevExt, TRUE, TRUE, TRUE);
+ Status = PoCallDriver(pDevExt->pLowerDO, pIrp);
+ }
+ else
+ {
+ pIrp->IoStatus.Status = Status;
+ pIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ vboxUsbDdiStateRelease(pDevExt);
+ }
+
+ return Status;
+}
+
+
+static NTSTATUS vboxUsbPwrMnSetPower(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+ switch (pSl->Parameters.Power.Type)
+ {
+ case SystemPowerState:
+ return vboxUsbPwrSetPowerSys(pDevExt, pIrp);
+
+ case DevicePowerState:
+ return vboxUsbPwrSetPowerDev(pDevExt, pIrp);
+
+ default:
+ AssertFailed();
+ return vboxUsbPwrMnDefault(pDevExt, pIrp);
+ }
+}
+
+static NTSTATUS vboxUsbPwrMnWaitWake(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ AssertFailed();
+ return vboxUsbPwrMnDefault(pDevExt, pIrp);
+}
+
+
+static NTSTATUS vboxUsbPwrDispatch(IN PVBOXUSBDEV_EXT pDevExt, IN PIRP pIrp)
+{
+ PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
+
+ switch (pSl->MinorFunction)
+ {
+ case IRP_MN_POWER_SEQUENCE:
+ return vboxUsbPwrMnPowerSequence(pDevExt, pIrp);
+
+ case IRP_MN_QUERY_POWER:
+ return vboxUsbPwrMnQueryPower(pDevExt, pIrp);
+
+ case IRP_MN_SET_POWER:
+ return vboxUsbPwrMnSetPower(pDevExt, pIrp);
+
+ case IRP_MN_WAIT_WAKE:
+ return vboxUsbPwrMnWaitWake(pDevExt, pIrp);
+
+ default:
+// AssertFailed();
+ return vboxUsbPwrMnDefault(pDevExt, pIrp);
+ }
+}
+
+DECLHIDDEN(NTSTATUS) vboxUsbDispatchPower(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
+{
+ PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension;
+ ENMVBOXUSB_PNPSTATE enmState = vboxUsbDdiStateRetainIfNotRemoved(pDevExt);
+ switch (enmState)
+ {
+ case ENMVBOXUSB_PNPSTATE_REMOVED:
+ PoStartNextPowerIrp(pIrp);
+
+ pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
+ pIrp->IoStatus.Information = 0;
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ vboxUsbDdiStateRelease(pDevExt);
+
+ return STATUS_DELETE_PENDING;
+
+ case ENMVBOXUSB_PNPSTATE_START_PENDING:
+ PoStartNextPowerIrp(pIrp);
+ IoSkipCurrentIrpStackLocation(pIrp);
+
+ vboxUsbDdiStateRelease(pDevExt);
+
+ return PoCallDriver(pDevExt->pLowerDO, pIrp);
+
+ default:
+ return vboxUsbPwrDispatch(pDevExt, pIrp);
+ }
+}
+