VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/Monitor/USBMonFlt.cpp@ 31908

Last change on this file since 31908 was 31898, checked in by vboxsync, 14 years ago

OSE header fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.6 KB
Line 
1/** @file
2 * VBox host drivers - USB drivers - Win32 USB monitor driver
3 */
4
5/*
6 * Copyright (C) 2006-2007 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include "USBMon.h"
22#include <VBox/cdefs.h>
23#include <VBox/types.h>
24#include <iprt/process.h>
25#include <iprt/assert.h>
26#include <VBox/sup.h>
27
28#include <VBox/log.h>
29#include <iprt/assert.h>
30#include <stdio.h>
31
32#pragma warning(disable : 4200)
33#include "usbdi.h"
34#pragma warning(default : 4200)
35#include "usbdlib.h"
36#include "VBoxUSBFilterMgr.h"
37#include <VBox/usblib.h>
38#include <devguid.h>
39
40/*
41 * Note: Must match the VID & PID in the USB driver .inf file!!
42 */
43/*
44 BusQueryDeviceID USB\Vid_80EE&Pid_CAFE
45 BusQueryInstanceID 2
46 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE&Rev_0100
47 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE
48 BusQueryCompatibleIDs USB\Class_ff&SubClass_00&Prot_00
49 BusQueryCompatibleIDs USB\Class_ff&SubClass_00
50 BusQueryCompatibleIDs USB\Class_ff
51*/
52
53#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
54#define szBusQueryHardwareIDs L"USB\\Vid_80EE&Pid_CAFE&Rev_0100\0USB\\Vid_80EE&Pid_CAFE\0\0"
55#define szBusQueryCompatibleIDs L"USB\\Class_ff&SubClass_00&Prot_00\0USB\\Class_ff&SubClass_00\0USB\\Class_ff\0\0"
56
57#define szDeviceTextDescription L"VirtualBox USB"
58
59/* Possible USB bus driver names. */
60static LPWSTR lpszStandardControllerName[1] =
61{
62 L"\\Driver\\usbhub",
63};
64
65#define MAX_ATTACHED_USB_DEVICES 64
66
67typedef struct
68{
69 bool fAttached, fCaptured;
70 PDEVICE_OBJECT Pdo;
71 uint16_t idVendor;
72 uint16_t idProduct;
73 uint16_t bcdDevice;
74 uint8_t bClass;
75 uint8_t bSubClass;
76 uint8_t bProtocol;
77 char szSerial[MAX_USB_SERIAL_STRING];
78 char szMfgName[MAX_USB_SERIAL_STRING];
79 char szProduct[MAX_USB_SERIAL_STRING];
80} FLTUSB_DEVICE, *PFLTUSB_DEVICE;
81
82/* Device driver instance data */
83typedef struct
84{
85 LONG cUSBDevices;
86 LONG CaptureCount;
87
88 LONG cUSBStateChange;
89
90 KSPIN_LOCK lock;
91
92 FLTUSB_DEVICE USBDevice[MAX_ATTACHED_USB_DEVICES];
93
94 /* Set to force grabbing of newly arrived devices */
95 bool fForceGrab;
96 /* Set to disable all filters */
97 bool fDisableFilters;
98
99} DRVINSTANCE, *PDRVINSTANCE;
100
101DRVINSTANCE DrvInstance = {0};
102
103/* Forward declarations. */
104NTSTATUS VBoxUSBGetDeviceDescription(PDEVICE_OBJECT pDevObj, USHORT *pusVendorId, USHORT *pusProductId, USHORT *pusRevision);
105NTSTATUS VBoxUSBGetDeviceIdStrings(PDEVICE_OBJECT pDevObj, PFLTUSB_DEVICE pFltDev);
106
107#define ACQUIRE_LOCK() \
108 KIRQL oldIrql; \
109 KeAcquireSpinLock(&DrvInstance.lock, &oldIrql);
110
111#define RELEASE_LOCK() \
112 KeReleaseSpinLock(&DrvInstance.lock, oldIrql);
113
114
115NTSTATUS _stdcall VBoxUSBInit()
116{
117 memset(&DrvInstance, 0, sizeof(DrvInstance));
118 KeInitializeSpinLock(&DrvInstance.lock);
119 VBoxUSBFilterInit();
120 return STATUS_SUCCESS;
121}
122
123NTSTATUS _stdcall VBoxUSBTerm()
124{
125 VBoxUSBFilterTerm();
126 return STATUS_SUCCESS;
127}
128
129
130/**
131 * Device I/O Control entry point.
132 *
133 * @param pDevObj Device object.
134 * @param pIrp Request packet.
135 */
136NTSTATUS _stdcall VBoxUSBDispatchIO(PDEVICE_OBJECT DeviceObject, PIRP Irp)
137{
138 PIO_STACK_LOCATION irpStack;
139 NTSTATUS status;
140 ULONG info = 0;
141 PVOID ioBuffer;
142 ULONG inputBufferLength;
143 ULONG outputBufferLength;
144
145 status = STATUS_SUCCESS;
146 Irp->IoStatus.Information = 0;
147 irpStack = IoGetCurrentIrpStackLocation (Irp);
148
149 ioBuffer = Irp->AssociatedIrp.SystemBuffer;
150 inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
151 outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
152
153 switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
154 {
155 case SUPUSBFLT_IOCTL_USB_CHANGE:
156 {
157 PUSBSUP_USB_CHANGE pOut = (PUSBSUP_USB_CHANGE)ioBuffer;
158
159 if (!ioBuffer || outputBufferLength != sizeof(*pOut) || inputBufferLength != 0)
160 {
161 AssertMsgFailed(("SUPUSBFLT_IOCTL_USB_CHANGE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
162 inputBufferLength, 0, outputBufferLength, sizeof(*pOut)));
163 status = STATUS_INVALID_PARAMETER;
164 break;
165 }
166 Assert(sizeof(DrvInstance.cUSBStateChange) == sizeof(uint32_t));
167
168//// DebugPrint(("SUPUSBFLT_IOCTL_USB_CHANGE -> %d\n", DrvInstance.cUSBStateChange));
169 pOut->cUSBStateChange = DrvInstance.cUSBStateChange;
170
171 info = sizeof(*pOut);
172 break;
173 }
174
175 case SUPUSBFLT_IOCTL_GET_NUM_DEVICES:
176 {
177 PUSBSUP_GETNUMDEV pOut = (PUSBSUP_GETNUMDEV)ioBuffer;
178
179 if (!ioBuffer || outputBufferLength != sizeof(*pOut) || inputBufferLength != 0)
180 {
181 AssertMsgFailed(("SUPUSBFLT_IOCTL_GET_NUM_DEVICES: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
182 inputBufferLength, 0, outputBufferLength, sizeof(*pOut)));
183 status = STATUS_INVALID_PARAMETER;
184 break;
185 }
186 DebugPrint(("SUPUSBFLT_IOCTL_GET_NUM_DEVICES -> %d devices\n", DrvInstance.cUSBDevices));
187 pOut->cUSBDevices = DrvInstance.cUSBDevices;
188 info = sizeof(*pOut);
189 break;
190 }
191
192 case SUPUSBFLT_IOCTL_CAPTURE_DEVICE:
193 {
194 PUSBSUP_CAPTURE pIn = (PUSBSUP_CAPTURE)ioBuffer;
195
196 DebugPrint(("SUPUSBFLT_IOCTL_CAPTURE_DEVICE\n"));
197 if (!ioBuffer || inputBufferLength != sizeof(*pIn) || outputBufferLength != 0)
198 {
199 AssertMsgFailed(("SUPUSBFLT_IOCTL_CAPTURE_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
200 inputBufferLength, sizeof(*pIn), outputBufferLength, 0));
201 status = STATUS_INVALID_PARAMETER;
202 break;
203 }
204 status = VBoxUSBGrabDevice(pIn->usVendorId, pIn->usProductId, pIn->usRevision);
205 break;
206 }
207
208 case SUPUSBFLT_IOCTL_RELEASE_DEVICE:
209 {
210 PUSBSUP_RELEASE pIn = (PUSBSUP_RELEASE)ioBuffer;
211
212 DebugPrint(("SUPUSBFLT_IOCTL_RELEASE_DEVICE\n"));
213 if (!ioBuffer || inputBufferLength != sizeof(*pIn) || outputBufferLength != 0)
214 {
215 AssertMsgFailed(("SUPUSBFLT_IOCTL_RELEASE_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
216 inputBufferLength, sizeof(*pIn), outputBufferLength, 0));
217 status = STATUS_INVALID_PARAMETER;
218 break;
219 }
220 status = VBoxUSBReleaseDevice(pIn->usVendorId, pIn->usProductId, pIn->usRevision);
221 break;
222 }
223
224 case SUPUSBFLT_IOCTL_GET_VERSION:
225 {
226 PUSBSUP_VERSION pOut = (PUSBSUP_VERSION)ioBuffer;
227
228 DebugPrint(("SUPUSBFLT_IOCTL_GET_VERSION\n"));
229 if (!ioBuffer || outputBufferLength != sizeof(*pOut) || inputBufferLength != 0)
230 {
231 AssertMsgFailed(("SUPUSBFLT_IOCTL_GET_VERSION: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
232 inputBufferLength, 0, outputBufferLength, sizeof(*pOut)));
233 status = STATUS_INVALID_PARAMETER;
234 break;
235 }
236 pOut->u32Major = USBMON_MAJOR_VERSION;
237 pOut->u32Minor = USBMON_MINOR_VERSION;
238 info = sizeof(*pOut);
239 break;
240 }
241
242 case SUPUSBFLT_IOCTL_ADD_FILTER:
243 {
244 PUSBFILTER pFilter = (PUSBFILTER)ioBuffer;
245 PUSBSUP_FLTADDOUT pOut = (PUSBSUP_FLTADDOUT)ioBuffer;
246 RTPROCESS pid = RTProcSelf();
247 uintptr_t uId = 0;
248
249 /* Validate input. */
250 if (RT_UNLIKELY(!ioBuffer || inputBufferLength != sizeof(*pFilter) || outputBufferLength != sizeof(*pOut)))
251 {
252 AssertMsgFailed(("SUPUSBFLT_IOCTL_ADD_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
253 inputBufferLength, sizeof(pFilter), outputBufferLength, 0));
254 status = STATUS_INVALID_PARAMETER;
255 break;
256 }
257
258 /* Log the filter details. */
259 DebugPrint(("SUPUSBFLT_IOCTL_ADD_FILTER %s %s %s\n",
260 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
261 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
262 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
263#ifdef DEBUG
264 DebugPrint(("VBoxUSBClient::addFilter: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
265 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
266 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
267 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
268 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
269 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
270 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
271 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
272 USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
273#endif
274
275 /* We can't get the bus/port numbers. Ignore them while matching. */
276 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false);
277 USBFilterSetMustBePresent(pFilter, USBFILTERIDX_PORT, false);
278
279 /* Add the filter. */
280 pOut->rc = VBoxUSBFilterAdd(pFilter, pid, &uId);
281 pOut->uId = uId;
282
283 info = sizeof(*pOut);
284 break;
285 }
286
287 case SUPUSBFLT_IOCTL_REMOVE_FILTER:
288 {
289 uintptr_t *pIn = (uintptr_t *)ioBuffer;
290 RTPROCESS pid = RTProcSelf();
291
292 if (!ioBuffer || inputBufferLength != sizeof(*pIn))
293 {
294 AssertMsgFailed(("SUPUSBFLT_IOCTL_REMOVE_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.\n",
295 inputBufferLength, sizeof(pIn), outputBufferLength, 0));
296 status = STATUS_INVALID_PARAMETER;
297 break;
298 }
299 DebugPrint(("SUPUSBFLT_IOCTL_REMOVE_FILTER %x\n", *pIn));
300 VBoxUSBFilterRemove(pid, *pIn);
301 break;
302 }
303
304 default:
305 status = STATUS_INVALID_PARAMETER;
306 break;
307 }
308 Irp->IoStatus.Information = info;
309
310 return status;
311}
312
313NTSTATUS _stdcall VBoxUSBCreate()
314{
315 Assert(sizeof(DrvInstance.CaptureCount) == sizeof(LONG));
316 InterlockedIncrement(&DrvInstance.CaptureCount);
317 return STATUS_SUCCESS;
318}
319
320NTSTATUS _stdcall VBoxUSBClose()
321{
322 ACQUIRE_LOCK();
323 Assert(sizeof(DrvInstance.CaptureCount) == sizeof(LONG));
324 InterlockedDecrement(&DrvInstance.CaptureCount);
325 Assert(DrvInstance.CaptureCount >= 0);
326 VBoxUSBFilterRemoveOwner(RTProcSelf());
327
328 if (DrvInstance.CaptureCount == 0)
329 {
330 DrvInstance.cUSBDevices = 0;
331 }
332 RELEASE_LOCK();
333 return STATUS_SUCCESS;
334}
335
336
337unsigned myxdigit(char c)
338{
339 if (c >= 'a' && c <= 'z')
340 c = c - 'a' + 'A';
341 if (c >= '0' && c <= '9')
342 return c - '0';
343 if (c >= 'A' && c <= 'F')
344 return c - 'A' + 10;
345 return 0;
346}
347
348#if 1
349bool VBoxMatchFilter(PDEVICE_OBJECT pdo)
350{
351 USBFILTER Device;
352 int index;
353 PFLTUSB_DEVICE USBDevice;
354
355 if (DrvInstance.fForceGrab)
356 {
357 DebugPrint(("VBoxMatchFilter -> Force Grab -> TRUE\n"));
358 return true;
359 }
360 if (DrvInstance.fDisableFilters)
361 {
362 DebugPrint(("VBoxMatchFilter -> filters disabled -> FALSE\n"));
363 return false;
364 }
365
366 index = VBoxUSBIsKnownPDO(pdo);
367 if (index == -1)
368 {
369 DebugPrint(("VBoxMatchFilter -> unknown PDO -> FALSE\n"));
370 return false;
371 }
372 ACQUIRE_LOCK();
373
374 USBDevice = &DrvInstance.USBDevice[index];
375 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
376
377 USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, USBDevice->idVendor, true);
378 USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, USBDevice->idProduct, true);
379 USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_REV, USBDevice->bcdDevice, true);
380 USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_CLASS, USBDevice->bClass, true);
381 USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_SUB_CLASS, USBDevice->bSubClass, true);
382 USBFilterSetNumExact(&Device, USBFILTERIDX_DEVICE_PROTOCOL, USBDevice->bProtocol, true);
383 USBFilterSetStringExact(&Device, USBFILTERIDX_MANUFACTURER_STR, USBDevice->szMfgName, true);
384 USBFilterSetStringExact(&Device, USBFILTERIDX_PRODUCT_STR, USBDevice->szProduct, true);
385 USBFilterSetStringExact(&Device, USBFILTERIDX_SERIAL_NUMBER_STR, USBDevice->szSerial, true);
386
387 /* Run filters on the thing. */
388 uintptr_t uId = 0;
389 RTPROCESS Owner = VBoxUSBFilterMatch(&Device, &uId);
390 USBFilterDelete(&Device);
391 if (Owner == NIL_RTPROCESS)
392 {
393 RELEASE_LOCK();
394 return false;
395 }
396 DebugPrint(("VBoxMatchFilter: HIT\n"));
397 RELEASE_LOCK();
398 return true;
399}
400#else
401bool VBoxMatchFilter(WCHAR *pszDeviceId)
402{
403 //#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
404 uint16_t pId;
405 uint16_t vId;
406// char szRevision[4];
407#ifdef DEBUG
408 WCHAR *pszOrgDeviceId = pszDeviceId;
409#endif
410 USBFILTER Device;
411
412 if (DrvInstance.fForceGrab)
413 {
414 DebugPrint(("VBoxMatchFilter -> Force Grab -> TRUE\n"));
415 return true;
416 }
417 if (DrvInstance.fDisableFilters)
418 {
419 DebugPrint(("VBoxMatchFilter -> filters disabled -> FALSE\n"));
420 return false;
421 }
422
423 if (RtlCompareMemory(pszDeviceId, L"USB\\", 4*sizeof(WCHAR)) != 4*sizeof(WCHAR))
424 return false;
425
426 while(*pszDeviceId != 0 && *pszDeviceId != '_')
427 pszDeviceId++;
428 if(*pszDeviceId == 0)
429 return false;
430 pszDeviceId++;
431
432 /* Vid_ skipped */
433 vId = myxdigit((CHAR)pszDeviceId[0]) << 12
434 | myxdigit((CHAR)pszDeviceId[1]) << 8
435 | myxdigit((CHAR)pszDeviceId[2]) << 4
436 | myxdigit((CHAR)pszDeviceId[3]) << 0;
437
438 while(*pszDeviceId != 0 && *pszDeviceId != '_')
439 pszDeviceId++;
440 if(*pszDeviceId == 0)
441 return false;
442 pszDeviceId++;
443
444 /* Pid_ skipped */
445 pId = myxdigit((CHAR)pszDeviceId[0]) << 12
446 | myxdigit((CHAR)pszDeviceId[1]) << 8
447 | myxdigit((CHAR)pszDeviceId[2]) << 4
448 | myxdigit((CHAR)pszDeviceId[3]) << 0;
449
450 ACQUIRE_LOCK();
451
452 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
453
454 USBFilterSetNumExact(&Device, USBFILTERIDX_VENDOR_ID, vId, true);
455 USBFilterSetNumExact(&Device, USBFILTERIDX_PRODUCT_ID, pId, true);
456
457 /* Run filters on the thing. */
458 uintptr_t uId = 0;
459 RTPROCESS Owner = VBoxUSBFilterMatch(&Device, &uId);
460 USBFilterDelete(&Device);
461 if (Owner == NIL_RTPROCESS)
462 {
463 RELEASE_LOCK();
464 return false;
465 }
466 DebugPrint(("VBoxMatchFilter: HIT\n"));
467 RELEASE_LOCK();
468 return true;
469}
470#endif
471
472bool VBoxUSBAddDevice(PDEVICE_OBJECT pdo)
473{
474 if (VBoxUSBIsKnownPDO(pdo) != -1)
475 return true;
476
477 ACQUIRE_LOCK()
478 for (int i=0;i<MAX_ATTACHED_USB_DEVICES;i++)
479 {
480 if (DrvInstance.USBDevice[i].fAttached == false)
481 {
482 DebugPrint(("VBoxUSBAddDevice %p\n", pdo));
483 DrvInstance.USBDevice[i].fAttached = true;
484 DrvInstance.USBDevice[i].Pdo = pdo;
485 DrvInstance.USBDevice[i].fCaptured = false;
486 Assert(DrvInstance.cUSBDevices <= MAX_ATTACHED_USB_DEVICES);
487
488 DebugPrint(("Signal USB change ADD\n"));
489 RELEASE_LOCK();
490 /* There doesn't appear to be any good way to get device information
491 * from Windows. Reading its descriptor should do the trick though.
492 */
493 VBoxUSBGetDeviceIdStrings(pdo, &DrvInstance.USBDevice[i]);
494
495 InterlockedIncrement(&DrvInstance.cUSBStateChange);
496 return true;
497 }
498 }
499 RELEASE_LOCK();
500 return false;
501}
502
503int VBoxUSBIsKnownPDO(PDEVICE_OBJECT pdo)
504{
505 Assert(pdo);
506 ACQUIRE_LOCK();
507 for (int i=0;i<MAX_ATTACHED_USB_DEVICES;i++)
508 {
509 if (DrvInstance.USBDevice[i].Pdo == pdo)
510 {
511 RELEASE_LOCK();
512 return i;
513 }
514 }
515 RELEASE_LOCK();
516 return -1;
517}
518
519bool VBoxUSBRemoveDevice(PDEVICE_OBJECT pdo)
520{
521 ACQUIRE_LOCK();
522
523 for (int i=0;i<MAX_ATTACHED_USB_DEVICES;i++)
524 {
525 if (DrvInstance.USBDevice[i].Pdo == pdo)
526 {
527 DebugPrint(("VBoxUSBRemoveDevice %p\n", pdo));
528 DrvInstance.USBDevice[i].fAttached = false;
529 DrvInstance.USBDevice[i].Pdo = NULL;
530
531 if (DrvInstance.USBDevice[i].fCaptured == true)
532 {
533 InterlockedDecrement(&DrvInstance.cUSBDevices);
534 Assert(DrvInstance.cUSBDevices >= 0);
535
536 DrvInstance.USBDevice[i].fCaptured = false;
537 }
538
539 DebugPrint(("Signal USB change REMOVE\n"));
540 InterlockedIncrement(&DrvInstance.cUSBStateChange);
541
542 RELEASE_LOCK();
543 return true;
544 }
545 }
546 RELEASE_LOCK();
547 return false;
548}
549
550bool VBoxUSBCaptureDevice(PDEVICE_OBJECT pdo)
551{
552 Assert(DrvInstance.CaptureCount);
553 if (DrvInstance.CaptureCount == 0)
554 return false;
555
556 ACQUIRE_LOCK();
557 for (int i=0;i<MAX_ATTACHED_USB_DEVICES;i++)
558 {
559 if ( DrvInstance.USBDevice[i].Pdo == pdo
560 && DrvInstance.USBDevice[i].fCaptured == false)
561 {
562 DebugPrint(("VBoxUSBCaptureDevice %p\n", pdo));
563
564 Assert(DrvInstance.USBDevice[i].fAttached);
565
566 DrvInstance.USBDevice[i].fCaptured = true;
567 InterlockedIncrement(&DrvInstance.cUSBDevices);
568 RELEASE_LOCK();
569 return true;
570 }
571 }
572 RELEASE_LOCK();
573 return false;
574}
575
576void VBoxUSBDeviceArrived(PDEVICE_OBJECT pdo)
577{
578 /* If we manually release a device, then all filters will be temporarily disabled; Enable them again when the
579 * device has been started.
580 */
581 DrvInstance.fDisableFilters = false;
582
583 /* If we manually capture a device, we are forced to grab the next device that arrives. Disable this mode here */
584 DrvInstance.fForceGrab = false;
585 return;
586}
587
588bool VBoxUSBDeviceIsCaptured(PDEVICE_OBJECT pdo)
589{
590 bool ret;
591
592 ACQUIRE_LOCK();
593 for (int i=0;i<MAX_ATTACHED_USB_DEVICES;i++)
594 {
595 if (DrvInstance.USBDevice[i].Pdo == pdo)
596 {
597 ret = DrvInstance.USBDevice[i].fCaptured;
598 RELEASE_LOCK();
599 return ret;
600 }
601 }
602 RELEASE_LOCK();
603 return false;
604}
605
606/**
607 * Send USB ioctl
608 *
609 * @returns NT Status
610 * @param pDevObj USB device pointer
611 * @param control_code ioctl
612 * @param buffer Descriptor buffer
613 * @param size size of buffer
614 */
615NTSTATUS VBoxUSBSendIOCTL(PDEVICE_OBJECT pDevObj, ULONG control_code, void *buffer, uint32_t size)
616{
617 IO_STATUS_BLOCK io_status;
618 KEVENT event;
619 NTSTATUS status;
620 IRP *pIrp;
621 PIO_STACK_LOCATION stackloc;
622
623 KeInitializeEvent(&event, NotificationEvent, FALSE);
624
625 pIrp = IoBuildDeviceIoControlRequest(control_code, pDevObj, NULL, 0, NULL, 0, TRUE, &event, &io_status);
626 if (!pIrp)
627 {
628 AssertMsgFailed(("IoBuildDeviceIoControlRequest failed!!\n"));
629 return STATUS_INSUFFICIENT_RESOURCES;
630 }
631
632 /* Get the next stack location as that is used for the new irp */
633 stackloc = IoGetNextIrpStackLocation(pIrp);
634 stackloc->Parameters.Others.Argument1 = buffer;
635 stackloc->Parameters.Others.Argument2 = NULL;
636
637 status = IoCallDriver(pDevObj, pIrp);
638 if (status == STATUS_PENDING)
639 {
640 DebugPrint(("IoCallDriver returned STATUS_PENDING!!\n"));
641 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
642 status = io_status.Status;
643 }
644
645 DebugPrint(("IoCallDriver returned %x\n", status));
646
647 return status;
648}
649
650/**
651 * Get USB descriptor
652 *
653 * @returns NT Status
654 * @param pDevObj USB device pointer
655 * @param buffer Descriptor buffer
656 * @param size size of buffer
657 * @param type descriptor type
658 * @param index descriptor index
659 * @param language_id descriptor language id
660 */
661NTSTATUS VBoxUSBGetDescriptor(PDEVICE_OBJECT pDevObj, void *buffer, int size, int type, int index, int language_id)
662{
663 NTSTATUS rc;
664 PURB urb;
665
666 urb = (PURB)ExAllocatePool(NonPagedPool,sizeof(URB));
667 if(urb == NULL)
668 {
669 DebugPrint(("Failed to alloc mem for urb\n"));
670 return STATUS_INSUFFICIENT_RESOURCES;
671 }
672 memset(urb, 0, sizeof(*urb));
673
674 urb->UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
675 urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
676 urb->UrbControlDescriptorRequest.TransferBufferLength = size;
677 urb->UrbControlDescriptorRequest.TransferBuffer = buffer;
678 urb->UrbControlDescriptorRequest.Index = (UCHAR)index;
679 urb->UrbControlDescriptorRequest.DescriptorType = (UCHAR)type;
680 urb->UrbControlDescriptorRequest.LanguageId = (USHORT)language_id;
681
682 rc = VBoxUSBSendIOCTL(pDevObj, IOCTL_INTERNAL_USB_SUBMIT_URB, urb, sizeof(*urb));
683#ifdef DEBUG
684 if(!NT_SUCCESS(rc) || !USBD_SUCCESS(urb->UrbHeader.Status))
685 DebugPrint(("VBoxUSBGetDescriptor: VBoxUSBSendIOCTL failed with %x (%x)\n", rc, urb->UrbHeader.Status));
686#endif
687
688 ExFreePool(urb);
689 return rc;
690}
691
692/**
693 * Get a valid USB string descriptor language ID (the first ID found).
694 *
695 * @returns NT Status
696 * @param pDevObj USB device pointer
697 * @param lang_id pointer to language id
698 */
699NTSTATUS VBoxUSBGetLangID(PDEVICE_OBJECT pDevObj, int *lang_id)
700{
701 NTSTATUS status;
702 unsigned length;
703 char buffer[MAXIMUM_USB_STRING_LENGTH];
704 PUSB_STRING_DESCRIPTOR pstrdescr = (PUSB_STRING_DESCRIPTOR)&buffer;
705
706 Assert(lang_id);
707 *lang_id = 0;
708
709 length = sizeof(buffer);
710 memset(pstrdescr, 0, length);
711 pstrdescr->bLength = length;
712 pstrdescr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE;
713
714 status = VBoxUSBGetDescriptor(pDevObj, pstrdescr, length, USB_STRING_DESCRIPTOR_TYPE, 0, 0);
715 if (!NT_SUCCESS(status))
716 {
717 DebugPrint(("VBoxUSBGetLangID: language ID table not present (?)\n"));
718 goto fail;
719 }
720 /* Just grab the first lang ID if available. In 99% cases, it will be US English (0x0409).*/
721 if (pstrdescr->bLength >= sizeof(USB_STRING_DESCRIPTOR))
722 {
723 Assert(sizeof(pstrdescr->bString[0]) == sizeof(uint16_t));
724 *lang_id = pstrdescr->bString[0];
725 status = STATUS_SUCCESS;
726 }
727 else
728 status = STATUS_INVALID_PARAMETER;
729fail:
730 return status;
731}
732
733NTSTATUS VBoxUSBGetStringDescriptor(PDEVICE_OBJECT pDevObj, char *dest, unsigned size, int index, int lang_id)
734{
735 NTSTATUS status;
736 PUSB_STRING_DESCRIPTOR pstrdescr = NULL;
737 unsigned length;
738 UNICODE_STRING ustr;
739 ANSI_STRING astr;
740
741 *dest = '\0';
742 if (index)
743 {
744 /* An entire USB string descriptor is Unicode and can't be longer than 256 bytes.
745 * Hence 128 bytes is enough for an ASCII string.
746 */
747 length = sizeof(USB_STRING_DESCRIPTOR) + MAX_USB_SERIAL_STRING * sizeof(pstrdescr->bString[0]);
748 pstrdescr = (PUSB_STRING_DESCRIPTOR)ExAllocatePool(NonPagedPool, length);
749 if (!pstrdescr)
750 {
751 AssertMsgFailed(("VBoxUSBGetStringDescriptor: ExAllocatePool failed\n"));
752 status = STATUS_INSUFFICIENT_RESOURCES;
753 goto fail;
754 }
755 memset(pstrdescr, 0, length);
756 pstrdescr->bLength = length;
757 pstrdescr->bDescriptorType = USB_STRING_DESCRIPTOR_TYPE;
758
759 status = VBoxUSBGetDescriptor(pDevObj, pstrdescr, length, USB_STRING_DESCRIPTOR_TYPE, index, lang_id);
760 if (!NT_SUCCESS(status))
761 {
762 DebugPrint(("VBoxUSBGetStringDescriptor: requested string not present (?)\n"));
763 status = STATUS_SUCCESS; //not fatal
764 goto fail;
765 }
766 if (pstrdescr->bLength > sizeof(USB_STRING_DESCRIPTOR))
767 {
768 RtlInitUnicodeString(&ustr, pstrdescr->bString);
769 RtlInitAnsiString(&astr, NULL);
770 RtlUnicodeStringToAnsiString(&astr, &ustr, TRUE);
771 strncpy(dest, astr.Buffer, size);
772 RtlFreeAnsiString(&astr);
773 }
774 }
775 status = STATUS_SUCCESS;
776fail:
777 if (pstrdescr)
778 ExFreePool(pstrdescr);
779 return status;
780}
781
782NTSTATUS VBoxUSBGetDeviceIdStrings(PDEVICE_OBJECT pDevObj, PFLTUSB_DEVICE pFltDev)
783{
784 NTSTATUS status;
785 PUSB_DEVICE_DESCRIPTOR devdescr = 0;
786
787 devdescr = (PUSB_DEVICE_DESCRIPTOR)ExAllocatePool(NonPagedPool, sizeof(USB_DEVICE_DESCRIPTOR));
788 if (devdescr == NULL)
789 {
790 DebugPrint(("Failed to alloc mem for urb\n"));
791 status = STATUS_INSUFFICIENT_RESOURCES;
792 goto fail;
793 }
794 memset(devdescr, 0, sizeof(*devdescr));
795
796 status = VBoxUSBGetDescriptor(pDevObj, devdescr, sizeof(*devdescr), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0);
797 if (!NT_SUCCESS(status))
798 {
799 AssertMsgFailed(("VBoxUSBGetDeviceDescription: getting device descriptor failed\n"));
800 goto fail;
801 }
802 DebugPrint(("Device pid=%x vid=%x rev=%x\n", devdescr->idVendor, devdescr->idProduct, devdescr->bcdDevice));
803 pFltDev->idVendor = devdescr->idVendor;
804 pFltDev->idProduct = devdescr->idProduct;
805 pFltDev->bcdDevice = devdescr->bcdDevice;
806 pFltDev->bClass = devdescr->bDeviceClass;
807 pFltDev->bSubClass = devdescr->bDeviceSubClass;
808 pFltDev->bProtocol = devdescr->bDeviceProtocol;
809 pFltDev->szSerial[0] = 0;
810 pFltDev->szMfgName[0] = 0;
811 pFltDev->szProduct[0] = 0;
812
813 /* If there are no strings, don't even try to get any string descriptors. */
814 if (devdescr->iSerialNumber || devdescr->iManufacturer || devdescr->iProduct)
815 {
816 int langId;
817
818 status = VBoxUSBGetLangID(pDevObj, &langId);
819 if (!NT_SUCCESS(status))
820 {
821 AssertMsgFailed(("VBoxUSBGetDeviceDescription: reading language ID failed\n"));
822 goto fail;
823 }
824 status = VBoxUSBGetStringDescriptor(pDevObj, pFltDev->szSerial, sizeof(pFltDev->szSerial), devdescr->iSerialNumber, langId);
825 if (!NT_SUCCESS(status))
826 {
827 AssertMsgFailed(("VBoxUSBGetDeviceDescription: reading serial number failed\n"));
828 goto fail;
829 }
830 status = VBoxUSBGetStringDescriptor(pDevObj, pFltDev->szMfgName, sizeof(pFltDev->szMfgName), devdescr->iManufacturer, langId);
831 if (!NT_SUCCESS(status))
832 {
833 AssertMsgFailed(("VBoxUSBGetDeviceDescription: reading manufacturer name failed\n"));
834 goto fail;
835 }
836 status = VBoxUSBGetStringDescriptor(pDevObj, pFltDev->szProduct, sizeof(pFltDev->szProduct), devdescr->iProduct, langId);
837 if (!NT_SUCCESS(status))
838 {
839 AssertMsgFailed(("VBoxUSBGetDeviceDescription: reading product name failed\n"));
840 goto fail;
841 }
842
843 DebugPrint(("VBoxUSBGetStringDescriptor: strings: '%s':'%s':'%s' (lang ID %x)\n",
844 pFltDev->szMfgName, pFltDev->szProduct, pFltDev->szSerial, langId));
845 }
846 status = STATUS_SUCCESS;
847
848fail:
849 if (devdescr)
850 ExFreePool(devdescr);
851 return status;
852}
853
854/**
855 * Get USB device description
856 *
857 * @returns NT Status
858 * @param pDevObj USB device pointer
859 * @param pusVendorId Vendor id (out)
860 * @param pusProductId Product id (out)
861 * @param pusRevision Revision (out)
862 */
863NTSTATUS VBoxUSBGetDeviceDescription(PDEVICE_OBJECT pDevObj, USHORT *pusVendorId, USHORT *pusProductId, USHORT *pusRevision)
864{
865 NTSTATUS status;
866 PUSB_DEVICE_DESCRIPTOR devdescr = 0;
867
868 devdescr = (PUSB_DEVICE_DESCRIPTOR)ExAllocatePool(NonPagedPool,sizeof(USB_DEVICE_DESCRIPTOR));
869 if(devdescr == NULL)
870 {
871 DebugPrint(("Failed to alloc mem for urb\n"));
872 status = STATUS_INSUFFICIENT_RESOURCES;
873 goto fail;
874 }
875 memset(devdescr, 0, sizeof(*devdescr));
876
877 status = VBoxUSBGetDescriptor(pDevObj, devdescr, sizeof(*devdescr), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0);
878 if (!NT_SUCCESS(status))
879 {
880 DebugPrint(("VBoxUSBGetDeviceDescription: getting device descriptor failed\n"));
881 goto fail;
882 }
883 DebugPrint(("Device pid=%x vid=%x rev=%x\n", devdescr->idVendor, devdescr->idProduct, devdescr->bcdDevice));
884 *pusVendorId = devdescr->idVendor;
885 *pusProductId = devdescr->idProduct;
886 *pusRevision = devdescr->bcdDevice;
887
888 ExFreePool(devdescr);
889 return STATUS_SUCCESS;
890
891fail:
892 if (devdescr)
893 ExFreePool(devdescr);
894 return status;
895}
896
897/**
898 * Unplug and replug the specified USB device
899 *
900 * @returns NT status code
901 * @param usVendorId Vendor id
902 * @param usProductId Product id
903 * @param usRevision Revision
904 * @param fCaptured Already captured or not
905 * @param pfReplugged Replugged or not (out)
906 */
907NTSTATUS VBoxUSBReplugDevice(USHORT usVendorId, USHORT usProductId, USHORT usRevision, bool fCaptured, bool *pfReplugged)
908{
909 NTSTATUS status;
910 UNICODE_STRING szStandardControllerName[RT_ELEMENTS(lpszStandardControllerName)];
911
912 DebugPrint(("VBoxUSBReplugDevice: %04X %04X %04X\n", usVendorId, usProductId, usRevision));
913
914 Assert(pfReplugged);
915 *pfReplugged = false;
916
917 for (int i=0;i<RT_ELEMENTS(lpszStandardControllerName);i++)
918 {
919 szStandardControllerName[i].Length = 0;
920 szStandardControllerName[i].MaximumLength = 0;
921 szStandardControllerName[i].Buffer = 0;
922
923 RtlInitUnicodeString(&szStandardControllerName[i], lpszStandardControllerName[i]);
924 }
925
926 for (int i=0;i<16;i++)
927 {
928 char szHubName[32];
929 UNICODE_STRING UnicodeName;
930 ANSI_STRING AnsiName;
931 PDEVICE_OBJECT pHubDevObj;
932 PFILE_OBJECT pHubFileObj;
933
934 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
935
936 UnicodeName.Length = 0;
937 UnicodeName.MaximumLength = 0;
938 UnicodeName.Buffer = 0;
939
940 RtlInitAnsiString(&AnsiName, szHubName);
941 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
942
943 status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
944 if (status == STATUS_SUCCESS)
945 {
946 DebugPrint(("IoGetDeviceObjectPointer for %s returned %p %p\n", szHubName, pHubDevObj, pHubFileObj));
947
948 if ( pHubDevObj->DriverObject
949 && pHubDevObj->DriverObject->DriverName.Buffer
950 && pHubDevObj->DriverObject->DriverName.Length
951 )
952 {
953 for (int j=0;j<RT_ELEMENTS(lpszStandardControllerName);j++)
954 {
955 if (!RtlCompareUnicodeString(&szStandardControllerName[j], &pHubDevObj->DriverObject->DriverName, TRUE /* case insensitive */))
956 {
957 PDEVICE_RELATIONS pDevRelations = NULL;
958
959 DebugPrint(("Associated driver %wZ -> related dev obj=%p\n", pHubDevObj->DriverObject->DriverName, IoGetRelatedDeviceObject(pHubFileObj)));
960
961 status = VBoxUSBQueryBusRelations(pHubDevObj, pHubFileObj, &pDevRelations);
962 if ( status == STATUS_SUCCESS
963 && pDevRelations)
964 {
965 for (unsigned k=0;k<pDevRelations->Count;k++)
966 {
967 USHORT usPDOVendorId, usPDOProductId, usPDORevision;
968
969 DebugPrint(("Found existing USB PDO %p\n", pDevRelations->Objects[k]));
970 VBoxUSBGetDeviceDescription(pDevRelations->Objects[k], &usPDOVendorId, &usPDOProductId, &usPDORevision);
971
972 if ( VBoxUSBDeviceIsCaptured(pDevRelations->Objects[k]) == fCaptured
973 && usPDOVendorId == usVendorId
974 && usPDOProductId == usProductId
975 && usPDORevision == usRevision)
976 {
977 DebugPrint(("REPLUG device -> \n"));
978 /* Simulate a device replug */
979 status = VBoxUSBSendIOCTL(pDevRelations->Objects[k], IOCTL_INTERNAL_USB_CYCLE_PORT, NULL, 0);
980
981 *pfReplugged = true;
982 }
983 ObDereferenceObject(pDevRelations->Objects[k]);
984 if (*pfReplugged == true)
985 break;
986 }
987 ExFreePool(pDevRelations);
988 }
989 if (*pfReplugged == true)
990 break;
991 }
992 }
993 }
994 ObDereferenceObject(pHubFileObj);
995 }
996 RtlFreeUnicodeString(&UnicodeName);
997 if (*pfReplugged == true)
998 break;
999 }
1000
1001 return STATUS_SUCCESS;
1002}
1003
1004/**
1005 * Capture specified USB device
1006 *
1007 * @returns NT status code
1008 * @param usVendorId Vendor id
1009 * @param usProductId Product id
1010 * @param usRevision Revision
1011 */
1012NTSTATUS VBoxUSBReleaseDevice(USHORT usVendorId, USHORT usProductId, USHORT usRevision)
1013{
1014 NTSTATUS status;
1015 bool fReplugged;
1016
1017 DebugPrint(("VBoxUSBReleaseDevice\n"));
1018
1019 DrvInstance.fDisableFilters = true;
1020 status = VBoxUSBReplugDevice(usVendorId, usProductId, usRevision, true, &fReplugged);
1021 if ( status != STATUS_SUCCESS
1022 || !fReplugged)
1023 DrvInstance.fDisableFilters = false;
1024 return status;
1025}
1026
1027/**
1028 * Capture specified USB device
1029 *
1030 * @returns NT status code
1031 * @param usVendorId Vendor id
1032 * @param usProductId Product id
1033 * @param usRevision Revision
1034 */
1035NTSTATUS VBoxUSBGrabDevice(USHORT usVendorId, USHORT usProductId, USHORT usRevision)
1036{
1037 NTSTATUS status;
1038 bool fReplugged;
1039
1040 DebugPrint(("VBoxUSBGrabDevice\n"));
1041
1042 DrvInstance.fForceGrab = true;
1043 status = VBoxUSBReplugDevice(usVendorId, usProductId, usRevision, false, &fReplugged);
1044 if ( status != STATUS_SUCCESS
1045 || !fReplugged)
1046 DrvInstance.fForceGrab = false;
1047 return status;
1048}
1049
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