VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxUsbTool.cpp@ 78039

Last change on this file since 78039 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
Line 
1/* $Id: VBoxUsbTool.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * Windows USB R0 Tooling.
4 */
5
6/*
7 * Copyright (C) 2011-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27#define INITGUID
28#include "VBoxUsbTool.h"
29#include <usbbusif.h>
30
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include <iprt/utf16.h>
34#include <VBox/log.h>
35#include <VBox/usblib.h>
36
37#include "../../../win/VBoxDbgLog.h"
38
39#define VBOXUSBTOOL_MEMTAG 'TUBV'
40
41static PVOID vboxUsbToolMemAlloc(SIZE_T cbBytes)
42{
43 PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSBTOOL_MEMTAG);
44 Assert(pvMem);
45 return pvMem;
46}
47
48static PVOID vboxUsbToolMemAllocZ(SIZE_T cbBytes)
49{
50 PVOID pvMem = vboxUsbToolMemAlloc(cbBytes);
51 if (pvMem)
52 {
53 RtlZeroMemory(pvMem, cbBytes);
54 }
55 return pvMem;
56}
57
58static VOID vboxUsbToolMemFree(PVOID pvMem)
59{
60 ExFreePoolWithTag(pvMem, VBOXUSBTOOL_MEMTAG);
61}
62
63VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbAlloc(USHORT u16Function, USHORT cbSize)
64{
65 PURB pUrb = (PURB)vboxUsbToolMemAlloc(cbSize);
66 Assert(pUrb);
67 if (!pUrb)
68 return NULL;
69
70 pUrb->UrbHeader.Length = cbSize;
71 pUrb->UrbHeader.Function = u16Function;
72 return pUrb;
73}
74
75VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbAllocZ(USHORT u16Function, USHORT cbSize)
76{
77 PURB pUrb = (PURB)vboxUsbToolMemAllocZ(cbSize);
78 Assert(pUrb);
79 if (!pUrb)
80 return NULL;
81
82 pUrb->UrbHeader.Length = cbSize;
83 pUrb->UrbHeader.Function = u16Function;
84 return pUrb;
85}
86
87VBOXUSBTOOL_DECL(PURB) VBoxUsbToolUrbReinit(PURB pUrb, USHORT cbSize, USHORT u16Function)
88{
89 Assert(pUrb->UrbHeader.Length == cbSize);
90 if (pUrb->UrbHeader.Length < cbSize)
91 return NULL;
92 pUrb->UrbHeader.Length = cbSize;
93 pUrb->UrbHeader.Function = u16Function;
94 return pUrb;
95}
96
97VBOXUSBTOOL_DECL(VOID) VBoxUsbToolUrbFree(PURB pUrb)
98{
99 vboxUsbToolMemFree(pUrb);
100}
101
102VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolUrbPost(PDEVICE_OBJECT pDevObj, PURB pUrb, ULONG dwTimeoutMs)
103{
104 if (dwTimeoutMs == RT_INDEFINITE_WAIT)
105 return VBoxUsbToolIoInternalCtlSendSync(pDevObj, IOCTL_INTERNAL_USB_SUBMIT_URB, pUrb, NULL);
106 return VBoxUsbToolIoInternalCtlSendSyncWithTimeout(pDevObj, IOCTL_INTERNAL_USB_SUBMIT_URB, pUrb, NULL, dwTimeoutMs);
107}
108
109VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetDescriptor(PDEVICE_OBJECT pDevObj, void *pvBuffer, int cbBuffer, int Type, int iIndex, int LangId, ULONG dwTimeoutMs)
110{
111 NTSTATUS Status;
112 USHORT cbUrb = sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST);
113 PURB pUrb = VBoxUsbToolUrbAllocZ(URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE, cbUrb);
114 if (!pUrb)
115 {
116 WARN(("allocating URB failed"));
117 return STATUS_INSUFFICIENT_RESOURCES;
118 }
119
120 PUSB_COMMON_DESCRIPTOR pCmn = (PUSB_COMMON_DESCRIPTOR)pvBuffer;
121 pCmn->bLength = cbBuffer;
122 pCmn->bDescriptorType = Type;
123
124 pUrb->UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
125 pUrb->UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
126 pUrb->UrbControlDescriptorRequest.TransferBufferLength = cbBuffer;
127 pUrb->UrbControlDescriptorRequest.TransferBuffer = pvBuffer;
128 pUrb->UrbControlDescriptorRequest.Index = (UCHAR)iIndex;
129 pUrb->UrbControlDescriptorRequest.DescriptorType = (UCHAR)Type;
130 pUrb->UrbControlDescriptorRequest.LanguageId = (USHORT)LangId;
131
132 Status = VBoxUsbToolUrbPost(pDevObj, pUrb, dwTimeoutMs);
133 ASSERT_WARN(Status == STATUS_SUCCESS, ("VBoxUsbToolUrbPost failed Status (0x%x)", Status));
134
135 VBoxUsbToolUrbFree(pUrb);
136
137 return Status;
138}
139
140VBOXUSBTOOL_DECL(VOID) VBoxUsbToolStringDescriptorToUnicodeString(PUSB_STRING_DESCRIPTOR pDr, PUNICODE_STRING pUnicode)
141{
142 /* for some reason the string dr sometimes contains a non-null terminated string
143 * although we zeroed up the complete descriptor buffer
144 * this is why RtlInitUnicodeString won't work
145 * we need to init the scting length based on dr length */
146 pUnicode->Buffer = pDr->bString;
147 pUnicode->Length = pUnicode->MaximumLength = pDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString);
148}
149
150VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetStringDescriptor(PDEVICE_OBJECT pDevObj, char *pszResult, ULONG cbResult,
151 int iIndex, int LangId, ULONG dwTimeoutMs)
152{
153 char aBuf[MAXIMUM_USB_STRING_LENGTH];
154 AssertCompile(sizeof (aBuf) <= UINT8_MAX);
155 UCHAR cbBuf = (UCHAR)sizeof (aBuf);
156 PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)&aBuf;
157
158 Assert(pszResult);
159 *pszResult = 0;
160
161 memset(pDr, 0, cbBuf);
162 pDr->bLength = cbBuf;
163 pDr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE;
164
165 NTSTATUS Status = VBoxUsbToolGetDescriptor(pDevObj, pDr, cbBuf, USB_STRING_DESCRIPTOR_TYPE, iIndex, LangId, dwTimeoutMs);
166 if (NT_SUCCESS(Status))
167 {
168 if (pDr->bLength >= sizeof (USB_STRING_DESCRIPTOR))
169 {
170 int rc = RTUtf16ToUtf8Ex(pDr->bString, (pDr->bLength - RT_OFFSETOF(USB_STRING_DESCRIPTOR, bString)) / sizeof(RTUTF16),
171 &pszResult, cbResult, NULL /*pcch*/);
172 if (RT_SUCCESS(rc))
173 {
174 USBLibPurgeEncoding(pszResult);
175 Status = STATUS_SUCCESS;
176 }
177 else
178 Status = STATUS_UNSUCCESSFUL;
179 }
180 else
181 Status = STATUS_INVALID_PARAMETER;
182 }
183 return Status;
184}
185
186VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetLangID(PDEVICE_OBJECT pDevObj, int *pLangId, ULONG dwTimeoutMs)
187{
188 char aBuf[MAXIMUM_USB_STRING_LENGTH];
189 AssertCompile(sizeof (aBuf) <= UINT8_MAX);
190 UCHAR cbBuf = (UCHAR)sizeof (aBuf);
191 PUSB_STRING_DESCRIPTOR pDr = (PUSB_STRING_DESCRIPTOR)&aBuf;
192
193 Assert(pLangId);
194 *pLangId = 0;
195
196 memset(pDr, 0, cbBuf);
197 pDr->bLength = cbBuf;
198 pDr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE;
199
200 NTSTATUS Status = VBoxUsbToolGetDescriptor(pDevObj, pDr, cbBuf, USB_STRING_DESCRIPTOR_TYPE, 0, 0, dwTimeoutMs);
201 if (NT_SUCCESS(Status))
202 {
203 /* Just grab the first lang ID if available. In 99% cases, it will be US English (0x0409).*/
204 if (pDr->bLength >= sizeof (USB_STRING_DESCRIPTOR))
205 {
206 AssertCompile(sizeof (pDr->bString[0]) == sizeof (uint16_t));
207 *pLangId = pDr->bString[0];
208 Status = STATUS_SUCCESS;
209 }
210 else
211 {
212 Status = STATUS_INVALID_PARAMETER;
213 }
214 }
215 return Status;
216}
217
218VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolGetDeviceSpeed(PDEVICE_OBJECT pDevObj, BOOLEAN *pbIsHigh)
219{
220 Assert(pbIsHigh);
221 *pbIsHigh = FALSE;
222
223 PIRP pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
224 Assert(pIrp);
225 if (!pIrp)
226 {
227 return STATUS_INSUFFICIENT_RESOURCES;
228 }
229
230 USB_BUS_INTERFACE_USBDI_V1 BusIf;
231 PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp);
232 pSl->MajorFunction = IRP_MJ_PNP;
233 pSl->MinorFunction = IRP_MN_QUERY_INTERFACE;
234 pSl->Parameters.QueryInterface.InterfaceType = &USB_BUS_INTERFACE_USBDI_GUID;
235 pSl->Parameters.QueryInterface.Size = sizeof (BusIf);
236 pSl->Parameters.QueryInterface.Version = USB_BUSIF_USBDI_VERSION_1;
237 pSl->Parameters.QueryInterface.Interface = (PINTERFACE)&BusIf;
238 pSl->Parameters.QueryInterface.InterfaceSpecificData = NULL;
239
240 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
241
242 NTSTATUS Status = VBoxDrvToolIoPostSync(pDevObj, pIrp);
243 Assert(NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED);
244 if (NT_SUCCESS(Status))
245 {
246 *pbIsHigh = BusIf.IsDeviceHighSpeed(BusIf.BusContext);
247 BusIf.InterfaceDereference(BusIf.BusContext);
248 }
249 IoFreeIrp(pIrp);
250
251 return Status;
252}
253
254VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolPipeClear(PDEVICE_OBJECT pDevObj, HANDLE hPipe, bool fReset)
255{
256 if (!hPipe)
257 {
258 Log(("Resetting the control pipe??\n"));
259 return STATUS_SUCCESS;
260 }
261 USHORT u16Function = fReset ? URB_FUNCTION_RESET_PIPE : URB_FUNCTION_ABORT_PIPE;
262 PURB pUrb = VBoxUsbToolUrbAlloc(u16Function, sizeof (struct _URB_PIPE_REQUEST));
263 if (!pUrb)
264 {
265 AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbAlloc failed!\n"));
266 return STATUS_INSUFFICIENT_RESOURCES;
267 }
268 pUrb->UrbPipeRequest.PipeHandle = hPipe;
269 pUrb->UrbPipeRequest.Reserved = 0;
270
271 NTSTATUS Status = VBoxUsbToolUrbPost(pDevObj, pUrb, RT_INDEFINITE_WAIT);
272 if (!NT_SUCCESS(Status) || !USBD_SUCCESS(pUrb->UrbHeader.Status))
273 {
274 AssertMsgFailed((__FUNCTION__": vboxUsbToolRequest failed with %x (%x)\n", Status, pUrb->UrbHeader.Status));
275 }
276
277 VBoxUsbToolUrbFree(pUrb);
278
279 return Status;
280}
281
282VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolCurrentFrame(PDEVICE_OBJECT pDevObj, PIRP pIrp, PULONG piFrame)
283{
284 struct _URB_GET_CURRENT_FRAME_NUMBER Urb;
285 Urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
286 Urb.Hdr.Length = sizeof(Urb);
287 Urb.FrameNumber = (ULONG)-1;
288
289 Assert(piFrame);
290 *piFrame = (ULONG)-1;
291
292 PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp);
293 pSl->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
294 pSl->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
295 pSl->Parameters.Others.Argument1 = (PVOID)&Urb;
296 pSl->Parameters.Others.Argument2 = NULL;
297
298 NTSTATUS Status = VBoxUsbToolUrbPost(pDevObj, (PURB)&Urb, RT_INDEFINITE_WAIT);
299 Assert(NT_SUCCESS(Status));
300 if (NT_SUCCESS(Status))
301 {
302 *piFrame = Urb.FrameNumber;
303 }
304
305 return Status;
306}
307
308VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolDevUnconfigure(PDEVICE_OBJECT pDevObj)
309{
310 USHORT cbUrb = sizeof (struct _URB_SELECT_CONFIGURATION);
311 PURB pUrb = VBoxUsbToolUrbAlloc(URB_FUNCTION_SELECT_CONFIGURATION, cbUrb);
312 Assert(pUrb);
313 if (!pUrb)
314 return STATUS_INSUFFICIENT_RESOURCES;
315
316 UsbBuildSelectConfigurationRequest(pUrb, (USHORT)cbUrb, NULL);
317
318 NTSTATUS Status = VBoxUsbToolUrbPost(pDevObj, pUrb, RT_INDEFINITE_WAIT);
319 Assert(NT_SUCCESS(Status));
320
321 VBoxUsbToolUrbFree(pUrb);
322
323 return Status;
324}
325
326VBOXUSBTOOL_DECL(PIRP) VBoxUsbToolIoBuildAsyncInternalCtl(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2)
327{
328 PIRP pIrp = IoAllocateIrp(pDevObj->StackSize, FALSE);
329 Assert(pIrp);
330 if (!pIrp)
331 {
332 return NULL;
333 }
334
335 pIrp->IoStatus.Status = STATUS_SUCCESS;
336 pIrp->IoStatus.Information = NULL;
337
338 PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp);
339 pSl->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
340 pSl->MinorFunction = 0;
341 pSl->Parameters.DeviceIoControl.IoControlCode = uCtl;
342 pSl->Parameters.Others.Argument1 = pvArg1;
343 pSl->Parameters.Others.Argument2 = pvArg2;
344 return pIrp;
345}
346
347VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendSyncWithTimeout(PDEVICE_OBJECT pDevObj, ULONG uCtl,
348 void *pvArg1, void *pvArg2, ULONG dwTimeoutMs)
349{
350 /* since we're going to cancel the irp on timeout, we should allocate our own IRP rather than using the threaded one
351 * */
352 PIRP pIrp = VBoxUsbToolIoBuildAsyncInternalCtl(pDevObj, uCtl, pvArg1, pvArg2);
353 if (!pIrp)
354 {
355 WARN(("VBoxUsbToolIoBuildAsyncInternalCtl failed"));
356 return STATUS_INSUFFICIENT_RESOURCES;
357 }
358
359 NTSTATUS Status = VBoxDrvToolIoPostSyncWithTimeout(pDevObj, pIrp, dwTimeoutMs);
360
361 IoFreeIrp(pIrp);
362
363 return Status;
364}
365
366VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendAsync(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2,
367 PKEVENT pEvent, PIO_STATUS_BLOCK pIoStatus)
368{
369 NTSTATUS Status;
370 PIRP pIrp;
371 PIO_STACK_LOCATION pSl;
372 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
373
374 pIrp = IoBuildDeviceIoControlRequest(uCtl, pDevObj, NULL, 0, NULL, 0, TRUE, pEvent, pIoStatus);
375 if (!pIrp)
376 {
377 WARN(("IoBuildDeviceIoControlRequest failed!!\n"));
378 pIoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
379 pIoStatus->Information = 0;
380 return STATUS_INSUFFICIENT_RESOURCES;
381 }
382
383 /* Get the next stack location as that is used for the new irp */
384 pSl = IoGetNextIrpStackLocation(pIrp);
385 pSl->Parameters.Others.Argument1 = pvArg1;
386 pSl->Parameters.Others.Argument2 = pvArg2;
387
388 Status = IoCallDriver(pDevObj, pIrp);
389
390 return Status;
391}
392
393VBOXUSBTOOL_DECL(NTSTATUS) VBoxUsbToolIoInternalCtlSendSync(PDEVICE_OBJECT pDevObj, ULONG uCtl, void *pvArg1, void *pvArg2)
394{
395 IO_STATUS_BLOCK IoStatus = {0};
396 KEVENT Event;
397 NTSTATUS Status;
398
399 KeInitializeEvent(&Event, NotificationEvent, FALSE);
400
401 LOG(("Sending sync Ctl pDevObj(0x%p), uCtl(0x%x), pvArg1(0x%p), pvArg2(0x%p)", pDevObj, uCtl, pvArg1, pvArg2));
402
403 Status = VBoxUsbToolIoInternalCtlSendAsync(pDevObj, uCtl, pvArg1, pvArg2, &Event, &IoStatus);
404
405 if (Status == STATUS_PENDING)
406 {
407 LOG(("VBoxUsbToolIoInternalCtlSendAsync returned pending for pDevObj(0x%x)", pDevObj));
408 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
409 Status = IoStatus.Status;
410 LOG(("Pending VBoxUsbToolIoInternalCtlSendAsync completed with Status (0x%x) for pDevObj(0x%x)", Status, pDevObj));
411 }
412 else
413 {
414 LOG(("VBoxUsbToolIoInternalCtlSendAsync completed with Status (0x%x) for pDevObj(0x%x)", Status, pDevObj));
415 }
416
417 return Status;
418}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette