VirtualBox

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

Last change on this file since 60159 was 60159, checked in by vboxsync, 9 years ago

USB: Added fPurge parameter to USBFilterSetStringExact so the usb device drivers can do the same purging as userland.

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