From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/HostDrivers/VBoxUSB/win/dev/Makefile.kup | 0 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUSB.inf | 88 ++ src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbCmn.h | 103 ++ .../HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.cpp | 357 +++++ src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.h | 218 +++ src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.rc | 70 + .../HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.cpp | 274 ++++ src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.h | 46 + .../HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp | 427 ++++++ src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.h | 51 + src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.cpp | 1593 ++++++++++++++++++++ src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.h | 97 ++ 12 files changed, 3324 insertions(+) create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/Makefile.kup create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUSB.inf create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbCmn.h create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.cpp create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.h create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.rc create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.cpp create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.h create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.h create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.cpp create mode 100644 src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.h (limited to 'src/VBox/HostDrivers/VBoxUSB/win/dev') diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/Makefile.kup b/src/VBox/HostDrivers/VBoxUSB/win/dev/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUSB.inf b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUSB.inf new file mode 100644 index 00000000..9b580b98 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUSB.inf @@ -0,0 +1,88 @@ +; $Id: VBoxUSB.inf $ +;; @file +; VBox host drivers - USB drivers - Win32 USB device +; + +; +; Copyright (C) 2011-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox 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. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +[Version] +Signature="$Windows NT$" +Class=USB +ClassGUID={36FC9E60-C465-11CF-8056-444553540000} +provider=%ORACLE% +;edit-DriverVer=08/26/2008,2.00.0000 +;cat CatalogFile=VBoxUSB.cat + +[SourceDisksNames] +1=%Disk_Description%,,, + +[SourceDisksFiles] +VBoxUSB.sys = 1 + +[Manufacturer] +%ORACLE%=VBoxUSB@COMMA-NT-ARCH@ + +[VBoxUSB@DOT-NT-ARCH@] +%USB\VID_80EE&PID_CAFE.DeviceDesc%=VBoxUSB.Dev, USB\VID_80EE&PID_CAFE + +[DestinationDirs] +VBoxUSB.Files.Ext = 10,System32\Drivers + +[VBoxUSB.Dev.NT] +CopyFiles=VBoxUSB.Files.Ext + +[VBoxUSB.Dev.NT.Services] +Addservice = VBoxUSB, 0x00000002, VBoxUSB.AddService + +[VBoxUSB.AddService] +DisplayName = %VBoxUSB.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %10%\System32\Drivers\VBoxUSB.sys +AddReg = VBoxUSB.AddReg +LoadOrderGroup = Base + +[VBoxUSB.AddReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,VBoxUSB.sys + +[VBoxUSB.Files.Ext] +VBoxUSB.sys + +;---------------------------------------------------------------; + +[Strings] +ORACLE="Oracle Corporation" +Disk_Description="VBoxUSB Installation Disk" +USB\VID_80EE&PID_CAFE.DeviceDesc="VirtualBox USB" +VBoxUSB.SvcDesc="VirtualBox USB" diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbCmn.h b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbCmn.h new file mode 100644 index 00000000..57eeeafa --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbCmn.h @@ -0,0 +1,103 @@ +/* $Id: VBoxUsbCmn.h $ */ +/** @file + * VBoxUsmCmn.h - USB device. Common defs + */ +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbCmn_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbCmn_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "../cmn/VBoxDrvTool.h" +#include "../cmn/VBoxUsbTool.h" + +#include +#include + +#include + +#define VBOXUSB_CFG_IDLE_TIME_MS 5000 + +typedef struct VBOXUSBDEV_EXT *PVBOXUSBDEV_EXT; + +RT_C_DECLS_BEGIN + +#ifdef _WIN64 +#define DECLSPEC_USBIMPORT DECLSPEC_IMPORT +#else +#define DECLSPEC_USBIMPORT + +#define USBD_ParseDescriptors _USBD_ParseDescriptors +#define USBD_ParseConfigurationDescriptorEx _USBD_ParseConfigurationDescriptorEx +#define USBD_CreateConfigurationRequestEx _USBD_CreateConfigurationRequestEx +#endif + +DECLSPEC_USBIMPORT PUSB_COMMON_DESCRIPTOR +USBD_ParseDescriptors( + IN PVOID DescriptorBuffer, + IN ULONG TotalLength, + IN PVOID StartPosition, + IN LONG DescriptorType + ); + +DECLSPEC_USBIMPORT PUSB_INTERFACE_DESCRIPTOR +USBD_ParseConfigurationDescriptorEx( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + IN PVOID StartPosition, + IN LONG InterfaceNumber, + IN LONG AlternateSetting, + IN LONG InterfaceClass, + IN LONG InterfaceSubClass, + IN LONG InterfaceProtocol + ); + +DECLSPEC_USBIMPORT PURB +USBD_CreateConfigurationRequestEx( + IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList + ); + +RT_C_DECLS_END + +DECLHIDDEN(PVOID) vboxUsbMemAlloc(SIZE_T cbBytes); +DECLHIDDEN(PVOID) vboxUsbMemAllocZ(SIZE_T cbBytes); +DECLHIDDEN(VOID) vboxUsbMemFree(PVOID pvMem); + +#include "VBoxUsbRt.h" +#include "VBoxUsbPnP.h" +#include "VBoxUsbPwr.h" +#include "VBoxUsbDev.h" + + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbCmn_h */ diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.cpp b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.cpp new file mode 100644 index 00000000..680f5d2f --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.cpp @@ -0,0 +1,357 @@ +/* $Id: VBoxUsbDev.cpp $ */ +/** @file + * VBoxUsbDev.cpp - USB device. + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "VBoxUsbCmn.h" +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define VBOXUSB_MEMTAG 'bUBV' + + + +DECLHIDDEN(PVOID) vboxUsbMemAlloc(SIZE_T cbBytes) +{ + PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSB_MEMTAG); + Assert(pvMem); + return pvMem; +} + +DECLHIDDEN(PVOID) vboxUsbMemAllocZ(SIZE_T cbBytes) +{ + PVOID pvMem = vboxUsbMemAlloc(cbBytes); + if (pvMem) + { + RtlZeroMemory(pvMem, cbBytes); + } + return pvMem; +} + +DECLHIDDEN(VOID) vboxUsbMemFree(PVOID pvMem) +{ + ExFreePoolWithTag(pvMem, VBOXUSB_MEMTAG); +} + +VBOXUSB_GLOBALS g_VBoxUsbGlobals = {0}; + +static NTSTATUS vboxUsbDdiAddDevice(PDRIVER_OBJECT pDriverObject, + PDEVICE_OBJECT pPDO) +{ + PDEVICE_OBJECT pFDO = NULL; + NTSTATUS Status = IoCreateDevice(pDriverObject, + sizeof (VBOXUSBDEV_EXT), + NULL, /* IN PUNICODE_STRING pDeviceName OPTIONAL */ + FILE_DEVICE_UNKNOWN, /* IN DEVICE_TYPE DeviceType */ + FILE_AUTOGENERATED_DEVICE_NAME, /* IN ULONG DeviceCharacteristics */ + FALSE, /* IN BOOLEAN fExclusive */ + &pFDO); + Assert(Status == STATUS_SUCCESS); + if (Status == STATUS_SUCCESS) + { + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pFDO->DeviceExtension; + /* init Device Object bits */ + pFDO->Flags |= DO_DIRECT_IO; + if (pPDO->Flags & DO_POWER_PAGABLE) + pFDO->Flags |= DO_POWER_PAGABLE; + + + /* now init our state bits */ + + pDevExt->cHandles = 0; + + pDevExt->pFDO = pFDO; + pDevExt->pPDO = pPDO; + pDevExt->pLowerDO = IoAttachDeviceToDeviceStack(pFDO, pPDO); + Assert(pDevExt->pLowerDO); + if (pDevExt->pLowerDO) + { + vboxUsbDdiStateInit(pDevExt); + Status = vboxUsbRtInit(pDevExt); + if (Status == STATUS_SUCCESS) + { + /* we're done! */ + pFDO->Flags &= ~DO_DEVICE_INITIALIZING; + return STATUS_SUCCESS; + } + + IoDetachDevice(pDevExt->pLowerDO); + } + else + Status = STATUS_NO_SUCH_DEVICE; + + IoDeleteDevice(pFDO); + } + + return Status; +} + +static VOID vboxUsbDdiUnload(PDRIVER_OBJECT pDriverObject) +{ + RT_NOREF1(pDriverObject); + LogRel(("VBoxUsb::DriverUnload. Built Date (%s) Time (%s)\n", __DATE__, __TIME__)); + VBoxDrvToolStrFree(&g_VBoxUsbGlobals.RegPath); + + vboxUsbRtGlobalsTerm(); + + PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL); + if (pLogger) + { + RTLogDestroy(pLogger); + } + pLogger = RTLogSetDefaultInstance(NULL); + if (pLogger) + { + RTLogDestroy(pLogger); + } +} + +static NTSTATUS vboxUsbDispatchCreate(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension; + NTSTATUS Status = STATUS_INVALID_HANDLE; + do + { + if (vboxUsbPnPStateGet(pDevExt) != ENMVBOXUSB_PNPSTATE_STARTED) + { + Status = STATUS_INVALID_DEVICE_STATE; + break; + } + + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + if (!pFObj) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + pFObj->FsContext = NULL; + + if (pFObj->FileName.Length) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + + Status = vboxUsbRtCreate(pDevExt, pIrp); + if (!NT_SUCCESS(Status)) + { + AssertFailed(); + break; + } + + ASMAtomicIncU32(&pDevExt->cHandles); + Status = STATUS_SUCCESS; + break; + } while (0); + + Status = VBoxDrvToolIoComplete(pIrp, Status, 0); + return Status; +} + +static NTSTATUS vboxUsbDispatchClose(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension; + NTSTATUS Status = STATUS_SUCCESS; +#ifdef VBOX_STRICT + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + Assert(pFObj); + Assert(!pFObj->FileName.Length); +#endif + Status = vboxUsbRtClose(pDevExt, pIrp); + if (NT_SUCCESS(Status)) + { + ASMAtomicDecU32(&pDevExt->cHandles); + } + else + { + AssertFailed(); + } + Status = VBoxDrvToolIoComplete(pIrp, Status, 0); + return Status; +} + +static NTSTATUS vboxUsbDispatchDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension; + if (vboxUsbDdiStateRetainIfStarted(pDevExt)) + return vboxUsbRtDispatch(pDevExt, pIrp); + return VBoxDrvToolIoComplete(pIrp, STATUS_INVALID_DEVICE_STATE, 0); +} + +static NTSTATUS vboxUsbDispatchCleanup(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + RT_NOREF1(pDeviceObject); + return VBoxDrvToolIoComplete(pIrp, STATUS_SUCCESS, 0); +} + +static NTSTATUS vboxUsbDevAccessDeviedDispatchStub(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension; + if (!vboxUsbDdiStateRetainIfNotRemoved(pDevExt)) + { + VBoxDrvToolIoComplete(pIrp, STATUS_DELETE_PENDING, 0); + return STATUS_DELETE_PENDING; + } + + NTSTATUS Status = VBoxDrvToolIoComplete(pIrp, STATUS_ACCESS_DENIED, 0); + + vboxUsbDdiStateRelease(pDevExt); + + return Status; +} + +static NTSTATUS vboxUsbDispatchSystemControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension; + if (!vboxUsbDdiStateRetainIfNotRemoved(pDevExt)) + { + VBoxDrvToolIoComplete(pIrp, STATUS_DELETE_PENDING, 0); + return STATUS_DELETE_PENDING; + } + + IoSkipCurrentIrpStackLocation(pIrp); + + NTSTATUS Status = IoCallDriver(pDevExt->pLowerDO, pIrp); + + vboxUsbDdiStateRelease(pDevExt); + + return Status; +} + +static NTSTATUS vboxUsbDispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ +#ifdef DEBUG_misha + AssertFailed(); +#endif + return vboxUsbDevAccessDeviedDispatchStub(pDeviceObject, pIrp); +} + +static NTSTATUS vboxUsbDispatchWrite(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ +#ifdef DEBUG_misha + AssertFailed(); +#endif + return vboxUsbDevAccessDeviedDispatchStub(pDeviceObject, pIrp); +} + +RT_C_DECLS_BEGIN + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath); + +RT_C_DECLS_END + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) +{ + LogRel(("VBoxUsb::DriverEntry. Built Date (%s) Time (%s)\n", __DATE__, __TIME__)); + + NTSTATUS Status = vboxUsbRtGlobalsInit(); + Assert(Status == STATUS_SUCCESS); + if (Status == STATUS_SUCCESS) + { + Status = VBoxDrvToolStrCopy(&g_VBoxUsbGlobals.RegPath, pRegistryPath); + Assert(Status == STATUS_SUCCESS); + if (Status == STATUS_SUCCESS) + { + g_VBoxUsbGlobals.pDrvObj = pDriverObject; + + pDriverObject->DriverExtension->AddDevice = vboxUsbDdiAddDevice; + + pDriverObject->DriverUnload = vboxUsbDdiUnload; + + pDriverObject->MajorFunction[IRP_MJ_CREATE] = vboxUsbDispatchCreate; + pDriverObject->MajorFunction[IRP_MJ_CLOSE] = vboxUsbDispatchClose; + pDriverObject->MajorFunction[IRP_MJ_READ] = vboxUsbDispatchRead; + pDriverObject->MajorFunction[IRP_MJ_WRITE] = vboxUsbDispatchWrite; + pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vboxUsbDispatchDeviceControl; + pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = vboxUsbDispatchCleanup; + pDriverObject->MajorFunction[IRP_MJ_POWER] = vboxUsbDispatchPower; + pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = vboxUsbDispatchSystemControl; + pDriverObject->MajorFunction[IRP_MJ_PNP] = vboxUsbDispatchPnP; + + return STATUS_SUCCESS; + } + vboxUsbRtGlobalsTerm(); + } + + LogRel(("VBoxUsb::DriverEntry. failed with Status (0x%x)\n", Status)); + + return Status; +} + +#ifdef VBOX_STRICT +DECLHIDDEN(VOID) vboxUsbPnPStateGbgChange(ENMVBOXUSB_PNPSTATE enmOldState, ENMVBOXUSB_PNPSTATE enmNewState) +{ + /* *ensure the state change is valid */ + switch (enmNewState) + { + case ENMVBOXUSB_PNPSTATE_STARTED: + Assert( enmOldState == ENMVBOXUSB_PNPSTATE_START_PENDING + || enmOldState == ENMVBOXUSB_PNPSTATE_REMOVE_PENDING + || enmOldState == ENMVBOXUSB_PNPSTATE_STOPPED + || enmOldState == ENMVBOXUSB_PNPSTATE_STOP_PENDING); + break; + case ENMVBOXUSB_PNPSTATE_STOP_PENDING: + Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STARTED); + break; + case ENMVBOXUSB_PNPSTATE_STOPPED: + Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STOP_PENDING); + break; + case ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED: + Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STARTED); + break; + case ENMVBOXUSB_PNPSTATE_REMOVE_PENDING: + Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STARTED); + break; + case ENMVBOXUSB_PNPSTATE_REMOVED: + Assert( enmOldState == ENMVBOXUSB_PNPSTATE_REMOVE_PENDING + || enmOldState == ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED); + break; + default: + AssertFailed(); + break; + } + +} +#endif diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.h b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.h new file mode 100644 index 00000000..7dd19d86 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.h @@ -0,0 +1,218 @@ +/* $Id: VBoxUsbDev.h $ */ +/** @file + * VBoxUsbDev.h - USB device. + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbDev_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbDev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxUsbCmn.h" +#include +#include + +typedef struct VBOXUSB_GLOBALS +{ + PDRIVER_OBJECT pDrvObj; + UNICODE_STRING RegPath; + VBOXUSBRT_IDC RtIdc; +} VBOXUSB_GLOBALS, *PVBOXUSB_GLOBALS; + +extern VBOXUSB_GLOBALS g_VBoxUsbGlobals; + +/* pnp state decls */ +typedef enum +{ + ENMVBOXUSB_PNPSTATE_UNKNOWN = 0, + ENMVBOXUSB_PNPSTATE_START_PENDING, + ENMVBOXUSB_PNPSTATE_STARTED, + ENMVBOXUSB_PNPSTATE_STOP_PENDING, + ENMVBOXUSB_PNPSTATE_STOPPED, + ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED, + ENMVBOXUSB_PNPSTATE_REMOVE_PENDING, + ENMVBOXUSB_PNPSTATE_REMOVED, + ENMVBOXUSB_PNPSTATE_FORSEDWORD = 0x8fffffff +} ENMVBOXUSB_PNPSTATE; +AssertCompile(sizeof (ENMVBOXUSB_PNPSTATE) == sizeof (uint32_t)); + +#ifdef VBOX_STRICT +DECLHIDDEN(VOID) vboxUsbPnPStateGbgChange(ENMVBOXUSB_PNPSTATE enmOld, ENMVBOXUSB_PNPSTATE enmNew); +# define VBOXUSB_PNP_GBG_STATE_CHANGE(_old, _new) vboxUsbPnPStateGbgChange((_old), (_new)) +#else +# define VBOXUSB_PNP_GBG_STATE_CHANGE(_old, _new) do { } while (0) +#endif + + +typedef struct VBOXUSB_PNPSTATE +{ + /* Current state */ + volatile ENMVBOXUSB_PNPSTATE Curr; + /* Previous state, used to restore state info on cancell stop device */ + ENMVBOXUSB_PNPSTATE Prev; +} VBOXUSB_PNPSTATE, *PVBOXUSB_PNPSTATE; + +typedef struct VBOXUSBDEV_DDISTATE +{ + /* Lock */ + KSPIN_LOCK Lock; + VBOXDRVTOOL_REF Ref; + VBOXUSB_PNPSTATE PnPState; + VBOXUSB_PWRSTATE PwrState; + /* current dev caps */ + DEVICE_CAPABILITIES DevCaps; +} VBOXUSBDEV_DDISTATE, *PVBOXUSBDEV_DDISTATE; + +typedef struct VBOXUSBDEV_EXT +{ + PDEVICE_OBJECT pFDO; + PDEVICE_OBJECT pPDO; + PDEVICE_OBJECT pLowerDO; + + VBOXUSBDEV_DDISTATE DdiState; + + uint32_t cHandles; + + VBOXUSB_RT Rt; + +} VBOXUSBDEV_EXT, *PVBOXUSBDEV_EXT; + +/* pnp state api */ +DECLINLINE(ENMVBOXUSB_PNPSTATE) vboxUsbPnPStateGet(PVBOXUSBDEV_EXT pDevExt) +{ + return (ENMVBOXUSB_PNPSTATE)ASMAtomicUoReadU32((volatile uint32_t*)&pDevExt->DdiState.PnPState.Curr); +} + +DECLINLINE(ENMVBOXUSB_PNPSTATE) vboxUsbPnPStateSet(PVBOXUSBDEV_EXT pDevExt, ENMVBOXUSB_PNPSTATE enmState) +{ + KIRQL Irql; + ENMVBOXUSB_PNPSTATE enmOldState; + KeAcquireSpinLock(&pDevExt->DdiState.Lock, &Irql); + pDevExt->DdiState.PnPState.Prev = (ENMVBOXUSB_PNPSTATE)ASMAtomicUoReadU32((volatile uint32_t*)&pDevExt->DdiState.PnPState.Curr); + ASMAtomicWriteU32((volatile uint32_t*)&pDevExt->DdiState.PnPState.Curr, (uint32_t)enmState); + pDevExt->DdiState.PnPState.Curr = enmState; + enmOldState = pDevExt->DdiState.PnPState.Prev; + KeReleaseSpinLock(&pDevExt->DdiState.Lock, Irql); + VBOXUSB_PNP_GBG_STATE_CHANGE(enmOldState, enmState); + return enmState; +} + +DECLINLINE(ENMVBOXUSB_PNPSTATE) vboxUsbPnPStateRestore(PVBOXUSBDEV_EXT pDevExt) +{ + ENMVBOXUSB_PNPSTATE enmNewState, enmOldState; + KIRQL Irql; + KeAcquireSpinLock(&pDevExt->DdiState.Lock, &Irql); + enmOldState = pDevExt->DdiState.PnPState.Curr; + enmNewState = pDevExt->DdiState.PnPState.Prev; + ASMAtomicWriteU32((volatile uint32_t*)&pDevExt->DdiState.PnPState.Curr, (uint32_t)pDevExt->DdiState.PnPState.Prev); + KeReleaseSpinLock(&pDevExt->DdiState.Lock, Irql); + VBOXUSB_PNP_GBG_STATE_CHANGE(enmOldState, enmNewState); + Assert(enmNewState == ENMVBOXUSB_PNPSTATE_STARTED); + Assert(enmOldState == ENMVBOXUSB_PNPSTATE_STOP_PENDING + || enmOldState == ENMVBOXUSB_PNPSTATE_REMOVE_PENDING); + return enmNewState; +} + +DECLINLINE(VOID) vboxUsbPnPStateInit(PVBOXUSBDEV_EXT pDevExt) +{ + pDevExt->DdiState.PnPState.Curr = pDevExt->DdiState.PnPState.Prev = ENMVBOXUSB_PNPSTATE_START_PENDING; +} + +DECLINLINE(VOID) vboxUsbDdiStateInit(PVBOXUSBDEV_EXT pDevExt) +{ + KeInitializeSpinLock(&pDevExt->DdiState.Lock); + VBoxDrvToolRefInit(&pDevExt->DdiState.Ref); + vboxUsbPwrStateInit(pDevExt); + vboxUsbPnPStateInit(pDevExt); +} + +DECLINLINE(bool) vboxUsbDdiStateRetainIfStarted(PVBOXUSBDEV_EXT pDevExt) +{ + KIRQL oldIrql; + bool bRetained = true; + KeAcquireSpinLock(&pDevExt->DdiState.Lock, &oldIrql); + if (vboxUsbPnPStateGet(pDevExt) == ENMVBOXUSB_PNPSTATE_STARTED) + { + VBoxDrvToolRefRetain(&pDevExt->DdiState.Ref); + } + else + { + bRetained = false; + } + KeReleaseSpinLock(&pDevExt->DdiState.Lock, oldIrql); + return bRetained; +} + +/* if device is removed - does nothing and returns zero, + * otherwise increments a ref counter and returns the current pnp state + * NOTE: never returns ENMVBOXUSB_PNPSTATE_REMOVED + * */ +DECLINLINE(ENMVBOXUSB_PNPSTATE) vboxUsbDdiStateRetainIfNotRemoved(PVBOXUSBDEV_EXT pDevExt) +{ + KIRQL oldIrql; + ENMVBOXUSB_PNPSTATE enmState; + KeAcquireSpinLock(&pDevExt->DdiState.Lock, &oldIrql); + enmState = vboxUsbPnPStateGet(pDevExt); + if (enmState != ENMVBOXUSB_PNPSTATE_REMOVED) + { + VBoxDrvToolRefRetain(&pDevExt->DdiState.Ref); + } + KeReleaseSpinLock(&pDevExt->DdiState.Lock, oldIrql); + return enmState != ENMVBOXUSB_PNPSTATE_REMOVED ? enmState : (ENMVBOXUSB_PNPSTATE)0; +} + +DECLINLINE(uint32_t) vboxUsbDdiStateRetain(PVBOXUSBDEV_EXT pDevExt) +{ + return VBoxDrvToolRefRetain(&pDevExt->DdiState.Ref); +} + +DECLINLINE(uint32_t) vboxUsbDdiStateRelease(PVBOXUSBDEV_EXT pDevExt) +{ + return VBoxDrvToolRefRelease(&pDevExt->DdiState.Ref); +} + +DECLINLINE(VOID) vboxUsbDdiStateReleaseAndWaitCompleted(PVBOXUSBDEV_EXT pDevExt) +{ + VBoxDrvToolRefRelease(&pDevExt->DdiState.Ref); + VBoxDrvToolRefWaitEqual(&pDevExt->DdiState.Ref, 1); +} + +DECLINLINE(VOID) vboxUsbDdiStateReleaseAndWaitRemoved(PVBOXUSBDEV_EXT pDevExt) +{ + VBoxDrvToolRefRelease(&pDevExt->DdiState.Ref); + VBoxDrvToolRefWaitEqual(&pDevExt->DdiState.Ref, 0); +} + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbDev_h */ diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.rc b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.rc new file mode 100644 index 00000000..83ccd753 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbDev.rc @@ -0,0 +1,70 @@ +/* $Id: VBoxUsbDev.rc $ */ +/** @file + * VBoxUSB - Resource file containing version info and icon. + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VBOX_RC_FILE_VERSION + PRODUCTVERSION VBOX_RC_FILE_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS VBOX_RC_FILE_FLAGS + FILEOS VBOX_RC_FILE_OS + FILETYPE VBOX_RC_TYPE_DRV + FILESUBTYPE VFT2_DRV_SYSTEM +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "FileDescription", "VirtualBox USB Driver\0" + VALUE "InternalName", "VBoxUSB\0" + VALUE "OriginalFilename", "VBoxUSB.sys\0" + VALUE "CompanyName", VBOX_RC_COMPANY_NAME + VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR + VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT + VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR + VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR + VBOX_RC_MORE_STRINGS + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.cpp b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.cpp new file mode 100644 index 00000000..18a068c8 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.cpp @@ -0,0 +1,274 @@ +/* $Id: VBoxUsbPnP.cpp $ */ +/** @file + * USB PnP Handling + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include "VBoxUsbCmn.h" + +static NTSTATUS vboxUsbPnPMnStartDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + IoCopyCurrentIrpStackLocationToNext(pIrp); + NTSTATUS Status = VBoxDrvToolIoPostSync(pDevExt->pLowerDO, pIrp); + Assert(NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED); + if (NT_SUCCESS(Status)) + { + Status = vboxUsbRtStart(pDevExt); + Assert(Status == STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + { + vboxUsbPnPStateSet(pDevExt, ENMVBOXUSB_PNPSTATE_STARTED); + } + } + + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbPnPMnQueryStopDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + vboxUsbPnPStateSet(pDevExt, ENMVBOXUSB_PNPSTATE_STOP_PENDING); + + vboxUsbDdiStateReleaseAndWaitCompleted(pDevExt); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoSkipCurrentIrpStackLocation(pIrp); + return IoCallDriver(pDevExt->pLowerDO, pIrp); +} + +static NTSTATUS vboxUsbPnPMnStopDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + vboxUsbPnPStateSet(pDevExt, ENMVBOXUSB_PNPSTATE_STOPPED); + + vboxUsbRtClear(pDevExt); + + NTSTATUS Status = VBoxUsbToolDevUnconfigure(pDevExt->pLowerDO); + Assert(NT_SUCCESS(Status)); + + pIrp->IoStatus.Status = Status; + pIrp->IoStatus.Information = 0; + IoSkipCurrentIrpStackLocation(pIrp); + Status = IoCallDriver(pDevExt->pLowerDO, pIrp); + + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbPnPMnCancelStopDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + ENMVBOXUSB_PNPSTATE enmState = vboxUsbPnPStateGet(pDevExt); + NTSTATUS Status = STATUS_SUCCESS; + + IoCopyCurrentIrpStackLocationToNext(pIrp); + Status = VBoxDrvToolIoPostSync(pDevExt->pLowerDO, pIrp); + if (NT_SUCCESS(Status) && enmState == ENMVBOXUSB_PNPSTATE_STOP_PENDING) + { + vboxUsbPnPStateRestore(pDevExt); + } + + Status = STATUS_SUCCESS; + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + + return Status; +} + +static NTSTATUS vboxUsbPnPMnQueryRemoveDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + vboxUsbPnPStateSet(pDevExt, ENMVBOXUSB_PNPSTATE_REMOVE_PENDING); + + vboxUsbDdiStateReleaseAndWaitCompleted(pDevExt); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoSkipCurrentIrpStackLocation(pIrp); + return IoCallDriver(pDevExt->pLowerDO, pIrp); +} + +static NTSTATUS vboxUsbPnPRmDev(PVBOXUSBDEV_EXT pDevExt) +{ + NTSTATUS Status = vboxUsbRtRm(pDevExt); + Assert(Status == STATUS_SUCCESS); + + return Status; +} + +static NTSTATUS vboxUsbPnPMnRemoveDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + ENMVBOXUSB_PNPSTATE enmState = vboxUsbPnPStateGet(pDevExt); + NTSTATUS Status = STATUS_SUCCESS; + if (enmState != ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED) + { + Status = vboxUsbPnPRmDev(pDevExt); + Assert(Status == STATUS_SUCCESS); + } + + vboxUsbPnPStateSet(pDevExt, ENMVBOXUSB_PNPSTATE_REMOVED); + + vboxUsbDdiStateRelease(pDevExt); + + vboxUsbDdiStateReleaseAndWaitRemoved(pDevExt); + + vboxUsbRtClear(pDevExt); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoSkipCurrentIrpStackLocation(pIrp); + Status = IoCallDriver(pDevExt->pLowerDO, pIrp); + + IoDetachDevice(pDevExt->pLowerDO); + IoDeleteDevice(pDevExt->pFDO); + + return Status; +} + +static NTSTATUS vboxUsbPnPMnCancelRemoveDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + ENMVBOXUSB_PNPSTATE enmState = vboxUsbPnPStateGet(pDevExt); + NTSTATUS Status = STATUS_SUCCESS; + IoCopyCurrentIrpStackLocationToNext(pIrp); + + Status = VBoxDrvToolIoPostSync(pDevExt->pLowerDO, pIrp); + + if (NT_SUCCESS(Status) && + enmState == ENMVBOXUSB_PNPSTATE_REMOVE_PENDING) + { + vboxUsbPnPStateRestore(pDevExt); + } + + Status = STATUS_SUCCESS; + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + + return Status; +} + +static NTSTATUS vboxUsbPnPMnSurpriseRemoval(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + vboxUsbPnPStateSet(pDevExt, ENMVBOXUSB_PNPSTATE_SURPRISE_REMOVED); + + NTSTATUS Status = vboxUsbPnPRmDev(pDevExt); + Assert(Status == STATUS_SUCCESS); + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = 0; + IoSkipCurrentIrpStackLocation(pIrp); + Status = IoCallDriver(pDevExt->pLowerDO, pIrp); + + vboxUsbDdiStateRelease(pDevExt); + + return Status; +} + +static NTSTATUS vboxUsbPnPMnQueryCapabilities(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PDEVICE_CAPABILITIES pDevCaps = pSl->Parameters.DeviceCapabilities.Capabilities; + + if (pDevCaps->Version < 1 || pDevCaps->Size < sizeof (*pDevCaps)) + { + AssertFailed(); + /** @todo return more appropriate status ?? */ + return STATUS_UNSUCCESSFUL; + } + + pDevCaps->SurpriseRemovalOK = TRUE; + pIrp->IoStatus.Status = STATUS_SUCCESS; + + IoCopyCurrentIrpStackLocationToNext(pIrp); + NTSTATUS Status = VBoxDrvToolIoPostSync(pDevExt->pLowerDO, pIrp); + Assert(NT_SUCCESS(Status)); + if (NT_SUCCESS(Status)) + { + pDevCaps->SurpriseRemovalOK = 1; + pDevExt->DdiState.DevCaps = *pDevCaps; + } + + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + + return Status; +} + +static NTSTATUS vboxUsbPnPMnDefault(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + NTSTATUS Status; + IoSkipCurrentIrpStackLocation(pIrp); + Status = IoCallDriver(pDevExt->pLowerDO, pIrp); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +DECLHIDDEN(NTSTATUS) vboxUsbDispatchPnP(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) +{ + PVBOXUSBDEV_EXT pDevExt = (PVBOXUSBDEV_EXT)pDeviceObject->DeviceExtension; + if (!vboxUsbDdiStateRetainIfNotRemoved(pDevExt)) + return VBoxDrvToolIoComplete(pIrp, STATUS_DELETE_PENDING, 0); + + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + switch (pSl->MinorFunction) + { + case IRP_MN_START_DEVICE: + return vboxUsbPnPMnStartDevice(pDevExt, pIrp); + + case IRP_MN_QUERY_STOP_DEVICE: + return vboxUsbPnPMnQueryStopDevice(pDevExt, pIrp); + + case IRP_MN_STOP_DEVICE: + return vboxUsbPnPMnStopDevice(pDevExt, pIrp); + + case IRP_MN_CANCEL_STOP_DEVICE: + return vboxUsbPnPMnCancelStopDevice(pDevExt, pIrp); + + case IRP_MN_QUERY_REMOVE_DEVICE: + return vboxUsbPnPMnQueryRemoveDevice(pDevExt, pIrp); + + case IRP_MN_REMOVE_DEVICE: + return vboxUsbPnPMnRemoveDevice(pDevExt, pIrp); + + case IRP_MN_CANCEL_REMOVE_DEVICE: + return vboxUsbPnPMnCancelRemoveDevice(pDevExt, pIrp); + + case IRP_MN_SURPRISE_REMOVAL: + return vboxUsbPnPMnSurpriseRemoval(pDevExt, pIrp); + + case IRP_MN_QUERY_CAPABILITIES: + return vboxUsbPnPMnQueryCapabilities(pDevExt, pIrp); + + default: + return vboxUsbPnPMnDefault(pDevExt, pIrp); + } +} + diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.h b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.h new file mode 100644 index 00000000..c1799080 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPnP.h @@ -0,0 +1,46 @@ +/* $Id: VBoxUsbPnP.h $ */ +/** @file + * USB PnP Handling + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbPnP_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbPnP_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif +#include "VBoxUsbCmn.h" + +DECLHIDDEN(NTSTATUS) vboxUsbDispatchPnP(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbPnP_h */ 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..35b57159 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.cpp @@ -0,0 +1,427 @@ +/* $Id: VBoxUsbPwr.cpp $ */ +/** @file + * USB Power state Handling + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#include "VBoxUsbCmn.h" + +#include + +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); + } +} + diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.h b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.h new file mode 100644 index 00000000..792187ed --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbPwr.h @@ -0,0 +1,51 @@ +/* $Id: VBoxUsbPwr.h $ */ +/** @file + * USB Power state Handling + */ +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbPwr_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbPwr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +typedef struct VBOXUSB_PWRSTATE +{ + POWER_STATE PowerState; + ULONG PowerDownLevel; +} VBOXUSB_PWRSTATE, *PVBOXUSB_PWRSTATE; + +DECLHIDDEN(VOID) vboxUsbPwrStateInit(PVBOXUSBDEV_EXT pDevExt); +DECLHIDDEN(NTSTATUS) vboxUsbDispatchPower(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp); + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbPwr_h */ diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.cpp b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.cpp new file mode 100644 index 00000000..f4e82a33 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.cpp @@ -0,0 +1,1593 @@ +/* $Id: VBoxUsbRt.cpp $ */ +/** @file + * VBox USB R0 runtime + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "VBoxUsbCmn.h" +#include "../cmn/VBoxUsbIdc.h" +#include "../cmn/VBoxUsbTool.h" + +#include +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define _USBD_ /** @todo r=bird: What is this?? */ + +#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 + +#define VBOXUSB_MAGIC 0xABCF1423 + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct VBOXUSB_URB_CONTEXT +{ + PURB pUrb; + PMDL pMdlBuf; + PVBOXUSBDEV_EXT pDevExt; + PVOID pOut; + ULONG ulTransferType; + ULONG ulMagic; +} VBOXUSB_URB_CONTEXT, * PVBOXUSB_URB_CONTEXT; + +typedef struct VBOXUSB_SETUP +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} VBOXUSB_SETUP, *PVBOXUSB_SETUP; + + + +static bool vboxUsbRtCtxSetOwner(PVBOXUSBDEV_EXT pDevExt, PFILE_OBJECT pFObj) +{ + bool fRc = ASMAtomicCmpXchgPtr(&pDevExt->Rt.pOwner, pFObj, NULL); + if (fRc) + LogFunc(("pDevExt (0x%x) Owner(0x%x) acquired\n", pFObj)); + else + LogFunc(("pDevExt (0x%x) Owner(0x%x) FAILED!!\n", pFObj)); + return fRc; +} + +static bool vboxUsbRtCtxReleaseOwner(PVBOXUSBDEV_EXT pDevExt, PFILE_OBJECT pFObj) +{ + bool fRc = ASMAtomicCmpXchgPtr(&pDevExt->Rt.pOwner, NULL, pFObj); + if (fRc) + LogFunc(("pDevExt (0x%x) Owner(0x%x) released\n", pFObj)); + else + LogFunc(("pDevExt (0x%x) Owner(0x%x) release: is NOT an owner\n", pFObj)); + return fRc; +} + +static bool vboxUsbRtCtxIsOwner(PVBOXUSBDEV_EXT pDevExt, PFILE_OBJECT pFObj) +{ + PFILE_OBJECT pOwner = (PFILE_OBJECT)ASMAtomicReadPtr((void *volatile *)(&pDevExt->Rt.pOwner)); + return pOwner == pFObj; +} + +static NTSTATUS vboxUsbRtIdcSubmit(ULONG uCtl, void *pvBuffer) +{ + /* we just reuse the standard usb tooling for simplicity here */ + NTSTATUS Status = VBoxUsbToolIoInternalCtlSendSync(g_VBoxUsbGlobals.RtIdc.pDevice, uCtl, pvBuffer, NULL); + Assert(Status == STATUS_SUCCESS); + return Status; +} + +static NTSTATUS vboxUsbRtIdcInit() +{ + UNICODE_STRING UniName; + RtlInitUnicodeString(&UniName, USBMON_DEVICE_NAME_NT); + NTSTATUS Status = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_VBoxUsbGlobals.RtIdc.pFile, &g_VBoxUsbGlobals.RtIdc.pDevice); + if (NT_SUCCESS(Status)) + { + VBOXUSBIDC_VERSION Version; + vboxUsbRtIdcSubmit(VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION, &Version); + if (NT_SUCCESS(Status)) + { + if ( Version.u32Major == VBOXUSBIDC_VERSION_MAJOR +#if VBOXUSBIDC_VERSION_MINOR != 0 + && Version.u32Minor >= VBOXUSBIDC_VERSION_MINOR +#endif + ) + return STATUS_SUCCESS; + AssertFailed(); + } + else + { + AssertFailed(); + } + + /* this will as well dereference the dev obj */ + ObDereferenceObject(g_VBoxUsbGlobals.RtIdc.pFile); + } + else + { + AssertFailed(); + } + + memset(&g_VBoxUsbGlobals.RtIdc, 0, sizeof (g_VBoxUsbGlobals.RtIdc)); + return Status; +} + +static VOID vboxUsbRtIdcTerm() +{ + Assert(g_VBoxUsbGlobals.RtIdc.pFile); + Assert(g_VBoxUsbGlobals.RtIdc.pDevice); + ObDereferenceObject(g_VBoxUsbGlobals.RtIdc.pFile); + memset(&g_VBoxUsbGlobals.RtIdc, 0, sizeof (g_VBoxUsbGlobals.RtIdc)); +} + +static NTSTATUS vboxUsbRtIdcReportDevStart(PDEVICE_OBJECT pPDO, HVBOXUSBIDCDEV *phDev) +{ + VBOXUSBIDC_PROXY_STARTUP Start; + Start.u.pPDO = pPDO; + + *phDev = NULL; + + NTSTATUS Status = vboxUsbRtIdcSubmit(VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP, &Start); + Assert(Status == STATUS_SUCCESS); + if (!NT_SUCCESS(Status)) + return Status; + + *phDev = Start.u.hDev; + return STATUS_SUCCESS; +} + +static NTSTATUS vboxUsbRtIdcReportDevStop(HVBOXUSBIDCDEV hDev) +{ + VBOXUSBIDC_PROXY_TEARDOWN Stop; + Stop.hDev = hDev; + + NTSTATUS Status = vboxUsbRtIdcSubmit(VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN, &Stop); + Assert(Status == STATUS_SUCCESS); + return Status; +} + + +DECLHIDDEN(NTSTATUS) vboxUsbRtGlobalsInit() +{ + return vboxUsbRtIdcInit(); +} + +DECLHIDDEN(VOID) vboxUsbRtGlobalsTerm() +{ + vboxUsbRtIdcTerm(); +} + + +DECLHIDDEN(NTSTATUS) vboxUsbRtInit(PVBOXUSBDEV_EXT pDevExt) +{ + RtlZeroMemory(&pDevExt->Rt, sizeof (pDevExt->Rt)); + NTSTATUS Status = IoRegisterDeviceInterface(pDevExt->pPDO, &GUID_CLASS_VBOXUSB, + NULL, /* IN PUNICODE_STRING ReferenceString OPTIONAL */ + &pDevExt->Rt.IfName); + Assert(Status == STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + { + Status = vboxUsbRtIdcReportDevStart(pDevExt->pPDO, &pDevExt->Rt.hMonDev); + Assert(Status == STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + { + Assert(pDevExt->Rt.hMonDev); + return STATUS_SUCCESS; + } + + NTSTATUS tmpStatus = IoSetDeviceInterfaceState(&pDevExt->Rt.IfName, FALSE); + Assert(tmpStatus == STATUS_SUCCESS); + if (NT_SUCCESS(tmpStatus)) + { + RtlFreeUnicodeString(&pDevExt->Rt.IfName); + } + } + return Status; +} + +/** + * Free cached USB device/configuration descriptors + * + * @param pDevExt USB DevExt pointer + */ +static void vboxUsbRtFreeCachedDescriptors(PVBOXUSBDEV_EXT pDevExt) +{ + if (pDevExt->Rt.devdescr) + { + vboxUsbMemFree(pDevExt->Rt.devdescr); + pDevExt->Rt.devdescr = NULL; + } + for (ULONG i = 0; i < VBOXUSBRT_MAX_CFGS; ++i) + { + if (pDevExt->Rt.cfgdescr[i]) + { + vboxUsbMemFree(pDevExt->Rt.cfgdescr[i]); + pDevExt->Rt.cfgdescr[i] = NULL; + } + } +} + +/** + * Free per-device interface info + * + * @param pDevExt USB DevExt pointer + * @param fAbortPipes If true, also abort any open pipes + */ +static void vboxUsbRtFreeInterfaces(PVBOXUSBDEV_EXT pDevExt, BOOLEAN fAbortPipes) +{ + unsigned i; + unsigned j; + + /* + * Free old interface info + */ + if (pDevExt->Rt.pVBIfaceInfo) + { + for (i=0;iRt.uNumInterfaces;i++) + { + if (pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo) + { + if (fAbortPipes) + { + for (j=0; jRt.pVBIfaceInfo[i].pInterfaceInfo->NumberOfPipes; j++) + { + Log(("Aborting Pipe %d handle %x address %x\n", j, + pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].PipeHandle, + pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].EndpointAddress)); + VBoxUsbToolPipeClear(pDevExt->pLowerDO, pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].PipeHandle, FALSE); + } + } + vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo); + } + pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo = NULL; + if (pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo) + vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo); + pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo = NULL; + } + vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo); + pDevExt->Rt.pVBIfaceInfo = NULL; + } +} + +DECLHIDDEN(VOID) vboxUsbRtClear(PVBOXUSBDEV_EXT pDevExt) +{ + vboxUsbRtFreeCachedDescriptors(pDevExt); + vboxUsbRtFreeInterfaces(pDevExt, FALSE); +} + +DECLHIDDEN(NTSTATUS) vboxUsbRtRm(PVBOXUSBDEV_EXT pDevExt) +{ + if (!pDevExt->Rt.IfName.Buffer) + return STATUS_SUCCESS; + + NTSTATUS Status = vboxUsbRtIdcReportDevStop(pDevExt->Rt.hMonDev); + Assert(Status == STATUS_SUCCESS); + Status = IoSetDeviceInterfaceState(&pDevExt->Rt.IfName, FALSE); + Assert(Status == STATUS_SUCCESS); + if (NT_SUCCESS(Status)) + { + RtlFreeUnicodeString(&pDevExt->Rt.IfName); + pDevExt->Rt.IfName.Buffer = NULL; + } + return Status; +} + +DECLHIDDEN(NTSTATUS) vboxUsbRtStart(PVBOXUSBDEV_EXT pDevExt) +{ + NTSTATUS Status = IoSetDeviceInterfaceState(&pDevExt->Rt.IfName, TRUE); + Assert(Status == STATUS_SUCCESS); + return Status; +} + +static NTSTATUS vboxUsbRtCacheDescriptors(PVBOXUSBDEV_EXT pDevExt) +{ + NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; +// uint32_t uTotalLength; +// unsigned i; + + /* Read device descriptor */ + Assert(!pDevExt->Rt.devdescr); + pDevExt->Rt.devdescr = (PUSB_DEVICE_DESCRIPTOR)vboxUsbMemAlloc(sizeof (USB_DEVICE_DESCRIPTOR)); + if (pDevExt->Rt.devdescr) + { + memset(pDevExt->Rt.devdescr, 0, sizeof (USB_DEVICE_DESCRIPTOR)); + Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDevExt->Rt.devdescr, sizeof (USB_DEVICE_DESCRIPTOR), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, RT_INDEFINITE_WAIT); + if (NT_SUCCESS(Status)) + { + Assert(pDevExt->Rt.devdescr->bNumConfigurations > 0); + PUSB_CONFIGURATION_DESCRIPTOR pDr = (PUSB_CONFIGURATION_DESCRIPTOR)vboxUsbMemAlloc(sizeof (USB_CONFIGURATION_DESCRIPTOR)); + Assert(pDr); + if (pDr) + { + UCHAR i = 0; + for (; i < pDevExt->Rt.devdescr->bNumConfigurations; ++i) + { + Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDr, sizeof (USB_CONFIGURATION_DESCRIPTOR), USB_CONFIGURATION_DESCRIPTOR_TYPE, i, 0, RT_INDEFINITE_WAIT); + if (!NT_SUCCESS(Status)) + { + break; + } + + USHORT uTotalLength = pDr->wTotalLength; + pDevExt->Rt.cfgdescr[i] = (PUSB_CONFIGURATION_DESCRIPTOR)vboxUsbMemAlloc(uTotalLength); + if (!pDevExt->Rt.cfgdescr[i]) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDevExt->Rt.cfgdescr[i], uTotalLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, i, 0, RT_INDEFINITE_WAIT); + if (!NT_SUCCESS(Status)) + { + break; + } + } + + vboxUsbMemFree(pDr); + + if (NT_SUCCESS(Status)) + return Status; + + /* recources will be freed in vboxUsbRtFreeCachedDescriptors below */ + } + } + + vboxUsbRtFreeCachedDescriptors(pDevExt); + } + + /* shoud be only on fail here */ + Assert(!NT_SUCCESS(Status)); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchClaimDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + PUSBSUP_CLAIMDEV pDev = (PUSBSUP_CLAIMDEV)pIrp->AssociatedIrp.SystemBuffer; + ULONG cbOut = 0; + NTSTATUS Status = STATUS_SUCCESS; + + do + { + if (!pFObj) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if ( !pDev + || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pDev) + || pSl->Parameters.DeviceIoControl.OutputBufferLength != sizeof (*pDev)) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (!vboxUsbRtCtxSetOwner(pDevExt, pFObj)) + { + AssertFailed(); + pDev->fClaimed = false; + cbOut = sizeof (*pDev); + break; + } + + vboxUsbRtFreeCachedDescriptors(pDevExt); + Status = vboxUsbRtCacheDescriptors(pDevExt); + if (NT_SUCCESS(Status)) + { + pDev->fClaimed = true; + cbOut = sizeof (*pDev); + } + } while (0); + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, cbOut); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchReleaseDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + NTSTATUS Status= STATUS_SUCCESS; + + if (vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + vboxUsbRtFreeCachedDescriptors(pDevExt); + bool fRc = vboxUsbRtCtxReleaseOwner(pDevExt, pFObj); + Assert(fRc); NOREF(fRc); + } + else + { + AssertFailed(); + Status = STATUS_ACCESS_DENIED; + } + + VBoxDrvToolIoComplete(pIrp, STATUS_SUCCESS, 0); + vboxUsbDdiStateRelease(pDevExt); + return STATUS_SUCCESS; +} + +static NTSTATUS vboxUsbRtGetDeviceDescription(PVBOXUSBDEV_EXT pDevExt) +{ + NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; + PUSB_DEVICE_DESCRIPTOR pDr = (PUSB_DEVICE_DESCRIPTOR)vboxUsbMemAllocZ(sizeof (USB_DEVICE_DESCRIPTOR)); + if (pDr) + { + Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDr, sizeof(*pDr), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, RT_INDEFINITE_WAIT); + if (NT_SUCCESS(Status)) + { + pDevExt->Rt.idVendor = pDr->idVendor; + pDevExt->Rt.idProduct = pDr->idProduct; + pDevExt->Rt.bcdDevice = pDr->bcdDevice; + pDevExt->Rt.szSerial[0] = 0; + + if (pDr->iSerialNumber +#ifdef DEBUG + || pDr->iProduct || pDr->iManufacturer +#endif + ) + { + int langId; + Status = VBoxUsbToolGetLangID(pDevExt->pLowerDO, &langId, RT_INDEFINITE_WAIT); + if (NT_SUCCESS(Status)) + { + Status = VBoxUsbToolGetStringDescriptor(pDevExt->pLowerDO, pDevExt->Rt.szSerial, sizeof (pDevExt->Rt.szSerial), + pDr->iSerialNumber, langId, RT_INDEFINITE_WAIT); + } + else + { + Status = STATUS_SUCCESS; + } + } + } + vboxUsbMemFree(pDr); + } + + return Status; +} + +static NTSTATUS vboxUsbRtDispatchGetDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PUSBSUP_GETDEV pDev = (PUSBSUP_GETDEV)pIrp->AssociatedIrp.SystemBuffer; + ULONG cbOut = 0; + + /* don't check for owner since this request is allowed for non-owners as well */ + NTSTATUS Status; + if ( pDev + && pSl->Parameters.DeviceIoControl.InputBufferLength == sizeof(*pDev) + && pSl->Parameters.DeviceIoControl.OutputBufferLength == sizeof(*pDev)) + { + /* Even if we don't return it, we need to query the HS flag for later use. */ + Status = VBoxUsbToolGetDeviceSpeed(pDevExt->pLowerDO, &pDevExt->Rt.fIsHighSpeed); + if (NT_SUCCESS(Status)) + { + pDev->hDevice = pDevExt->Rt.hMonDev; + cbOut = sizeof (*pDev); + } + } + else + Status = STATUS_INVALID_PARAMETER; + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, cbOut); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchUsbReset(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + NTSTATUS rcNt; + if (pFObj) + { + if (vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + if ( pIrp->AssociatedIrp.SystemBuffer == NULL + && pSl->Parameters.DeviceIoControl.InputBufferLength == 0 + && pSl->Parameters.DeviceIoControl.OutputBufferLength == 0) + { + rcNt = VBoxUsbToolIoInternalCtlSendSync(pDevExt->pLowerDO, IOCTL_INTERNAL_USB_RESET_PORT, NULL, NULL); + Assert(NT_SUCCESS(rcNt)); + } + else + { + AssertFailed(); + rcNt = STATUS_INVALID_PARAMETER; + } + } + else + { + AssertFailed(); + rcNt = STATUS_ACCESS_DENIED; + } + } + else + { + AssertFailed(); + rcNt = STATUS_INVALID_PARAMETER; + } + + Assert(rcNt != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, rcNt, 0); + vboxUsbDdiStateRelease(pDevExt); + return rcNt; +} + +static PUSB_CONFIGURATION_DESCRIPTOR vboxUsbRtFindConfigDesc(PVBOXUSBDEV_EXT pDevExt, uint8_t uConfiguration) +{ + PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL; + + for (ULONG i = 0; i < VBOXUSBRT_MAX_CFGS; ++i) + { + if (pDevExt->Rt.cfgdescr[i]) + { + if (pDevExt->Rt.cfgdescr[i]->bConfigurationValue == uConfiguration) + { + pCfgDr = pDevExt->Rt.cfgdescr[i]; + break; + } + } + } + + return pCfgDr; +} + +static NTSTATUS vboxUsbRtSetConfig(PVBOXUSBDEV_EXT pDevExt, uint8_t uConfiguration) +{ + PURB pUrb = NULL; + NTSTATUS Status = STATUS_SUCCESS; + uint32_t i; + + if (!uConfiguration) + { + pUrb = VBoxUsbToolUrbAllocZ(URB_FUNCTION_SELECT_CONFIGURATION, sizeof (struct _URB_SELECT_CONFIGURATION)); + if (!pUrb) + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbAlloc failed\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + vboxUsbRtFreeInterfaces(pDevExt, TRUE); + + pUrb->UrbSelectConfiguration.ConfigurationDescriptor = NULL; + + Status = VBoxUsbToolUrbPost(pDevExt->pLowerDO, pUrb, RT_INDEFINITE_WAIT); + if (NT_SUCCESS(Status) && USBD_SUCCESS(pUrb->UrbHeader.Status)) + { + pDevExt->Rt.hConfiguration = pUrb->UrbSelectConfiguration.ConfigurationHandle; + pDevExt->Rt.uConfigValue = uConfiguration; + } + else + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbPost failed Status (0x%x), usb Status (0x%x)\n", Status, pUrb->UrbHeader.Status)); + } + + VBoxUsbToolUrbFree(pUrb); + + return Status; + } + +/** @todo r=bird: Need to write a script for fixing these kind of clueless use + * of AssertMsgFailed (into AssertMsgReturn). The __FUNCTION__ is just + * the topping it off - the assertion message includes function, file and + * line number. Duh! */ + PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = vboxUsbRtFindConfigDesc(pDevExt, uConfiguration); + if (!pCfgDr) + { + AssertMsgFailed((__FUNCTION__": VBoxUSBFindConfigDesc did not find cfg (%d)\n", uConfiguration)); + return STATUS_INVALID_PARAMETER; + } + + PUSBD_INTERFACE_LIST_ENTRY pIfLe = (PUSBD_INTERFACE_LIST_ENTRY)vboxUsbMemAllocZ((pCfgDr->bNumInterfaces + 1) * sizeof(USBD_INTERFACE_LIST_ENTRY)); + if (!pIfLe) + { + AssertMsgFailed((__FUNCTION__": vboxUsbMemAllocZ for pIfLe failed\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + for (i = 0; i < pCfgDr->bNumInterfaces; i++) + { + pIfLe[i].InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(pCfgDr, pCfgDr, i, 0, -1, -1, -1); + if (!pIfLe[i].InterfaceDescriptor) + { + AssertMsgFailed((__FUNCTION__": interface %d not found\n", i)); + Status = STATUS_INVALID_PARAMETER; + break; + } + } + pIfLe[pCfgDr->bNumInterfaces].InterfaceDescriptor = NULL; + + if (NT_SUCCESS(Status)) + { + pUrb = USBD_CreateConfigurationRequestEx(pCfgDr, pIfLe); + if (pUrb) + { + Status = VBoxUsbToolUrbPost(pDevExt->pLowerDO, pUrb, RT_INDEFINITE_WAIT); + if (NT_SUCCESS(Status) && USBD_SUCCESS(pUrb->UrbHeader.Status)) + { + vboxUsbRtFreeInterfaces(pDevExt, FALSE); + + pDevExt->Rt.hConfiguration = pUrb->UrbSelectConfiguration.ConfigurationHandle; + pDevExt->Rt.uConfigValue = uConfiguration; + pDevExt->Rt.uNumInterfaces = pCfgDr->bNumInterfaces; + + pDevExt->Rt.pVBIfaceInfo = (VBOXUSB_IFACE_INFO*)vboxUsbMemAllocZ(pDevExt->Rt.uNumInterfaces * sizeof (VBOXUSB_IFACE_INFO)); + if (pDevExt->Rt.pVBIfaceInfo) + { + Assert(NT_SUCCESS(Status)); + for (i = 0; i < pDevExt->Rt.uNumInterfaces; i++) + { + size_t uTotalIfaceInfoLength = GET_USBD_INTERFACE_SIZE(pIfLe[i].Interface->NumberOfPipes); + pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo = (PUSBD_INTERFACE_INFORMATION)vboxUsbMemAlloc(uTotalIfaceInfoLength); + if (!pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo) + { + AssertMsgFailed((__FUNCTION__": vboxUsbMemAlloc failed\n")); + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + if (pIfLe[i].Interface->NumberOfPipes > 0) + { + pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo = (VBOXUSB_PIPE_INFO *)vboxUsbMemAlloc(pIfLe[i].Interface->NumberOfPipes * sizeof(VBOXUSB_PIPE_INFO)); + if (!pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo) + { + AssertMsgFailed((__FUNCTION__": vboxUsbMemAlloc failed\n")); + Status = STATUS_NO_MEMORY; + break; + } + } + else + { + pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo = NULL; + } + + RtlCopyMemory(pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo, pIfLe[i].Interface, uTotalIfaceInfoLength); + + for (ULONG j = 0; j < pIfLe[i].Interface->NumberOfPipes; j++) + { + pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j].EndpointAddress = pIfLe[i].Interface->Pipes[j].EndpointAddress; + pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j].NextScheduledFrame = 0; + } + } + +// if (NT_SUCCESS(Status)) +// { +// +// } + } + else + { + AssertMsgFailed((__FUNCTION__": vboxUsbMemAllocZ failed\n")); + Status = STATUS_NO_MEMORY; + } + } + else + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbPost failed Status (0x%x), usb Status (0x%x)\n", Status, pUrb->UrbHeader.Status)); + } + ExFreePool(pUrb); + } + else + { + AssertMsgFailed((__FUNCTION__": USBD_CreateConfigurationRequestEx failed\n")); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + vboxUsbMemFree(pIfLe); + + return Status; +} + +static NTSTATUS vboxUsbRtDispatchUsbSetConfig(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + PUSBSUP_SET_CONFIG pCfg = (PUSBSUP_SET_CONFIG)pIrp->AssociatedIrp.SystemBuffer; + NTSTATUS Status = STATUS_SUCCESS; + + do + { + if (!pFObj) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + AssertFailed(); + Status = STATUS_ACCESS_DENIED; + break; + } + + if ( !pCfg + || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pCfg) + || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0) + { + AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + Status = vboxUsbRtSetConfig(pDevExt, pCfg->bConfigurationValue); + } while (0); + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtSetInterface(PVBOXUSBDEV_EXT pDevExt, uint32_t InterfaceNumber, int AlternateSetting) +{ + AssertMsgReturn(pDevExt->Rt.uConfigValue, ("Can't select an interface without an active configuration\n"), + STATUS_INVALID_PARAMETER); + AssertMsgReturn(InterfaceNumber < pDevExt->Rt.uNumInterfaces, ("InterfaceNumber %d too high!!\n", InterfaceNumber), + STATUS_INVALID_PARAMETER); + PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = vboxUsbRtFindConfigDesc(pDevExt, pDevExt->Rt.uConfigValue); + AssertMsgReturn(pCfgDr, ("configuration %d not found!!\n", pDevExt->Rt.uConfigValue), + STATUS_INVALID_PARAMETER); + PUSB_INTERFACE_DESCRIPTOR pIfDr = USBD_ParseConfigurationDescriptorEx(pCfgDr, pCfgDr, InterfaceNumber, AlternateSetting, -1, -1, -1); + AssertMsgReturn(pIfDr, ("invalid interface %d or alternate setting %d\n", InterfaceNumber, AlternateSetting), + STATUS_UNSUCCESSFUL); + + USHORT uUrbSize = GET_SELECT_INTERFACE_REQUEST_SIZE(pIfDr->bNumEndpoints); + ULONG uTotalIfaceInfoLength = GET_USBD_INTERFACE_SIZE(pIfDr->bNumEndpoints); + NTSTATUS Status = STATUS_SUCCESS; + PURB pUrb; + PUSBD_INTERFACE_INFORMATION pNewIFInfo = NULL; + VBOXUSB_PIPE_INFO *pNewPipeInfo = NULL; + + if (pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo) + { + /* Clear pipes associated with the interface, else Windows may hang. */ + for (ULONG i = 0; i < pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo->NumberOfPipes; i++) + VBoxUsbToolPipeClear(pDevExt->pLowerDO, pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo->Pipes[i].PipeHandle, FALSE); + } + + do { + /* First allocate all the structures we'll need. */ + pUrb = VBoxUsbToolUrbAllocZ(0, uUrbSize); + if (!pUrb) + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbAllocZ failed\n")); + Status = STATUS_NO_MEMORY; + break; + } + + pNewIFInfo = (PUSBD_INTERFACE_INFORMATION)vboxUsbMemAlloc(uTotalIfaceInfoLength); + if (!pNewIFInfo) + { + AssertMsgFailed((__FUNCTION__": Failed allocating interface storage\n")); + Status = STATUS_NO_MEMORY; + break; + } + + if (pIfDr->bNumEndpoints > 0) + { + pNewPipeInfo = (VBOXUSB_PIPE_INFO *)vboxUsbMemAlloc(pIfDr->bNumEndpoints * sizeof(VBOXUSB_PIPE_INFO)); + if (!pNewPipeInfo) + { + AssertMsgFailed((__FUNCTION__": Failed allocating pipe info storage\n")); + Status = STATUS_NO_MEMORY; + break; + } + } + else + pNewPipeInfo = NULL; + + /* Now that we have all the bits, select the interface. */ + UsbBuildSelectInterfaceRequest(pUrb, uUrbSize, pDevExt->Rt.hConfiguration, InterfaceNumber, AlternateSetting); + pUrb->UrbSelectInterface.Interface.Length = GET_USBD_INTERFACE_SIZE(pIfDr->bNumEndpoints); + + Status = VBoxUsbToolUrbPost(pDevExt->pLowerDO, pUrb, RT_INDEFINITE_WAIT); + if (NT_SUCCESS(Status) && USBD_SUCCESS(pUrb->UrbHeader.Status)) + { + /* Free the old memory and put new in. */ + if (pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo) + vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo); + pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo = pNewIFInfo; + if (pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo) + vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo); + pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo = pNewPipeInfo; + pNewPipeInfo = NULL; pNewIFInfo = NULL; /* Don't try to free it again. */ + + USBD_INTERFACE_INFORMATION *pIfInfo = &pUrb->UrbSelectInterface.Interface; + memcpy(pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo, pIfInfo, GET_USBD_INTERFACE_SIZE(pIfDr->bNumEndpoints)); + + Assert(pIfInfo->NumberOfPipes == pIfDr->bNumEndpoints); + for (ULONG i = 0; i < pIfInfo->NumberOfPipes; i++) + { + pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo[i].EndpointAddress = pIfInfo->Pipes[i].EndpointAddress; + pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo[i].NextScheduledFrame = 0; + } + } + else + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbPost failed Status (0x%x) usb Status (0x%x)\n", Status, pUrb->UrbHeader.Status)); + } + } while (0); + + /* Clean up. */ + if (pUrb) + VBoxUsbToolUrbFree(pUrb); + if (pNewIFInfo) + vboxUsbMemFree(pNewIFInfo); + if (pNewPipeInfo) + vboxUsbMemFree(pNewPipeInfo); + + return Status; +} + +static NTSTATUS vboxUsbRtDispatchUsbSelectInterface(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + PUSBSUP_SELECT_INTERFACE pIf = (PUSBSUP_SELECT_INTERFACE)pIrp->AssociatedIrp.SystemBuffer; + NTSTATUS Status; + + do + { + if (!pFObj) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + AssertFailed(); + Status = STATUS_ACCESS_DENIED; + break; + } + + if ( !pIf + || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pIf) + || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0) + { + AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + Status = vboxUsbRtSetInterface(pDevExt, pIf->bInterfaceNumber, pIf->bAlternateSetting); + } while (0); + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static HANDLE vboxUsbRtGetPipeHandle(PVBOXUSBDEV_EXT pDevExt, uint32_t EndPointAddress) +{ + if (EndPointAddress == 0) + return pDevExt->Rt.hPipe0; + + for (ULONG i = 0; i < pDevExt->Rt.uNumInterfaces; i++) + { + for (ULONG j = 0; j < pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->NumberOfPipes; j++) + { + /* Note that bit 7 determines pipe direction, but is still significant + * because endpoints may be numbered like 0x01, 0x81, 0x02, 0x82 etc. + */ + if (pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].EndpointAddress == EndPointAddress) + return pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].PipeHandle; + } + } + return 0; +} + +static VBOXUSB_PIPE_INFO* vboxUsbRtGetPipeInfo(PVBOXUSBDEV_EXT pDevExt, uint32_t EndPointAddress) +{ + for (ULONG i = 0; i < pDevExt->Rt.uNumInterfaces; i++) + { + for (ULONG j = 0; j < pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->NumberOfPipes; j++) + { + if (pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j].EndpointAddress == EndPointAddress) + return &pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j]; + } + } + return NULL; +} + + + +static NTSTATUS vboxUsbRtClearEndpoint(PVBOXUSBDEV_EXT pDevExt, uint32_t EndPointAddress, bool fReset) +{ + NTSTATUS Status = VBoxUsbToolPipeClear(pDevExt->pLowerDO, vboxUsbRtGetPipeHandle(pDevExt, EndPointAddress), fReset); + if (!NT_SUCCESS(Status)) + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolPipeClear failed Status (0x%x)\n", Status)); + } + + return Status; +} + +static NTSTATUS vboxUsbRtDispatchUsbClearEndpoint(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + PUSBSUP_CLEAR_ENDPOINT pCe = (PUSBSUP_CLEAR_ENDPOINT)pIrp->AssociatedIrp.SystemBuffer; + NTSTATUS Status; + + do + { + if (!pFObj) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + AssertFailed(); + Status = STATUS_ACCESS_DENIED; + break; + } + + if ( !pCe + || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pCe) + || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0) + { + AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + Status = vboxUsbRtClearEndpoint(pDevExt, pCe->bEndpoint, TRUE); + } while (0); + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchUsbAbortEndpoint(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + PUSBSUP_CLEAR_ENDPOINT pCe = (PUSBSUP_CLEAR_ENDPOINT)pIrp->AssociatedIrp.SystemBuffer; + NTSTATUS Status; + + do + { + if (!pFObj) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + AssertFailed(); + Status = STATUS_ACCESS_DENIED; + break; + } + + if ( !pCe + || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pCe) + || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0) + { + AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + Status = vboxUsbRtClearEndpoint(pDevExt, pCe->bEndpoint, FALSE); + } while (0); + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtUrbSendCompletion(PDEVICE_OBJECT pDevObj, IRP *pIrp, void *pvContext) +{ + RT_NOREF1(pDevObj); + + if (!pvContext) + { + AssertMsgFailed((__FUNCTION__": context is NULL\n")); + pIrp->IoStatus.Information = 0; + return STATUS_CONTINUE_COMPLETION; + } + + PVBOXUSB_URB_CONTEXT pContext = (PVBOXUSB_URB_CONTEXT)pvContext; + + if (pContext->ulMagic != VBOXUSB_MAGIC) + { + AssertMsgFailed((__FUNCTION__": Invalid context magic\n")); + pIrp->IoStatus.Information = 0; + return STATUS_CONTINUE_COMPLETION; + } + + PURB pUrb = pContext->pUrb; + PMDL pMdlBuf = pContext->pMdlBuf; + PUSBSUP_URB pUrbInfo = (PUSBSUP_URB)pContext->pOut; + PVBOXUSBDEV_EXT pDevExt = pContext->pDevExt; + + if (!pUrb || !pMdlBuf || !pUrbInfo || !pDevExt) + { + AssertMsgFailed((__FUNCTION__": Invalid args\n")); + if (pDevExt) + vboxUsbDdiStateRelease(pDevExt); + pIrp->IoStatus.Information = 0; + return STATUS_CONTINUE_COMPLETION; + } + + NTSTATUS Status = pIrp->IoStatus.Status; + if (Status == STATUS_SUCCESS) + { + switch(pUrb->UrbHeader.Status) + { + case USBD_STATUS_CRC: + pUrbInfo->error = USBSUP_XFER_CRC; + break; + case USBD_STATUS_SUCCESS: + pUrbInfo->error = USBSUP_XFER_OK; + break; + case USBD_STATUS_STALL_PID: + pUrbInfo->error = USBSUP_XFER_STALL; + break; + case USBD_STATUS_INVALID_URB_FUNCTION: + case USBD_STATUS_INVALID_PARAMETER: + AssertMsgFailed((__FUNCTION__": sw error, urb Status (0x%x)\n", pUrb->UrbHeader.Status)); + case USBD_STATUS_DEV_NOT_RESPONDING: + default: + pUrbInfo->error = USBSUP_XFER_DNR; + break; + } + + switch(pContext->ulTransferType) + { + case USBSUP_TRANSFER_TYPE_MSG: + pUrbInfo->len = pUrb->UrbControlTransfer.TransferBufferLength; + /* QUSB_TRANSFER_TYPE_MSG is a control transfer, but it is special + * the first 8 bytes of the buffer is the setup packet so the real + * data length is therefore urb->len - 8 + */ + pUrbInfo->len += sizeof (pUrb->UrbControlTransfer.SetupPacket); + + /* If a control URB was successfully completed on the default control + * pipe, stash away the handle. When submitting the URB, we don't need + * to know (and initially don't have) the handle. If we want to abort + * the default control pipe, we *have* to have a handle. This is how we + * find out what the handle is. + */ + if (!pUrbInfo->ep && (pDevExt->Rt.hPipe0 == NULL)) + { + pDevExt->Rt.hPipe0 = pUrb->UrbControlTransfer.PipeHandle; + } + + break; + case USBSUP_TRANSFER_TYPE_ISOC: + pUrbInfo->len = pUrb->UrbIsochronousTransfer.TransferBufferLength; + break; + case USBSUP_TRANSFER_TYPE_BULK: + case USBSUP_TRANSFER_TYPE_INTR: + if (pUrbInfo->dir == USBSUP_DIRECTION_IN && pUrbInfo->error == USBSUP_XFER_OK + && !(pUrbInfo->flags & USBSUP_FLAG_SHORT_OK) + && pUrbInfo->len > pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength + ) + { + /* If we don't use the USBD_SHORT_TRANSFER_OK flag, the returned buffer lengths are + * wrong for short transfers (always a multiple of max packet size?). So we just figure + * out if this was a data underrun on our own. + */ + pUrbInfo->error = USBSUP_XFER_UNDERRUN; + } + pUrbInfo->len = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength; + break; + default: + break; + } + } + else + { + pUrbInfo->len = 0; + + LogFunc(("URB failed Status (0x%x) urb Status (0x%x)\n", Status, pUrb->UrbHeader.Status)); +#ifdef DEBUG + switch(pContext->ulTransferType) + { + case USBSUP_TRANSFER_TYPE_MSG: + LogRel(("Msg (CTRL) length=%d\n", pUrb->UrbControlTransfer.TransferBufferLength)); + break; + case USBSUP_TRANSFER_TYPE_ISOC: + LogRel(("ISOC length=%d\n", pUrb->UrbIsochronousTransfer.TransferBufferLength)); + break; + case USBSUP_TRANSFER_TYPE_BULK: + case USBSUP_TRANSFER_TYPE_INTR: + LogRel(("BULK/INTR length=%d\n", pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength)); + break; + } +#endif + switch(pUrb->UrbHeader.Status) + { + case USBD_STATUS_CRC: + pUrbInfo->error = USBSUP_XFER_CRC; + Status = STATUS_SUCCESS; + break; + case USBD_STATUS_STALL_PID: + pUrbInfo->error = USBSUP_XFER_STALL; + Status = STATUS_SUCCESS; + break; + case USBD_STATUS_DEV_NOT_RESPONDING: + case USBD_STATUS_DEVICE_GONE: + pUrbInfo->error = USBSUP_XFER_DNR; + Status = STATUS_SUCCESS; + break; + case ((USBD_STATUS)0xC0010000L): // USBD_STATUS_CANCELED - too bad usbdi.h and usb.h aren't consistent! + /// @todo What the heck are we really supposed to do here? + pUrbInfo->error = USBSUP_XFER_STALL; + Status = STATUS_SUCCESS; + break; + case USBD_STATUS_BAD_START_FRAME: // This one really shouldn't happen + case USBD_STATUS_ISOCH_REQUEST_FAILED: + pUrbInfo->error = USBSUP_XFER_NAC; + Status = STATUS_SUCCESS; + break; + default: + AssertMsgFailed((__FUNCTION__": err Status (0x%x) (0x%x)\n", Status, pUrb->UrbHeader.Status)); + pUrbInfo->error = USBSUP_XFER_DNR; + Status = STATUS_SUCCESS; + break; + } + } + // For isochronous transfers, always update the individual packets + if (pContext->ulTransferType == USBSUP_TRANSFER_TYPE_ISOC) + { + Assert(pUrbInfo->numIsoPkts == pUrb->UrbIsochronousTransfer.NumberOfPackets); + for (ULONG i = 0; i < pUrbInfo->numIsoPkts; ++i) + { + Assert(pUrbInfo->aIsoPkts[i].off == pUrb->UrbIsochronousTransfer.IsoPacket[i].Offset); + pUrbInfo->aIsoPkts[i].cb = (uint16_t)pUrb->UrbIsochronousTransfer.IsoPacket[i].Length; + switch (pUrb->UrbIsochronousTransfer.IsoPacket[i].Status) + { + case USBD_STATUS_SUCCESS: + pUrbInfo->aIsoPkts[i].stat = USBSUP_XFER_OK; + break; + case USBD_STATUS_NOT_ACCESSED: + pUrbInfo->aIsoPkts[i].stat = USBSUP_XFER_NAC; + break; + default: + pUrbInfo->aIsoPkts[i].stat = USBSUP_XFER_STALL; + break; + } + } + } + + MmUnlockPages(pMdlBuf); + IoFreeMdl(pMdlBuf); + + vboxUsbMemFree(pContext); + + vboxUsbDdiStateRelease(pDevExt); + + Assert(pIrp->IoStatus.Status != STATUS_IO_TIMEOUT); + pIrp->IoStatus.Information = sizeof(*pUrbInfo); + pIrp->IoStatus.Status = Status; + return STATUS_CONTINUE_COMPLETION; +} + +static NTSTATUS vboxUsbRtUrbSend(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp, PUSBSUP_URB pUrbInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + PVBOXUSB_URB_CONTEXT pContext = NULL; + PMDL pMdlBuf = NULL; + ULONG cbUrb; + + Assert(pUrbInfo); + if (pUrbInfo->type == USBSUP_TRANSFER_TYPE_ISOC) + { + Assert(pUrbInfo->numIsoPkts <= 8); + cbUrb = GET_ISO_URB_SIZE(pUrbInfo->numIsoPkts); + } + else + cbUrb = sizeof (URB); + + do + { + pContext = (PVBOXUSB_URB_CONTEXT)vboxUsbMemAllocZ(cbUrb + sizeof (VBOXUSB_URB_CONTEXT)); + if (!pContext) + { + AssertMsgFailed((__FUNCTION__": vboxUsbMemAlloc failed\n")); + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + PURB pUrb = (PURB)(pContext + 1); + HANDLE hPipe = NULL; + if (pUrbInfo->ep) + { + hPipe = vboxUsbRtGetPipeHandle(pDevExt, pUrbInfo->ep | ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? 0x80 : 0x00)); + if (!hPipe) + { + AssertMsgFailed((__FUNCTION__": vboxUsbRtGetPipeHandle failed for endpoint (0x%x)\n", pUrbInfo->ep)); + Status = STATUS_INVALID_PARAMETER; + break; + } + } + + pMdlBuf = IoAllocateMdl(pUrbInfo->buf, (ULONG)pUrbInfo->len, FALSE, FALSE, NULL); + if (!pMdlBuf) + { + AssertMsgFailed((__FUNCTION__": IoAllocateMdl failed for buffer (0x%p) length (%d)\n", pUrbInfo->buf, pUrbInfo->len)); + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + __try + { + MmProbeAndLockPages(pMdlBuf, KernelMode, IoModifyAccess); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + Status = GetExceptionCode(); + IoFreeMdl(pMdlBuf); + pMdlBuf = NULL; + AssertMsgFailed((__FUNCTION__": Exception Code (0x%x)\n", Status)); + break; + } + + /* For some reason, passing a MDL in the URB does not work reliably. Notably + * the iPhone when used with iTunes fails. + */ + PVOID pBuffer = MmGetSystemAddressForMdlSafe(pMdlBuf, NormalPagePriority); + if (!pBuffer) + { + AssertMsgFailed((__FUNCTION__": MmGetSystemAddressForMdlSafe failed\n")); + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + switch (pUrbInfo->type) + { + case USBSUP_TRANSFER_TYPE_MSG: + { + pUrb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER; + pUrb->UrbHeader.Length = sizeof (struct _URB_CONTROL_TRANSFER); + pUrb->UrbControlTransfer.PipeHandle = hPipe; + pUrb->UrbControlTransfer.TransferBufferLength = (ULONG)pUrbInfo->len; + pUrb->UrbControlTransfer.TransferFlags = ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT); + pUrb->UrbControlTransfer.UrbLink = 0; + + if (!hPipe) + pUrb->UrbControlTransfer.TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER; + + /* QUSB_TRANSFER_TYPE_MSG is a control transfer, but it is special + * the first 8 bytes of the buffer is the setup packet so the real + * data length is therefore pUrb->len - 8 + */ + //PVBOXUSB_SETUP pSetup = (PVBOXUSB_SETUP)pUrb->UrbControlTransfer.SetupPacket; + memcpy(pUrb->UrbControlTransfer.SetupPacket, pBuffer, min(sizeof (pUrb->UrbControlTransfer.SetupPacket), pUrbInfo->len)); + + if (pUrb->UrbControlTransfer.TransferBufferLength <= sizeof (pUrb->UrbControlTransfer.SetupPacket)) + pUrb->UrbControlTransfer.TransferBufferLength = 0; + else + pUrb->UrbControlTransfer.TransferBufferLength -= sizeof (pUrb->UrbControlTransfer.SetupPacket); + + pUrb->UrbControlTransfer.TransferBuffer = (uint8_t *)pBuffer + sizeof(pUrb->UrbControlTransfer.SetupPacket); + pUrb->UrbControlTransfer.TransferBufferMDL = 0; + pUrb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; + break; + } + case USBSUP_TRANSFER_TYPE_ISOC: + { + Assert(hPipe); + VBOXUSB_PIPE_INFO *pPipeInfo = vboxUsbRtGetPipeInfo(pDevExt, pUrbInfo->ep | ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? 0x80 : 0x00)); + if (pPipeInfo == NULL) + { + /* Can happen if the isoc request comes in too early or late. */ + AssertMsgFailed((__FUNCTION__": pPipeInfo not found\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + + pUrb->UrbHeader.Function = URB_FUNCTION_ISOCH_TRANSFER; + pUrb->UrbHeader.Length = (USHORT)cbUrb; + pUrb->UrbIsochronousTransfer.PipeHandle = hPipe; + pUrb->UrbIsochronousTransfer.TransferBufferLength = (ULONG)pUrbInfo->len; + pUrb->UrbIsochronousTransfer.TransferBufferMDL = 0; + pUrb->UrbIsochronousTransfer.TransferBuffer = pBuffer; + pUrb->UrbIsochronousTransfer.TransferFlags = ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT); + pUrb->UrbIsochronousTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; // May be implied already + pUrb->UrbIsochronousTransfer.NumberOfPackets = pUrbInfo->numIsoPkts; + pUrb->UrbIsochronousTransfer.ErrorCount = 0; + pUrb->UrbIsochronousTransfer.UrbLink = 0; + + Assert(pUrbInfo->numIsoPkts == pUrb->UrbIsochronousTransfer.NumberOfPackets); + for (ULONG i = 0; i < pUrbInfo->numIsoPkts; ++i) + { + pUrb->UrbIsochronousTransfer.IsoPacket[i].Offset = pUrbInfo->aIsoPkts[i].off; + pUrb->UrbIsochronousTransfer.IsoPacket[i].Length = pUrbInfo->aIsoPkts[i].cb; + } + + /* We have to schedule the URBs ourselves. There is an ASAP flag but + * that can only be reliably used after pipe creation/reset, ie. it's + * almost completely useless. + */ + ULONG iFrame, iStartFrame; + VBoxUsbToolCurrentFrame(pDevExt->pLowerDO, pIrp, &iFrame); + iFrame += 2; + iStartFrame = pPipeInfo->NextScheduledFrame; + if ((iFrame < iStartFrame) || (iStartFrame > iFrame + 512)) + iFrame = iStartFrame; + /* For full-speed devices, there must be one transfer per frame (Windows USB + * stack requirement), but URBs can contain multiple packets. For high-speed or + * faster transfers, we expect one URB per frame, regardless of the interval. + */ + if (pDevExt->Rt.devdescr->bcdUSB < 0x300 && !pDevExt->Rt.fIsHighSpeed) + pPipeInfo->NextScheduledFrame = iFrame + pUrbInfo->numIsoPkts; + else + pPipeInfo->NextScheduledFrame = iFrame + 1; + pUrb->UrbIsochronousTransfer.StartFrame = iFrame; + break; + } + case USBSUP_TRANSFER_TYPE_BULK: + case USBSUP_TRANSFER_TYPE_INTR: + { + Assert(pUrbInfo->dir != USBSUP_DIRECTION_SETUP); + Assert(pUrbInfo->dir == USBSUP_DIRECTION_IN || pUrbInfo->type == USBSUP_TRANSFER_TYPE_BULK); + Assert(hPipe); + + pUrb->UrbHeader.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; + pUrb->UrbHeader.Length = sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER); + pUrb->UrbBulkOrInterruptTransfer.PipeHandle = hPipe; + pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (ULONG)pUrbInfo->len; + pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = 0; + pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pBuffer; + pUrb->UrbBulkOrInterruptTransfer.TransferFlags = ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT); + + if (pUrb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) + pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= (USBD_SHORT_TRANSFER_OK); + + pUrb->UrbBulkOrInterruptTransfer.UrbLink = 0; + break; + } + default: + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + } + + if (!NT_SUCCESS(Status)) + { + break; + } + + pContext->pDevExt = pDevExt; + pContext->pMdlBuf = pMdlBuf; + pContext->pUrb = pUrb; + pContext->pOut = pUrbInfo; + pContext->ulTransferType = pUrbInfo->type; + pContext->ulMagic = VBOXUSB_MAGIC; + + PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp); + pSl->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + pSl->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; + pSl->Parameters.Others.Argument1 = pUrb; + pSl->Parameters.Others.Argument2 = NULL; + + IoSetCompletionRoutine(pIrp, vboxUsbRtUrbSendCompletion, pContext, TRUE, TRUE, TRUE); + IoMarkIrpPending(pIrp); + Status = IoCallDriver(pDevExt->pLowerDO, pIrp); + AssertMsg(NT_SUCCESS(Status), (__FUNCTION__": IoCallDriver failed Status (0x%x)\n", Status)); + return STATUS_PENDING; + } while (0); + + Assert(!NT_SUCCESS(Status)); + + if (pMdlBuf) + { + if (pMdlBuf->MdlFlags & MDL_PAGES_LOCKED) + MmUnlockPages(pMdlBuf); + + IoFreeMdl(pMdlBuf); + } + + if (pContext) + vboxUsbMemFree(pContext); + + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchSendUrb(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + PUSBSUP_URB pUrbInfo = (PUSBSUP_URB)pIrp->AssociatedIrp.SystemBuffer; + NTSTATUS Status; + + do + { + if (!pFObj) + { + AssertFailed(); + Status = STATUS_INVALID_PARAMETER; + break; + } + + if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj)) + { + AssertFailed(); + Status = STATUS_ACCESS_DENIED; + break; + } + + if ( !pUrbInfo + || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pUrbInfo) + || pSl->Parameters.DeviceIoControl.OutputBufferLength != sizeof (*pUrbInfo)) + { + AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n")); + Status = STATUS_INVALID_PARAMETER; + break; + } + return vboxUsbRtUrbSend(pDevExt, pIrp, pUrbInfo); + } while (0); + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, 0); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchIsOperational(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + VBoxDrvToolIoComplete(pIrp, STATUS_SUCCESS, 0); + vboxUsbDdiStateRelease(pDevExt); + return STATUS_SUCCESS; +} + +static NTSTATUS vboxUsbRtDispatchGetVersion(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PUSBSUP_VERSION pVer= (PUSBSUP_VERSION)pIrp->AssociatedIrp.SystemBuffer; + NTSTATUS Status = STATUS_SUCCESS; + + if ( pVer + && pSl->Parameters.DeviceIoControl.InputBufferLength == 0 + && pSl->Parameters.DeviceIoControl.OutputBufferLength == sizeof(*pVer)) + { + pVer->u32Major = USBDRV_MAJOR_VERSION; + pVer->u32Minor = USBDRV_MINOR_VERSION; + } + else + { + AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n")); + Status = STATUS_INVALID_PARAMETER; + } + + Assert(Status != STATUS_PENDING); + VBoxDrvToolIoComplete(pIrp, Status, sizeof (*pVer)); + vboxUsbDdiStateRelease(pDevExt); + return Status; +} + +static NTSTATUS vboxUsbRtDispatchDefault(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + VBoxDrvToolIoComplete(pIrp, STATUS_INVALID_DEVICE_REQUEST, 0); + vboxUsbDdiStateRelease(pDevExt); + return STATUS_INVALID_DEVICE_REQUEST; +} + +DECLHIDDEN(NTSTATUS) vboxUsbRtCreate(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + RT_NOREF1(pDevExt); + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + AssertReturn(pFObj, STATUS_INVALID_PARAMETER); + return STATUS_SUCCESS; +} + +DECLHIDDEN(NTSTATUS) vboxUsbRtClose(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + PFILE_OBJECT pFObj = pSl->FileObject; + Assert(pFObj); + + vboxUsbRtCtxReleaseOwner(pDevExt, pFObj); + + return STATUS_SUCCESS; +} + +DECLHIDDEN(NTSTATUS) vboxUsbRtDispatch(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp) +{ + PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp); + switch (pSl->Parameters.DeviceIoControl.IoControlCode) + { + case SUPUSB_IOCTL_USB_CLAIM_DEVICE: + return vboxUsbRtDispatchClaimDevice(pDevExt, pIrp); + + case SUPUSB_IOCTL_USB_RELEASE_DEVICE: + return vboxUsbRtDispatchReleaseDevice(pDevExt, pIrp); + + case SUPUSB_IOCTL_GET_DEVICE: + return vboxUsbRtDispatchGetDevice(pDevExt, pIrp); + + case SUPUSB_IOCTL_USB_RESET: + return vboxUsbRtDispatchUsbReset(pDevExt, pIrp); + + case SUPUSB_IOCTL_USB_SET_CONFIG: + return vboxUsbRtDispatchUsbSetConfig(pDevExt, pIrp); + + case SUPUSB_IOCTL_USB_SELECT_INTERFACE: + return vboxUsbRtDispatchUsbSelectInterface(pDevExt, pIrp); + + case SUPUSB_IOCTL_USB_CLEAR_ENDPOINT: + return vboxUsbRtDispatchUsbClearEndpoint(pDevExt, pIrp); + + case SUPUSB_IOCTL_USB_ABORT_ENDPOINT: + return vboxUsbRtDispatchUsbAbortEndpoint(pDevExt, pIrp); + + case SUPUSB_IOCTL_SEND_URB: + return vboxUsbRtDispatchSendUrb(pDevExt, pIrp); + + case SUPUSB_IOCTL_IS_OPERATIONAL: + return vboxUsbRtDispatchIsOperational(pDevExt, pIrp); + + case SUPUSB_IOCTL_GET_VERSION: + return vboxUsbRtDispatchGetVersion(pDevExt, pIrp); + + default: + return vboxUsbRtDispatchDefault(pDevExt, pIrp); + } +} diff --git a/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.h b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.h new file mode 100644 index 00000000..c835890d --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.h @@ -0,0 +1,97 @@ +/* $Id: VBoxUsbRt.h $ */ +/** @file + * VBox USB R0 runtime + */ +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbRt_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbRt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxUsbCmn.h" +#include "../cmn/VBoxUsbIdc.h" + +#define VBOXUSBRT_MAX_CFGS 4 + +typedef struct VBOXUSB_PIPE_INFO { + UCHAR EndpointAddress; + ULONG NextScheduledFrame; +} VBOXUSB_PIPE_INFO; + +typedef struct VBOXUSB_IFACE_INFO { + USBD_INTERFACE_INFORMATION *pInterfaceInfo; + VBOXUSB_PIPE_INFO *pPipeInfo; +} VBOXUSB_IFACE_INFO; + +typedef struct VBOXUSB_RT +{ + UNICODE_STRING IfName; + + HANDLE hPipe0; + HANDLE hConfiguration; + uint32_t uConfigValue; + + uint32_t uNumInterfaces; + USB_DEVICE_DESCRIPTOR *devdescr; + USB_CONFIGURATION_DESCRIPTOR *cfgdescr[VBOXUSBRT_MAX_CFGS]; + + VBOXUSB_IFACE_INFO *pVBIfaceInfo; + + uint16_t idVendor, idProduct, bcdDevice; + char szSerial[MAX_USB_SERIAL_STRING]; + BOOLEAN fIsHighSpeed; + + HVBOXUSBIDCDEV hMonDev; + PFILE_OBJECT pOwner; +} VBOXUSB_RT, *PVBOXUSB_RT; + +typedef struct VBOXUSBRT_IDC +{ + PDEVICE_OBJECT pDevice; + PFILE_OBJECT pFile; +} VBOXUSBRT_IDC, *PVBOXUSBRT_IDC; + +DECLHIDDEN(NTSTATUS) vboxUsbRtGlobalsInit(); +DECLHIDDEN(VOID) vboxUsbRtGlobalsTerm(); + +DECLHIDDEN(NTSTATUS) vboxUsbRtInit(PVBOXUSBDEV_EXT pDevExt); +DECLHIDDEN(VOID) vboxUsbRtClear(PVBOXUSBDEV_EXT pDevExt); +DECLHIDDEN(NTSTATUS) vboxUsbRtRm(PVBOXUSBDEV_EXT pDevExt); +DECLHIDDEN(NTSTATUS) vboxUsbRtStart(PVBOXUSBDEV_EXT pDevExt); + +DECLHIDDEN(NTSTATUS) vboxUsbRtDispatch(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp); +DECLHIDDEN(NTSTATUS) vboxUsbRtCreate(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp); +DECLHIDDEN(NTSTATUS) vboxUsbRtClose(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp); + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_dev_VBoxUsbRt_h */ -- cgit v1.2.3