diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/HostDrivers/VBoxUSB/win/cmn | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostDrivers/VBoxUSB/win/cmn')
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/Makefile.kup | 0 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp | 237 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.h | 103 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbIdc.h | 85 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.cpp | 418 | ||||
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.h | 79 |
6 files changed, 922 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/Makefile.kup b/src/VBox/HostDrivers/VBoxUSB/win/cmn/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/Makefile.kup diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp new file mode 100644 index 00000000..bb2fe14b --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp @@ -0,0 +1,237 @@ +/* $Id: VBoxDrvTool.cpp $ */ +/** @file + * Windows Driver R0 Tooling. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "VBoxDrvTool.h" + +#include <iprt/assert.h> +#include <VBox/log.h> + +#include "../../../win/VBoxDbgLog.h" + +#define VBOXDRVTOOL_MEMTAG 'TDBV' + +static PVOID vboxDrvToolMemAlloc(SIZE_T cbBytes) +{ + PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXDRVTOOL_MEMTAG); + Assert(pvMem); + return pvMem; +} + +static PVOID vboxDrvToolMemAllocZ(SIZE_T cbBytes) +{ + PVOID pvMem = vboxDrvToolMemAlloc(cbBytes); + if (pvMem) + { + RtlZeroMemory(pvMem, cbBytes); + } + return pvMem; +} + +static VOID vboxDrvToolMemFree(PVOID pvMem) +{ + ExFreePoolWithTag(pvMem, VBOXDRVTOOL_MEMTAG); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKeyU(OUT PHANDLE phKey, IN PUNICODE_STRING pName, IN ACCESS_MASK fAccess) +{ + OBJECT_ATTRIBUTES ObjAttr; + + InitializeObjectAttributes(&ObjAttr, pName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + return ZwOpenKey(phKey, fAccess, &ObjAttr); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess) +{ + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, pName); + + return VBoxDrvToolRegOpenKeyU(phKey, &RtlStr, fAccess); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegCloseKey(IN HANDLE hKey) +{ + return ZwClose(hKey); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PULONG pDword) +{ + struct + { + KEY_VALUE_PARTIAL_INFORMATION Info; + UCHAR Buf[32]; /* should be enough */ + } Buf; + ULONG cbBuf; + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, pName); + NTSTATUS Status = ZwQueryValueKey(hKey, + &RtlStr, + KeyValuePartialInformation, + &Buf.Info, + sizeof(Buf), + &cbBuf); + if (Status == STATUS_SUCCESS) + { + if (Buf.Info.Type == REG_DWORD) + { + Assert(Buf.Info.DataLength == 4); + *pDword = *((PULONG)Buf.Info.Data); + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_PARAMETER; +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT ULONG val) +{ + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, pName); + return ZwSetValueKey(hKey, &RtlStr, + NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */ + REG_DWORD, + &val, + sizeof(val)); +} + +static NTSTATUS vboxDrvToolIoCompletionSetEvent(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pvContext) +{ + RT_NOREF2(pDevObj, pIrp); + PKEVENT pEvent = (PKEVENT)pvContext; + KeSetEvent(pEvent, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostAsync(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent) +{ + IoSetCompletionRoutine(pIrp, vboxDrvToolIoCompletionSetEvent, pEvent, TRUE, TRUE, TRUE); + return IoCallDriver(pDevObj, pIrp); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSync(PDEVICE_OBJECT pDevObj, PIRP pIrp) +{ + KEVENT Event; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + NTSTATUS Status = VBoxDrvToolIoPostAsync(pDevObj, pIrp, &Event); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = pIrp->IoStatus.Status; + } + return Status; +} + +/* !!!NOTE: the caller MUST be the IRP owner!!! * + * !! one can not post threaded IRPs this way!! */ +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSyncWithTimeout(PDEVICE_OBJECT pDevObj, PIRP pIrp, ULONG dwTimeoutMs) +{ + KEVENT Event; + LOG(("post irp (0x%p) to DevObj(0x%p) with timeout (%u)", pIrp, pDevObj, dwTimeoutMs)); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + NTSTATUS Status = VBoxDrvToolIoPostAsync(pDevObj, pIrp, &Event); + if (Status == STATUS_PENDING) + { + LARGE_INTEGER Interval; + PLARGE_INTEGER pInterval = NULL; + if (dwTimeoutMs != RT_INDEFINITE_WAIT) + { + Interval.QuadPart = -(int64_t) dwTimeoutMs /* ms */ * 10000; + pInterval = &Interval; + } + + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, pInterval); + if (Status == STATUS_TIMEOUT) + { + WARN(("irp (0x%p) to DevObj(0x%p) was not completed within timeout (%u), cancelling", pIrp, pDevObj, dwTimeoutMs)); + if (!IoCancelIrp(pIrp)) + { + /* this may happen, but this is something the caller with timeout is not expecting */ + WARN(("IoCancelIrp failed")); + } + + /* wait for the IRP to complete */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + } + else + { + ASSERT_WARN(Status == STATUS_SUCCESS, ("uunexpected Status (0x%x)", Status)); + } + + /* by this time the IRP is completed */ + Status = pIrp->IoStatus.Status; + LOG(("Pending IRP(0x%p) completed with status(0x%x)", pIrp, Status)); + } + else + { + LOG(("IRP(0x%p) completed with status(0x%x)", pIrp, Status)); + } + return Status; +} + +VBOXDRVTOOL_DECL(VOID) VBoxDrvToolRefWaitEqual(PVBOXDRVTOOL_REF pRef, uint32_t u32Val) +{ + LARGE_INTEGER Interval; + Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000; + uint32_t cRefs; + size_t loops = 0; + KTIMER kTimer; + NTSTATUS status = STATUS_SUCCESS; + + KeInitializeTimer(&kTimer); + + while ((cRefs = ASMAtomicReadU32(&pRef->cRefs)) > u32Val && loops < 256) + { + Assert(cRefs >= u32Val); + Assert(cRefs < UINT32_MAX/2); + + KeSetTimer(&kTimer, Interval, NULL); + status = KeWaitForSingleObject(&kTimer, Executive, KernelMode, false, NULL); + Assert(NT_SUCCESS(status)); + loops++; + } +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolStrCopy(PUNICODE_STRING pDst, CONST PUNICODE_STRING pSrc) +{ + USHORT cbLength = pSrc->Length + sizeof (pDst->Buffer[0]); + pDst->Buffer = (PWCHAR)vboxDrvToolMemAlloc(cbLength); + Assert(pDst->Buffer); + if (pDst->Buffer) + { + RtlMoveMemory(pDst->Buffer, pSrc->Buffer, pSrc->Length); + pDst->Buffer[pSrc->Length / sizeof (pDst->Buffer[0])] = L'\0'; + pDst->Length = pSrc->Length; + pDst->MaximumLength = cbLength; + return STATUS_SUCCESS; + } + return STATUS_NO_MEMORY; +} + +VBOXDRVTOOL_DECL(VOID) VBoxDrvToolStrFree(PUNICODE_STRING pStr) +{ + vboxDrvToolMemFree(pStr->Buffer); +} diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.h b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.h new file mode 100644 index 00000000..248c4b63 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.h @@ -0,0 +1,103 @@ +/* $Id: VBoxDrvTool.h $ */ +/** @file + * Windows Driver R0 Tooling. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxDrvTool_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxDrvTool_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/cdefs.h> +#include <iprt/stdint.h> +#include <iprt/assert.h> +#include <iprt/asm.h> +#include <iprt/nt/wdm.h> + + +RT_C_DECLS_BEGIN + +#if 0 +/* enable this in case we include this in a dll*/ +# ifdef IN_VBOXDRVTOOL +# define VBOXDRVTOOL_DECL(a_Type) DECLEXPORT(a_Type) +# else +# define VBOXDRVTOOL_DECL(a_Type) DECLIMPORT(a_Type) +# endif +#else +/*enable this in case we include this in a static lib*/ +# define VBOXDRVTOOL_DECL(a_Type) a_Type VBOXCALL +#endif + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKeyU(OUT PHANDLE phKey, IN PUNICODE_STRING pName, IN ACCESS_MASK fAccess); +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess); +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegCloseKey(IN HANDLE hKey); +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PULONG pDword); +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT ULONG val); + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostAsync(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent); +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSync(PDEVICE_OBJECT pDevObj, PIRP pIrp); +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSyncWithTimeout(PDEVICE_OBJECT pDevObj, PIRP pIrp, ULONG dwTimeoutMs); +DECLINLINE(NTSTATUS) VBoxDrvToolIoComplete(PIRP pIrp, NTSTATUS Status, ULONG ulInfo) +{ + pIrp->IoStatus.Status = Status; + pIrp->IoStatus.Information = ulInfo; + IoCompleteRequest(pIrp, IO_NO_INCREMENT); + return Status; +} + +typedef struct VBOXDRVTOOL_REF +{ + volatile uint32_t cRefs; +} VBOXDRVTOOL_REF, *PVBOXDRVTOOL_REF; + +DECLINLINE(void) VBoxDrvToolRefInit(PVBOXDRVTOOL_REF pRef) +{ + pRef->cRefs = 1; +} + +DECLINLINE(uint32_t) VBoxDrvToolRefRetain(PVBOXDRVTOOL_REF pRef) +{ + Assert(pRef->cRefs); + Assert(pRef->cRefs < UINT32_MAX / 2); + return ASMAtomicIncU32(&pRef->cRefs); +} + +DECLINLINE(uint32_t) VBoxDrvToolRefRelease(PVBOXDRVTOOL_REF pRef) +{ + uint32_t cRefs = ASMAtomicDecU32(&pRef->cRefs); + Assert(cRefs < UINT32_MAX/2); + return cRefs; +} + +VBOXDRVTOOL_DECL(VOID) VBoxDrvToolRefWaitEqual(PVBOXDRVTOOL_REF pRef, uint32_t u32Val); + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolStrCopy(PUNICODE_STRING pDst, CONST PUNICODE_STRING pSrc); +VBOXDRVTOOL_DECL(VOID) VBoxDrvToolStrFree(PUNICODE_STRING pStr); + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxDrvTool_h */ + diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbIdc.h b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbIdc.h new file mode 100644 index 00000000..75cb651c --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbIdc.h @@ -0,0 +1,85 @@ +/* $Id: VBoxUsbIdc.h $ */ +/** @file + * Windows USB Proxy - Monitor Driver communication interface. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxUsbIdc_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxUsbIdc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define VBOXUSBIDC_VERSION_MAJOR 1 +#define VBOXUSBIDC_VERSION_MINOR 0 + +#define VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x618, METHOD_NEITHER, FILE_WRITE_ACCESS) +#define VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x619, METHOD_NEITHER, FILE_WRITE_ACCESS) +#define VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN CTL_CODE(FILE_DEVICE_UNKNOWN, 0x61A, METHOD_NEITHER, FILE_WRITE_ACCESS) +#define VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STATE_CHANGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x61B, METHOD_NEITHER, FILE_WRITE_ACCESS) + +typedef struct +{ + uint32_t u32Major; + uint32_t u32Minor; +} VBOXUSBIDC_VERSION, *PVBOXUSBIDC_VERSION; + +typedef void *HVBOXUSBIDCDEV; + +/* the initial device state is USBDEVICESTATE_HELD_BY_PROXY */ +typedef struct VBOXUSBIDC_PROXY_STARTUP +{ + union + { + /* in: device PDO */ + PDEVICE_OBJECT pPDO; + /* out: device handle to be used for subsequent USBSUP_PROXY_XXX calls */ + HVBOXUSBIDCDEV hDev; + } u; +} VBOXUSBIDC_PROXY_STARTUP, *PVBOXUSBIDC_PROXY_STARTUP; + +typedef struct VBOXUSBIDC_PROXY_TEARDOWN +{ + HVBOXUSBIDCDEV hDev; +} VBOXUSBIDC_PROXY_TEARDOWN, *PVBOXUSBIDC_PROXY_TEARDOWN; + +typedef enum +{ + VBOXUSBIDC_PROXY_STATE_UNKNOWN = 0, + VBOXUSBIDC_PROXY_STATE_IDLE, + VBOXUSBIDC_PROXY_STATE_INITIAL = VBOXUSBIDC_PROXY_STATE_IDLE, + VBOXUSBIDC_PROXY_STATE_USED_BY_GUEST +} VBOXUSBIDC_PROXY_STATE; + +typedef struct VBOXUSBIDC_PROXY_STATE_CHANGE +{ + HVBOXUSBIDCDEV hDev; + VBOXUSBIDC_PROXY_STATE enmState; +} VBOXUSBIDC_PROXY_STATE_CHANGE, *PVBOXUSBIDC_PROXY_STATE_CHANGE; + +NTSTATUS VBoxUsbIdcInit(); +VOID VBoxUsbIdcTerm(); +NTSTATUS VBoxUsbIdcProxyStarted(PDEVICE_OBJECT pPDO, HVBOXUSBIDCDEV *phDev); +NTSTATUS VBoxUsbIdcProxyStopped(HVBOXUSBIDCDEV hDev); + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxUsbIdc_h */ diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.cpp b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.cpp new file mode 100644 index 00000000..0016881b --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.cpp @@ -0,0 +1,418 @@ +/* $Id: VBoxUsbTool.cpp $ */ +/** @file + * Windows USB R0 Tooling. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#define INITGUID +#include "VBoxUsbTool.h" +#include <usbbusif.h> + +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/utf16.h> +#include <VBox/log.h> +#include <VBox/usblib.h> + +#include "../../../win/VBoxDbgLog.h" + +#define VBOXUSBTOOL_MEMTAG 'TUBV' + +static PVOID vboxUsbToolMemAlloc(SIZE_T cbBytes) +{ + PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSBTOOL_MEMTAG); + Assert(pvMem); + return pvMem; +} + +static PVOID vboxUsbToolMemAllocZ(SIZE_T cbBytes) +{ + PVOID pvMem = vboxUsbToolMemAlloc(cbBytes); + if (pvMem) + { + RtlZeroMemory(pvMem, cbBytes); + } + return pvMem; +} + +static VOID vboxUsbToolMemFree(PVOID pvMem) +{ + ExFreePoolWithTag(pvMem, VBOXUSBTOOL_MEMTAG); +} + +VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbAlloc(USHORT u16Function, USHORT cbSize) +{ + PURB pUrb = (PURB)vboxUsbToolMemAlloc(cbSize); + Assert(pUrb); + if (!pUrb) + return NULL; + + pUrb->UrbHeader.Length = cbSize; + pUrb->UrbHeader.Function = u16Function; + return pUrb; +} + +VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbAllocZ(USHORT u16Function, USHORT cbSize) +{ + PURB pUrb = (PURB)vboxUsbToolMemAllocZ(cbSize); + Assert(pUrb); + if (!pUrb) + return NULL; + + pUrb->UrbHeader.Length = cbSize; + pUrb->UrbHeader.Function = u16Function; + return pUrb; +} + +VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbReinit(PURB pUrb, USHORT cbSize, USHORT u16Function) +{ + Assert(pUrb->UrbHeader.Length == cbSize); + if (pUrb->UrbHeader.Length < cbSize) + return NULL; + pUrb->UrbHeader.Length = cbSize; + pUrb->UrbHeader.Function = u16Function; + return pUrb; +} + +VBOXUSBTOOL_DECL(VOID) VBoxUsbToolUrbFree(PURB pUrb) +{ + vboxUsbToolMemFree(pUrb); +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolUrbPost(PDEVICE_OBJECT pDevObj, PURB pUrb, ULONG dwTimeoutMs) +{ + if (dwTimeoutMs == RT_INDEFINITE_WAIT) + return VBoxUsbToolIoInternalCtlSendSync(pDevObj, IOCTL_INTERNAL_USB_SUBMIT_URB, pUrb, NULL); + return VBoxUsbToolIoInternalCtlSendSyncWithTimeout(pDevObj, IOCTL_INTERNAL_USB_SUBMIT_URB, pUrb, NULL, dwTimeoutMs); +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetDescriptor(PDEVICE_OBJECT pDevObj, void *pvBuffer, int cbBuffer, int Type, int iIndex, int LangId, ULONG dwTimeoutMs) +{ + NTSTATUS Status; + USHORT cbUrb = sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST); + PURB pUrb = VBoxUsbToolUrbAllocZ(URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, cbUrb); + if (!pUrb) + { + WARN(("allocating URB failed")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + PUSB_COMMON_DESCRIPTOR pCmn = (PUSB_COMMON_DESCRIPTOR)pvBuffer; + pCmn->bLength = cbBuffer; + pCmn->bDescriptorType = Type; + + pUrb->UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + pUrb->UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); + pUrb->UrbControlDescriptorRequest.TransferBufferLength = cbBuffer; + pUrb->UrbControlDescriptorRequest.TransferBuffer = pvBuffer; + pUrb->UrbControlDescriptorRequest.Index = (UCHAR)iIndex; + pUrb->UrbControlDescriptorRequest.DescriptorType = (UCHAR)Type; + pUrb->UrbControlDescriptorRequest.LanguageId = (USHORT)LangId; + + Status = VBoxUsbToolUrbPost(pDevObj, pUrb, dwTimeoutMs); + ASSERT_WARN(Status == STATUS_SUCCESS, ("VBoxUsbToolUrbPost failed Status (0x%x)", Status)); + + VBoxUsbToolUrbFree(pUrb); + + return Status; +} + +VBOXUSBTOOL_DECL(VOID) VBoxUsbToolStringDescriptorToUnicodeString(PUSB_STRING_DESCRIPTOR pDr, PUNICODE_STRING pUnicode) +{ + /* for some reason the string dr sometimes contains a non-null terminated string + * although we zeroed up the complete descriptor buffer + * this is why RtlInitUnicodeString won't work + * we need to init the scting length based on dr length */ + pUnicode->Buffer = pDr->bString; + pUnicode->Length = pUnicode->MaximumLength = pDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString); +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetStringDescriptor(PDEVICE_OBJECT pDevObj, char *pszResult, ULONG cbResult, + int iIndex, int LangId, ULONG dwTimeoutMs) +{ + char aBuf[MAXIMUM_USB_STRING_LENGTH]; + AssertCompile(sizeof (aBuf) <= UINT8_MAX); + UCHAR cbBuf = (UCHAR)sizeof (aBuf); + PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)&aBuf; + + Assert(pszResult); + *pszResult = 0; + + memset(pDr, 0, cbBuf); + pDr->bLength = cbBuf; + pDr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE; + + NTSTATUS Status = VBoxUsbToolGetDescriptor(pDevObj, pDr, cbBuf, USB_STRING_DESCRIPTOR_TYPE, iIndex, LangId, dwTimeoutMs); + if (NT_SUCCESS(Status)) + { + if (pDr->bLength >= sizeof (USB_STRING_DESCRIPTOR)) + { + int rc = RTUtf16ToUtf8Ex(pDr->bString, (pDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString)) / sizeof(RTUTF16), + &pszResult, cbResult, NULL /*pcch*/); + if (RT_SUCCESS(rc)) + { + USBLibPurgeEncoding(pszResult); + Status = STATUS_SUCCESS; + } + else + Status = STATUS_UNSUCCESSFUL; + } + else + Status = STATUS_INVALID_PARAMETER; + } + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetLangID(PDEVICE_OBJECT pDevObj, int *pLangId, ULONG dwTimeoutMs) +{ + char aBuf[MAXIMUM_USB_STRING_LENGTH]; + AssertCompile(sizeof (aBuf) <= UINT8_MAX); + UCHAR cbBuf = (UCHAR)sizeof (aBuf); + PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)&aBuf; + + Assert(pLangId); + *pLangId = 0; + + memset(pDr, 0, cbBuf); + pDr->bLength = cbBuf; + pDr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE; + + NTSTATUS Status = VBoxUsbToolGetDescriptor(pDevObj, pDr, cbBuf, USB_STRING_DESCRIPTOR_TYPE, 0, 0, dwTimeoutMs); + if (NT_SUCCESS(Status)) + { + /* Just grab the first lang ID if available. In 99% cases, it will be US English (0x0409).*/ + if (pDr->bLength >= sizeof (USB_STRING_DESCRIPTOR)) + { + AssertCompile(sizeof (pDr->bString[0]) == sizeof (uint16_t)); + *pLangId = pDr->bString[0]; + Status = STATUS_SUCCESS; + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + } + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetDeviceSpeed(PDEVICE_OBJECT pDevObj, BOOLEAN *pbIsHigh) +{ + Assert(pbIsHigh); + *pbIsHigh = FALSE; + + PIRP pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE); + Assert(pIrp); + if (!pIrp) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + USB_BUS_INTERFACE_USBDI_V1 BusIf; + PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp); + pSl->MajorFunction = IRP_MJ_PNP; + pSl->MinorFunction = IRP_MN_QUERY_INTERFACE; + pSl->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID; + pSl->Parameters.QueryInterface.Size = sizeof (BusIf); + pSl->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_1; + pSl->Parameters.QueryInterface.Interface = (PINTERFACE)&BusIf; + pSl->Parameters.QueryInterface.InterfaceSpecificData = NULL; + + pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + NTSTATUS Status = VBoxDrvToolIoPostSync(pDevObj, pIrp); + Assert(NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED); + if (NT_SUCCESS(Status)) + { + *pbIsHigh = BusIf.IsDeviceHighSpeed(BusIf.BusContext); + BusIf.InterfaceDereference(BusIf.BusContext); + } + IoFreeIrp(pIrp); + + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolPipeClear(PDEVICE_OBJECT pDevObj, HANDLE hPipe, bool fReset) +{ + if (!hPipe) + { + Log(("Resetting the control pipe??\n")); + return STATUS_SUCCESS; + } + USHORT u16Function = fReset ? URB_FUNCTION_RESET_PIPE : URB_FUNCTION_ABORT_PIPE; + PURB pUrb = VBoxUsbToolUrbAlloc(u16Function, sizeof (struct _URB_PIPE_REQUEST)); + if (!pUrb) + { + AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbAlloc failed!\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + pUrb->UrbPipeRequest.PipeHandle = hPipe; + pUrb->UrbPipeRequest.Reserved = 0; + + NTSTATUS Status = VBoxUsbToolUrbPost(pDevObj, pUrb, RT_INDEFINITE_WAIT); + if (!NT_SUCCESS(Status) || !USBD_SUCCESS(pUrb->UrbHeader.Status)) + { + AssertMsgFailed((__FUNCTION__": vboxUsbToolRequest failed with %x (%x)\n", Status, pUrb->UrbHeader.Status)); + } + + VBoxUsbToolUrbFree(pUrb); + + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolCurrentFrame(PDEVICE_OBJECT pDevObj, PIRP pIrp, PULONG piFrame) +{ + struct _URB_GET_CURRENT_FRAME_NUMBER Urb; + Urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER; + Urb.Hdr.Length = sizeof(Urb); + Urb.FrameNumber = (ULONG)-1; + + Assert(piFrame); + *piFrame = (ULONG)-1; + + 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 = (PVOID)&Urb; + pSl->Parameters.Others.Argument2 = NULL; + + NTSTATUS Status = VBoxUsbToolUrbPost(pDevObj, (PURB)&Urb, RT_INDEFINITE_WAIT); + Assert(NT_SUCCESS(Status)); + if (NT_SUCCESS(Status)) + { + *piFrame = Urb.FrameNumber; + } + + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolDevUnconfigure(PDEVICE_OBJECT pDevObj) +{ + USHORT cbUrb = sizeof (struct _URB_SELECT_CONFIGURATION); + PURB pUrb = VBoxUsbToolUrbAlloc(URB_FUNCTION_SELECT_CONFIGURATION, cbUrb); + Assert(pUrb); + if (!pUrb) + return STATUS_INSUFFICIENT_RESOURCES; + + UsbBuildSelectConfigurationRequest(pUrb, (USHORT)cbUrb, NULL); + + NTSTATUS Status = VBoxUsbToolUrbPost(pDevObj, pUrb, RT_INDEFINITE_WAIT); + Assert(NT_SUCCESS(Status)); + + VBoxUsbToolUrbFree(pUrb); + + return Status; +} + +VBOXUSBTOOL_DECL(PIRP) VBoxUsbToolIoBuildAsyncInternalCtl(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2) +{ + PIRP pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE); + Assert(pIrp); + if (!pIrp) + { + return NULL; + } + + pIrp->IoStatus.Status = STATUS_SUCCESS; + pIrp->IoStatus.Information = NULL; + + PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp); + pSl->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + pSl->MinorFunction = 0; + pSl->Parameters.DeviceIoControl.IoControlCode = uCtl; + pSl->Parameters.Others.Argument1 = pvArg1; + pSl->Parameters.Others.Argument2 = pvArg2; + return pIrp; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendSyncWithTimeout(PDEVICE_OBJECT pDevObj, ULONG uCtl, + void *pvArg1, void *pvArg2, ULONG dwTimeoutMs) +{ + /* since we're going to cancel the irp on timeout, we should allocate our own IRP rather than using the threaded one + * */ + PIRP pIrp = VBoxUsbToolIoBuildAsyncInternalCtl(pDevObj, uCtl, pvArg1, pvArg2); + if (!pIrp) + { + WARN(("VBoxUsbToolIoBuildAsyncInternalCtl failed")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + NTSTATUS Status = VBoxDrvToolIoPostSyncWithTimeout(pDevObj, pIrp, dwTimeoutMs); + + IoFreeIrp(pIrp); + + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendAsync(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2, + PKEVENT pEvent, PIO_STATUS_BLOCK pIoStatus) +{ + NTSTATUS Status; + PIRP pIrp; + PIO_STACK_LOCATION pSl; + Assert(KeGetCurrentIrql() == PASSIVE_LEVEL); + + pIrp = IoBuildDeviceIoControlRequest(uCtl, pDevObj, NULL, 0, NULL, 0, TRUE, pEvent, pIoStatus); + if (!pIrp) + { + WARN(("IoBuildDeviceIoControlRequest failed!!\n")); + pIoStatus->Status = STATUS_INSUFFICIENT_RESOURCES; + pIoStatus->Information = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Get the next stack location as that is used for the new irp */ + pSl = IoGetNextIrpStackLocation(pIrp); + pSl->Parameters.Others.Argument1 = pvArg1; + pSl->Parameters.Others.Argument2 = pvArg2; + + Status = IoCallDriver(pDevObj, pIrp); + + return Status; +} + +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendSync(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2) +{ + IO_STATUS_BLOCK IoStatus = {0}; + KEVENT Event; + NTSTATUS Status; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + + LOG(("Sending sync Ctl pDevObj(0x%p), uCtl(0x%x), pvArg1(0x%p), pvArg2(0x%p)", pDevObj, uCtl, pvArg1, pvArg2)); + + Status = VBoxUsbToolIoInternalCtlSendAsync(pDevObj, uCtl, pvArg1, pvArg2, &Event, &IoStatus); + + if (Status == STATUS_PENDING) + { + LOG(("VBoxUsbToolIoInternalCtlSendAsync returned pending for pDevObj(0x%x)", pDevObj)); + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = IoStatus.Status; + LOG(("Pending VBoxUsbToolIoInternalCtlSendAsync completed with Status (0x%x) for pDevObj(0x%x)", Status, pDevObj)); + } + else + { + LOG(("VBoxUsbToolIoInternalCtlSendAsync completed with Status (0x%x) for pDevObj(0x%x)", Status, pDevObj)); + } + + return Status; +} diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.h b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.h new file mode 100644 index 00000000..aeb62f05 --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.h @@ -0,0 +1,79 @@ +/* $Id: VBoxUsbTool.h $ */ +/** @file + * Windows USB R0 Tooling. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxUsbTool_h +#define VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxUsbTool_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxDrvTool.h" + +RT_C_DECLS_BEGIN +#pragma warning( disable : 4200 ) +#include <usbdi.h> +#pragma warning( default : 4200 ) +#include <usbdlib.h> + +RT_C_DECLS_END + +#if 0 +/* enable this in case we include this in a dll*/ +# ifdef IN_VBOXUSBTOOL +# define VBOXUSBTOOL_DECL(a_Type) DECLEXPORT(a_Type) +# else +# define VBOXUSBTOOL_DECL(a_Type) DECLIMPORT(a_Type) +# endif +#else +/*enable this in case we include this in a static lib*/ +# define VBOXUSBTOOL_DECL(a_Type) a_Type VBOXCALL +#endif + + +RT_C_DECLS_BEGIN + +VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbAlloc(USHORT u16Function, USHORT cbSize); +VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbAllocZ(USHORT u16Function, USHORT cbSize); +VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbReinit(PURB pUrb, USHORT cbSize, USHORT u16Function); +VBOXUSBTOOL_DECL(VOID) VBoxUsbToolUrbFree(PURB pUrb); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolUrbPost(PDEVICE_OBJECT pDevObj, PURB pUrb, ULONG dwTimeoutMs); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetDescriptor(PDEVICE_OBJECT pDevObj, void *pvBuffer, int cbBuffer, int Type, int iIndex, int LangId, ULONG dwTimeoutMs); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetStringDescriptor(PDEVICE_OBJECT pDevObj, char *pszResult, ULONG cbResult, int iIndex, int LangId, ULONG dwTimeoutMs); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetLangID(PDEVICE_OBJECT pDevObj, int *pLangId, ULONG dwTimeoutMs); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetDeviceSpeed(PDEVICE_OBJECT pDevObj, BOOLEAN *pbIsHigh); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolPipeClear(PDEVICE_OBJECT pDevObj, HANDLE hPipe, bool fReset); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolCurrentFrame(PDEVICE_OBJECT pDevObj, PIRP pIrp, PULONG piFrame); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolDevUnconfigure(PDEVICE_OBJECT pDevObj); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendAsync(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2, PKEVENT pEvent, PIO_STATUS_BLOCK pIoStatus); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendSync(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2); +VBOXUSBTOOL_DECL(PIRP) VBoxUsbToolIoBuildAsyncInternalCtl(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2); +VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendSyncWithTimeout(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2, ULONG dwTimeoutMs); +VBOXUSBTOOL_DECL(VOID) VBoxUsbToolStringDescriptorToUnicodeString(PUSB_STRING_DESCRIPTOR pDr, PUNICODE_STRING pUnicode); + + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_SRC_VBoxUSB_win_cmn_VBoxUsbTool_h */ |