VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/Monitor/USBMon.cpp@ 31896

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

export the VBoxUSB host driver to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.2 KB
Line 
1/** @file
2 *
3 * VBox USB drivers - USB Monitor driver - Win32 host:
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * Oracle Corporation confidential
10 * All rights reserved
11 */
12
13
14#include "USBMon.h"
15#include <VBox/usblib.h>
16#include <excpt.h>
17#include <stdio.h>
18
19/*
20 * Note: Must match the VID & PID in the USB driver .inf file!!
21 */
22/*
23 BusQueryDeviceID USB\Vid_80EE&Pid_CAFE
24 BusQueryInstanceID 2
25 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE&Rev_0100
26 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE
27 BusQueryCompatibleIDs USB\Class_ff&SubClass_00&Prot_00
28 BusQueryCompatibleIDs USB\Class_ff&SubClass_00
29 BusQueryCompatibleIDs USB\Class_ff
30*/
31
32#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
33#define szBusQueryHardwareIDs L"USB\\Vid_80EE&Pid_CAFE&Rev_0100\0USB\\Vid_80EE&Pid_CAFE\0\0"
34#define szBusQueryCompatibleIDs L"USB\\Class_ff&SubClass_00&Prot_00\0USB\\Class_ff&SubClass_00\0USB\\Class_ff\0\0"
35
36#define szDeviceTextDescription L"VirtualBox USB"
37
38static PDEVICE_OBJECT ControlDeviceObject = NULL;
39static PDRIVER_DISPATCH pfnOldPnPHandler = 0;
40
41static struct
42{
43 bool fValid;
44} InstalledPDOHooks[16] = {0};
45
46/**
47 * Driver entry point.
48 *
49 * @returns appropriate status code.
50 * @param pDrvObj Pointer to driver object.
51 * @param pRegPath Registry base path.
52 */
53NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
54{
55 NTSTATUS rc;
56 UNICODE_STRING DevName;
57 PDEVICE_OBJECT pDevObj;
58
59 DebugPrint(("VBoxUSBMon::DriverEntry\n"));
60
61 /*
62 * Create device.
63 * (That means creating a device object and a symbolic link so the DOS
64 * subsystems (OS/2, win32, ++) can access the device.)
65 */
66 RtlInitUnicodeString(&DevName, USBMON_DEVICE_NAME_NT);
67 rc = IoCreateDevice(pDrvObj, sizeof(DEVICE_EXTENSION), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
68 if (NT_SUCCESS(rc))
69 {
70 UNICODE_STRING DosName;
71
72 /* Save device object pointer in order to check whether we're being called in the entry points we register. */
73 ControlDeviceObject = pDevObj;
74
75 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
76 rc = IoCreateSymbolicLink(&DosName, &DevName);
77 if (NT_SUCCESS(rc))
78 {
79 ULONG ulIndex;
80 PDRIVER_DISPATCH *dispatch;
81
82 /*
83 * Initialize the device extension.
84 */
85 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
86 memset(pDevExt, 0, sizeof(*pDevExt));
87
88 /*
89 * Setup the driver entry points in pDrvObj.
90 */
91 for (ulIndex = 0, dispatch = pDrvObj->MajorFunction;
92 ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;
93 ulIndex++, dispatch++) {
94
95 *dispatch = VBoxUSBMonStub;
96 }
97
98 pDrvObj->DriverUnload = VBoxUSBMonUnload;
99 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxUSBMonCreate;
100 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxUSBMonClose;
101 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxUSBMonDeviceControl;
102
103// pDrvObj->MajorFunction[IRP_MJ_PNP] = VBoxUSBMonDispatchPnp;
104// pDrvObj->MajorFunction[IRP_MJ_POWER] = VBoxUSBMonDispatchPower;
105 /* Note: unable to unload driver if this is set: */
106//// pDrvObj->DriverExtension->AddDevice = VBoxUSBMonAddDevice;
107
108 VBoxUSBInit();
109 DebugPrint(("VBoxUSBMon::DriverEntry returning STATUS_SUCCESS\n"));
110 return STATUS_SUCCESS;
111 }
112 else
113 DebugPrint(("IoCreateSymbolicLink failed with rc=%#x!\n", rc));
114
115 IoDeleteDevice(pDevObj);
116 }
117 else
118 DebugPrint(("IoCreateDevice failed with rc=%#x!\n", rc));
119
120 if (NT_SUCCESS(rc))
121 rc = STATUS_INVALID_PARAMETER;
122 DebugPrint(("VBoxUSBMon::DriverEntry returning %#x\n", rc));
123 return rc;
124}
125
126/**
127 * Uninstall the PnP irp hook
128 *
129 * @param pDevExt Device extension
130 */
131void VBoxUSBUninstallPnPHook(PDEVICE_EXTENSION pDevExt)
132{
133 NTSTATUS status;
134 UNICODE_STRING szStandardHubName;
135
136 szStandardHubName.Length = 0;
137 szStandardHubName.MaximumLength = 0;
138 szStandardHubName.Buffer = 0;
139 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
140
141 DebugPrint(("Unhook USB hub drivers\n"));
142 for (int i = 0; i < RT_ELEMENTS(InstalledPDOHooks); i++)
143 {
144 char szHubName[32];
145 UNICODE_STRING UnicodeName;
146 ANSI_STRING AnsiName;
147 PDEVICE_OBJECT pHubDevObj;
148 PFILE_OBJECT pHubFileObj;
149
150 /* Don't bother to check PDO's that we haven't hooked; might even lead to host crashes during shutdown as IoGetDeviceObjectPointer can reopen a driver. */
151 if (!InstalledPDOHooks[i].fValid)
152 continue;
153
154 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
155
156 UnicodeName.Length = 0;
157 UnicodeName.MaximumLength = 0;
158 UnicodeName.Buffer = 0;
159
160 RtlInitAnsiString(&AnsiName, szHubName);
161 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
162
163 status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
164 if (status == STATUS_SUCCESS)
165 {
166 DebugPrint(("IoGetDeviceObjectPointer for %s returned %p %p\n", szHubName, pHubDevObj, pHubFileObj));
167
168 if ( pHubDevObj->DriverObject
169 && pHubDevObj->DriverObject->DriverName.Buffer
170 && pHubDevObj->DriverObject->DriverName.Length
171 && !RtlCompareUnicodeString(&szStandardHubName, &pHubDevObj->DriverObject->DriverName, TRUE /* case insensitive */))
172 {
173#if 0
174 DebugPrint(("Associated driver"));
175 DebugPrintUnicodeString(&pHubDevObj->DriverObject->DriverName);
176#endif
177 DebugPrint(("pnp handler %p\n", pHubDevObj->DriverObject->MajorFunction[IRP_MJ_PNP]));
178 InterlockedCompareExchangePointer((PVOID *)&pHubDevObj->DriverObject->MajorFunction[IRP_MJ_PNP], pfnOldPnPHandler, VBoxUSBMonPnPHook);
179 }
180 ObDereferenceObject(pHubFileObj);
181 }
182// else
183// DebugPrint(("IoGetDeviceObjectPointer for %s returned %x\n", szHubName, status));
184
185 RtlFreeUnicodeString(&UnicodeName);
186 }
187 pDevExt->fHookDevice = FALSE;
188 pfnOldPnPHandler = NULL;
189}
190
191/**
192 * Unload the driver.
193 *
194 * @param pDrvObj Driver object.
195 */
196void _stdcall VBoxUSBMonUnload(PDRIVER_OBJECT pDrvObj)
197{
198 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDrvObj->DeviceObject->DeviceExtension;
199
200 DebugPrint(("VBoxUSBMonUnload pDevExt=%p ControlDeviceObject=%p\n", pDevExt, ControlDeviceObject));
201
202 Assert(!pfnOldPnPHandler);
203 if (pfnOldPnPHandler) /* very bad! */
204 VBoxUSBUninstallPnPHook(pDevExt);
205
206 /* Clean up the filter manager */
207 VBoxUSBTerm();
208
209 /*
210 * We ASSUME that it's not possible to unload a driver with open handles.
211 * Start by deleting the symbolic link
212 */
213 UNICODE_STRING DosName;
214 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
215 NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
216
217 IoDeleteDevice(pDrvObj->DeviceObject);
218}
219
220
221/**
222 * Create (i.e. Open) file entry point.
223 *
224 * @param pDevObj Device object.
225 * @param pIrp Request packet.
226 */
227NTSTATUS _stdcall VBoxUSBMonCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
228{
229 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
230 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
231 NTSTATUS status;
232
233 DebugPrint(("VBoxUSBMonCreate\n"));
234
235 /*
236 * We are not remotely similar to a directory...
237 * (But this is possible.)
238 */
239 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
240 {
241 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
242 pIrp->IoStatus.Information = 0;
243 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
244 return STATUS_NOT_A_DIRECTORY;
245 }
246
247 VBoxUSBCreate();
248
249 if (InterlockedIncrement(&pDevExt->cOpened) == 1)
250 {
251 UNICODE_STRING szStandardHubName;
252
253 pDevExt->fHookDevice = TRUE;
254
255 szStandardHubName.Length = 0;
256 szStandardHubName.MaximumLength = 0;
257 szStandardHubName.Buffer = 0;
258 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
259
260 DebugPrint(("Hook USB hub drivers\n"));
261 for (int i = 0; i < RT_ELEMENTS(InstalledPDOHooks); i++)
262 {
263 char szHubName[32];
264 UNICODE_STRING UnicodeName;
265 ANSI_STRING AnsiName;
266 PDEVICE_OBJECT pHubDevObj;
267 PFILE_OBJECT pHubFileObj;
268
269 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
270
271 InstalledPDOHooks[i].fValid = false;
272
273 UnicodeName.Length = 0;
274 UnicodeName.MaximumLength = 0;
275 UnicodeName.Buffer = 0;
276
277 RtlInitAnsiString(&AnsiName, szHubName);
278 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, TRUE);
279
280 status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
281 if (status == STATUS_SUCCESS)
282 {
283 DebugPrint(("IoGetDeviceObjectPointer for %s returned %p %p\n", szHubName, pHubDevObj, pHubFileObj));
284
285 if ( pHubDevObj->DriverObject
286 && pHubDevObj->DriverObject->DriverName.Buffer
287 && pHubDevObj->DriverObject->DriverName.Length
288 && !RtlCompareUnicodeString(&szStandardHubName, &pHubDevObj->DriverObject->DriverName, TRUE /* case insensitive */))
289 {
290#if 0
291 DebugPrint(("Associated driver"));
292 DebugPrintUnicodeString(&pHubDevObj->DriverObject->DriverName);
293#endif
294 DebugPrint(("pnp handler %p\n", pHubDevObj->DriverObject->MajorFunction[IRP_MJ_PNP]));
295 if ( !pfnOldPnPHandler
296 || pHubDevObj->DriverObject->MajorFunction[IRP_MJ_PNP] == pfnOldPnPHandler)
297 {
298 InstalledPDOHooks[i].fValid = true;
299 pfnOldPnPHandler = (PDRIVER_DISPATCH)InterlockedExchangePointer((PVOID *)&pHubDevObj->DriverObject->MajorFunction[IRP_MJ_PNP], VBoxUSBMonPnPHook);
300 }
301 }
302 ObDereferenceObject(pHubFileObj);
303 }
304// else
305// DebugPrint(("IoGetDeviceObjectPointer for %s returned %x\n", szHubName, status));
306
307 RtlFreeUnicodeString(&UnicodeName);
308 }
309
310 //
311 // Let us use remove lock to keep count of IRPs so that we don't
312 // detach and delete our deviceobject until all pending I/Os in our
313 // devstack are completed. Remlock is required to protect us from
314 // various race conditions where our driver can get unloaded while we
315 // are still running dispatch or completion code.
316 //
317
318 IoInitializeRemoveLock (&pDevExt->RemoveLock , POOL_TAG,
319 1, // MaxLockedMinutes
320 100); // HighWatermark, this parameter is
321 // used only on checked build. Specifies
322 // the maximum number of outstanding
323 // acquisitions allowed on the lock
324
325 DebugPrint(("VBoxUSBMon: remove lock = %x\n", pDevExt->RemoveLock.Common.RemoveEvent));
326 }
327
328 status = IoAcquireRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
329 if (!NT_SUCCESS(status))
330 {
331 DebugPrint(("IoAcquireRemoveLock failed with %x\n", status));
332 pIrp->IoStatus.Status = status;
333 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
334 return status;
335 }
336
337 pIrp->IoStatus.Information = 0;
338 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
339
340 return STATUS_SUCCESS;
341}
342
343
344/**
345 * Close file entry point.
346 *
347 * @param pDevObj Device object.
348 * @param pIrp Request packet.
349 */
350NTSTATUS _stdcall VBoxUSBMonClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
351{
352 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
353 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
354 PFILE_OBJECT pFileObj = pStack->FileObject;
355
356 DebugPrint(("VBoxUSBMonClose: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pFileObj->FsContext));
357
358 /* Uninstall hook when we close the last instance. */
359 if (InterlockedDecrement(&pDevExt->cOpened) == 0)
360 VBoxUSBUninstallPnPHook(pDevExt);
361
362 VBoxUSBClose();
363
364 /* Wait for all outstanding requests to complete */
365 /* We're supposed to use it in the remove device function. During unload
366 * is no option as that crashes Vista64
367 */
368 DebugPrint(("Waiting for outstanding requests\n"));
369 IoReleaseRemoveLockAndWait(&pDevExt->RemoveLock, ControlDeviceObject);
370
371 DebugPrint(("Done waiting.\n"));
372 pFileObj->FsContext = NULL;
373 pIrp->IoStatus.Information = 0;
374 pIrp->IoStatus.Status = STATUS_SUCCESS;
375 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
376
377 return STATUS_SUCCESS;
378}
379
380
381/**
382 * Device I/O Control entry point.
383 *
384 * @param pDevObj Device object.
385 * @param pIrp Request packet.
386 */
387NTSTATUS _stdcall VBoxUSBMonDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
388{
389 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
390 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
391 NTSTATUS status = STATUS_SUCCESS;
392
393 status = IoAcquireRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
394 if (!NT_SUCCESS(status))
395 {
396 DebugPrint(("IoAcquireRemoveLock failed with %x\n", status));
397 pIrp->IoStatus.Status = status;
398 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
399 return status;
400 }
401
402 /* Handle ioctl meant for us */
403 pIrp->IoStatus.Information = 0;
404 status = VBoxUSBDispatchIO(pDevObj, pIrp);
405 pIrp->IoStatus.Status = status;
406 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
407
408 /* Release the remove lock */
409 IoReleaseRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
410 return status;
411}
412
413/**
414 * Pass on or refuse entry point
415 *
416 * @param pDevObj Device object.
417 * @param pIrp Request packet.
418 */
419NTSTATUS _stdcall VBoxUSBMonStub(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
420{
421#ifdef DEBUG
422 PIO_STACK_LOCATION irpStack;
423
424 irpStack = IoGetCurrentIrpStackLocation(pIrp);
425 DebugPrint (("VBoxUSBMonStub %x\n", irpStack->MinorFunction));
426#endif
427
428 /* Meant for us; report error */
429 pIrp->IoStatus.Information = 0;
430 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
431 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
432
433 return STATUS_NOT_SUPPORTED;
434}
435
436
437/**
438 * Handle the specific PnP ioctls we need for stealing devices.
439 *
440 * @param irpStack Device object
441 * @param pIoStatus IO status of finished IRP
442 */
443NTSTATUS _stdcall VBoxUSBMonHandlePnPIoctl(PIO_STACK_LOCATION irpStack, PIO_STATUS_BLOCK pIoStatus)
444{
445 DebugPrint(("VBoxUSBMonHandlePnPIoctl IRQL = %d\n", KeGetCurrentIrql()));
446 switch(irpStack->MinorFunction)
447 {
448 case IRP_MN_QUERY_DEVICE_TEXT:
449 {
450 DebugPrint(("IRP_MN_QUERY_DEVICE_TEXT: pIoStatus->Status = %x\n", pIoStatus->Status));
451 if (pIoStatus->Status == STATUS_SUCCESS)
452 {
453 WCHAR *pId = (WCHAR *)pIoStatus->Information;
454 if (VALID_PTR(pId))
455 {
456 switch(irpStack->Parameters.QueryDeviceText.DeviceTextType)
457 {
458 case DeviceTextLocationInformation:
459 DebugPrint(("DeviceTextLocationInformation %ws\n", pId));
460 break;
461
462 case DeviceTextDescription:
463 DebugPrint(("DeviceTextDescription %ws\n", pId));
464 if (VBoxUSBDeviceIsCaptured(irpStack->DeviceObject))
465 {
466 WCHAR *pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szDeviceTextDescription));
467 if (!pId)
468 {
469 AssertFailed();
470 break;
471 }
472 memcpy(pId, szDeviceTextDescription, sizeof(szDeviceTextDescription));
473 DebugPrint(("NEW szDeviceTextDescription %ws\n", pId));
474 ExFreePool((PVOID)pIoStatus->Information);
475 pIoStatus->Information = (ULONG_PTR)pId;
476 }
477 break;
478 }
479 }
480 else
481 DebugPrint(("Invalid pointer %p\n", pId));
482 }
483 break;
484 }
485
486 case IRP_MN_QUERY_ID:
487 {
488 DebugPrint(("IRP_MN_QUERY_ID: Irp->pIoStatus->Status = %x\n", pIoStatus->Status));
489 if ( pIoStatus->Status == STATUS_SUCCESS
490 && irpStack->DeviceObject)
491 {
492 WCHAR *pId = (WCHAR *)pIoStatus->Information;
493#ifdef DEBUG
494 WCHAR *pTmp;
495#endif
496 if (VALID_PTR(pId))
497 {
498 switch(irpStack->Parameters.QueryDeviceRelations.Type)
499 {
500 case BusQueryInstanceID:
501 DebugPrint(("BusQueryInstanceID %ws\n", pId));
502 break;
503
504 case BusQueryDeviceID:
505 VBoxUSBAddDevice(irpStack->DeviceObject);
506 if (VBoxMatchFilter(irpStack->DeviceObject) == true)
507 {
508 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryDeviceId));
509 if (!pId)
510 {
511 AssertFailed();
512 break;
513 }
514 memcpy(pId, szBusQueryDeviceId, sizeof(szBusQueryDeviceId));
515 DebugPrint(("NEW BusQueryDeviceID %ws\n", pId));
516 ExFreePool((PVOID)pIoStatus->Information);
517 pIoStatus->Information = (ULONG_PTR)pId;
518 VBoxUSBCaptureDevice(irpStack->DeviceObject);
519 }
520 break;
521
522 case BusQueryHardwareIDs:
523#ifdef DEBUG
524 while(*pId) //MULTI_SZ
525 {
526 DebugPrint(("BusQueryHardwareIDs %ws\n", pId));
527 while(*pId) pId++;
528 pId++;
529 }
530#endif
531 VBoxUSBAddDevice(irpStack->DeviceObject);
532 if (VBoxMatchFilter(irpStack->DeviceObject) == true)
533 {
534 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryHardwareIDs));
535 if (!pId)
536 {
537 AssertFailed();
538 break;
539 }
540 memcpy(pId, szBusQueryHardwareIDs, sizeof(szBusQueryHardwareIDs));
541#ifdef DEBUG
542 pTmp = pId;
543 while(*pTmp) //MULTI_SZ
544 {
545 DebugPrint(("NEW BusQueryHardwareIDs %ws\n", pTmp));
546 while(*pTmp) pTmp++;
547 pTmp++;
548 }
549#endif
550 ExFreePool((PVOID)pIoStatus->Information);
551 pIoStatus->Information = (ULONG_PTR)pId;
552 VBoxUSBCaptureDevice(irpStack->DeviceObject);
553 }
554 break;
555
556 case BusQueryCompatibleIDs:
557#ifdef DEBUG
558 while(*pId) //MULTI_SZ
559 {
560 DebugPrint(("BusQueryCompatibleIDs %ws\n", pId));
561 while(*pId) pId++;
562 pId++;
563 }
564#endif
565 if (VBoxUSBDeviceIsCaptured(irpStack->DeviceObject))
566 {
567 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryCompatibleIDs));
568 if (!pId)
569 {
570 AssertFailed();
571 break;
572 }
573 memcpy(pId, szBusQueryCompatibleIDs, sizeof(szBusQueryCompatibleIDs));
574#ifdef DEBUG
575 pTmp = pId;
576 while(*pTmp) //MULTI_SZ
577 {
578 DebugPrint(("NEW BusQueryCompatibleIDs %ws\n", pTmp));
579 while(*pTmp) pTmp++;
580 pTmp++;
581 }
582#endif
583 ExFreePool((PVOID)pIoStatus->Information);
584 pIoStatus->Information = (ULONG_PTR)pId;
585 }
586 break;
587 }
588 }
589 else
590 DebugPrint(("Invalid pointer %p\n", pId));
591 }
592 break;
593 }
594
595#ifdef DEBUG
596 case IRP_MN_QUERY_DEVICE_RELATIONS:
597 {
598 switch(irpStack->Parameters.QueryDeviceRelations.Type)
599 {
600 case BusRelations:
601 {
602 DebugPrint(("BusRelations\n"));
603
604 if (pIoStatus->Status == STATUS_SUCCESS)
605 {
606 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)pIoStatus->Information;
607 DebugPrint(("pRel = %p\n", pRel));
608 if (VALID_PTR(pRel))
609 {
610 for (unsigned i=0;i<pRel->Count;i++)
611 {
612 if (VBoxUSBDeviceIsCaptured(irpStack->DeviceObject))
613 DebugPrint(("New PDO %p\n", pRel->Objects[i]));
614 }
615 }
616 else
617 DebugPrint(("Invalid pointer %p\n", pRel));
618 }
619 break;
620 }
621 case TargetDeviceRelation:
622 DebugPrint(("TargetDeviceRelation\n"));
623 break;
624 case RemovalRelations:
625 DebugPrint(("RemovalRelations\n"));
626 break;
627 case EjectionRelations:
628 DebugPrint(("EjectionRelations\n"));
629 break;
630 }
631 break;
632 }
633
634 case IRP_MN_QUERY_CAPABILITIES:
635 {
636 DebugPrint(("IRP_MN_QUERY_CAPABILITIES: pIoStatus->Status = %x\n", pIoStatus->Status));
637 if (pIoStatus->Status == STATUS_SUCCESS)
638 {
639 PDEVICE_CAPABILITIES pCaps = irpStack->Parameters.DeviceCapabilities.Capabilities;
640 if (VALID_PTR(pCaps))
641 {
642 DebugPrint(("Caps.SilentInstall = %d\n", pCaps->SilentInstall));
643 DebugPrint(("Caps.UniqueID = %d\n", pCaps->UniqueID ));
644 DebugPrint(("Caps.Address = %d\n", pCaps->Address ));
645 DebugPrint(("Caps.UINumber = %d\n", pCaps->UINumber ));
646 }
647 else
648 DebugPrint(("Invalid pointer %p\n", pCaps));
649 }
650 break;
651 }
652#endif
653 } /*switch */
654 DebugPrint(("VBoxUSBMonHandlePnPIoctl returns %x (IRQL = %d)\n", pIoStatus->Status, KeGetCurrentIrql()));
655 return pIoStatus->Status;
656}
657
658/**
659 * IRP completion notification callback. Used for selected PNP irps.
660 *
661 * @param pDevObj Device object.(always NULL!)
662 * @param pIrp Request packet.
663 * @param context User parameter (old IRP)
664 */
665NTSTATUS _stdcall VBoxUSBPnPCompletion(DEVICE_OBJECT *pDevObj, IRP *pIrp, void *context)
666{
667 /* Note: pDevObj is NULL! */
668 PIRP pOrgIrp = (PIRP)context;
669 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pOrgIrp);
670 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)ControlDeviceObject->DeviceExtension;
671
672 DebugPrint(("VBoxUSBPnPCompletion %p %p %p minor=%x\n", pDevObj, pIrp, context, irpStack->MinorFunction));
673
674#ifdef USBMON_ASYNC
675 VBoxUSBMonHandlePnPIoctl(irpStack, &pIrp->IoStatus);
676
677 /* Copy back the result to the original IRP. */
678 pOrgIrp->IoStatus.Information = pIrp->IoStatus.Information;
679 pOrgIrp->IoStatus.Status = pIrp->IoStatus.Status;
680
681 /* Unlock & free mdls of our duplicate IRP. */
682 while (pIrp->MdlAddress != NULL)
683 {
684 PMDL nextMdl;
685 nextMdl = pIrp->MdlAddress->Next;
686 DebugPrint(("Unlock & free MDL %p\n", pIrp->MdlAddress));
687 MmUnlockPages(pIrp->MdlAddress);
688 IoFreeMdl(pIrp->MdlAddress);
689 pIrp->MdlAddress = nextMdl;
690 }
691 /* Free our duplicate IRP */
692 IoFreeIrp(pIrp);
693
694 /* Release the remove lock */
695 IoReleaseRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
696
697 /* Complete the original request */
698 IoCompleteRequest(pOrgIrp, IO_NO_INCREMENT);
699
700 return STATUS_MORE_PROCESSING_REQUIRED; /* must return this as we allocated the IRP with IoBuildAsynchronousFsdRequest! */
701#else
702 return STATUS_CONTINUE_COMPLETION;
703#endif
704}
705
706/**
707 * Device PnP hook
708 *
709 * @param pDevObj Device object.
710 * @param pIrp Request packet.
711 */
712NTSTATUS _stdcall VBoxUSBMonPnPHook(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
713{
714 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pIrp);
715 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)ControlDeviceObject->DeviceExtension;
716 NTSTATUS status;
717
718 DebugPrint(("VBoxUSBMonPnPHook pDevObj=%p %s IRP:%p \n", pDevObj, PnPMinorFunctionString(irpStack->MinorFunction), pIrp));
719
720 status = IoAcquireRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
721 if (!NT_SUCCESS(status))
722 {
723 DebugPrint(("IoAcquireRemoveLock failed with %x\n", status));
724 pIrp->IoStatus.Status = status;
725 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
726 return status;
727 }
728
729 if (pDevExt->fHookDevice == TRUE)
730 {
731 switch(irpStack->MinorFunction)
732 {
733 case IRP_MN_QUERY_DEVICE_TEXT:
734 case IRP_MN_QUERY_ID:
735#ifdef DEBUG
736 /* hooking this IRP causes problems for some reason */
737 //case IRP_MN_QUERY_DEVICE_RELATIONS:
738 case IRP_MN_QUERY_CAPABILITIES:
739#endif
740 {
741#ifdef USBMON_ASYNC
742 PIRP pNewIrp;
743 PIO_STACK_LOCATION newIrpStack;
744
745 /* The driver verifier claims all PNP irps must have Status preset to STATUS_NOT_SUPPORTED */
746 IoStatus.Status = STATUS_NOT_SUPPORTED;
747
748 pNewIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, NULL);
749 Assert(pNewIrp);
750 if (!pNewIrp)
751 break;
752
753 /* Get the next stack location as that is used for the new irp */
754 newIrpStack = IoGetNextIrpStackLocation(pNewIrp);
755 Assert(newIrpStack);
756 if (newIrpStack)
757 {
758 /* Make a copy of the original IRP */
759 newIrpStack->MajorFunction = irpStack->MajorFunction;
760 newIrpStack->MinorFunction = irpStack->MinorFunction;
761 newIrpStack->Parameters = irpStack->Parameters;
762 newIrpStack->FileObject = irpStack->FileObject;
763
764 IoSetCompletionRoutine(pNewIrp, VBoxUSBPnPCompletion, pIrp, TRUE, TRUE, TRUE);
765
766 /* Mark the original Irp as pending; will be completed above */
767 IoMarkIrpPending(pIrp);
768
769 pDevExt->fHookDevice = FALSE;
770 status = IoCallDriver(pDevObj, pNewIrp);
771 pDevExt->fHookDevice = TRUE;
772 return STATUS_PENDING; /* always return this! */
773 }
774 else
775 {
776 IoFreeIrp(pNewIrp);
777 break;
778 }
779#else
780 PIRP pNewIrp;
781 PIO_STACK_LOCATION newIrpStack;
782 KEVENT event;
783 IO_STATUS_BLOCK IoStatus;
784
785 KeInitializeEvent(&event, NotificationEvent, FALSE);
786
787 /* The driver verifier claims all PNP irps must have Status preset to STATUS_NOT_SUPPORTED */
788 IoStatus.Status = STATUS_NOT_SUPPORTED;
789
790 pNewIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, &event, &IoStatus);
791 Assert(pNewIrp);
792 if (!pNewIrp)
793 break;
794
795 /* Get the next stack location as that is used for the new irp */
796 newIrpStack = IoGetNextIrpStackLocation(pNewIrp);
797 Assert(newIrpStack);
798 if (newIrpStack)
799 {
800 /* Make a copy of the original IRP */
801 newIrpStack->MajorFunction = irpStack->MajorFunction;
802 newIrpStack->MinorFunction = irpStack->MinorFunction;
803 newIrpStack->Parameters = irpStack->Parameters;
804 newIrpStack->FileObject = irpStack->FileObject;
805
806 IoSetCompletionRoutine(pNewIrp, VBoxUSBPnPCompletion, pIrp, TRUE, TRUE, TRUE);
807
808 pDevExt->fHookDevice = FALSE;
809 status = IoCallDriver(pDevObj, pNewIrp);
810 pDevExt->fHookDevice = TRUE;
811
812 if (status == STATUS_PENDING)
813 {
814 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
815 status = IoStatus.Status;
816 }
817
818 if (status == STATUS_SUCCESS)
819 {
820 VBoxUSBMonHandlePnPIoctl(irpStack, &IoStatus);
821 }
822 /* Copy back the result to the original IRP. */
823 pIrp->IoStatus.Information = IoStatus.Information;
824 pIrp->IoStatus.Status = IoStatus.Status;
825
826 /* Complete the original request */
827 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
828
829 /* Release the remove lock */
830 IoReleaseRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
831
832 return status;
833 }
834 else
835 {
836 IoFreeIrp(pNewIrp);
837 break;
838 }
839#endif
840 }
841
842 case IRP_MN_SURPRISE_REMOVAL:
843 case IRP_MN_REMOVE_DEVICE:
844 VBoxUSBRemoveDevice(irpStack->DeviceObject);
845 break;
846
847 /* These two IRPs are received when the PnP subsystem has determined the id of the newly arrived device */
848 /* IRP_MN_START_DEVICE only arrives if it's a USB device of a known class or with a present host driver */
849 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
850 case IRP_MN_QUERY_RESOURCES:
851 VBoxUSBDeviceArrived(irpStack->DeviceObject);
852 break;
853
854 default:
855 break;
856 }
857 }
858 status = pfnOldPnPHandler(pDevObj, pIrp);
859 IoReleaseRemoveLock(&pDevExt->RemoveLock, ControlDeviceObject);
860 return status;
861}
862
863
864/**
865 * Send IRP_MN_QUERY_DEVICE_RELATIONS
866 *
867 * @returns NT Status
868 * @param pDevObj USB device pointer
869 * @param pFileObj Valid file object pointer
870 * @param pDevRelations Pointer to DEVICE_RELATIONS pointer (out)
871 */
872NTSTATUS VBoxUSBQueryBusRelations(PDEVICE_OBJECT pDevObj, PFILE_OBJECT pFileObj, PDEVICE_RELATIONS *pDevRelations)
873{
874 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)ControlDeviceObject->DeviceExtension;
875 IO_STATUS_BLOCK IoStatus;
876 KEVENT event;
877 NTSTATUS status;
878 IRP *pIrp;
879 PIO_STACK_LOCATION irpStack;
880
881 KeInitializeEvent(&event, NotificationEvent, FALSE);
882
883 Assert(pDevRelations);
884 *pDevRelations = NULL;
885
886 pIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, &event, &IoStatus);
887 if (!pIrp)
888 {
889 AssertMsgFailed(("IoBuildDeviceIoControlRequest failed!!\n"));
890 return STATUS_INSUFFICIENT_RESOURCES;
891 }
892 IoStatus.Status = STATUS_NOT_SUPPORTED;
893
894 /* Get the next stack location as that is used for the new irp */
895 irpStack = IoGetNextIrpStackLocation(pIrp);
896 irpStack->MajorFunction = IRP_MJ_PNP;
897 irpStack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
898 irpStack->Parameters.QueryDeviceRelations.Type = BusRelations;
899 irpStack->FileObject = pFileObj;
900
901 pDevExt->fHookDevice = FALSE;
902 status = IoCallDriver(pDevObj, pIrp);
903 pDevExt->fHookDevice = TRUE;
904 if (status == STATUS_PENDING)
905 {
906 DebugPrint(("IoCallDriver returned STATUS_PENDING!!\n"));
907 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
908 status = IoStatus.Status;
909 }
910
911 if (status == STATUS_SUCCESS)
912 {
913 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)IoStatus.Information;
914 DebugPrint(("pRel = %p\n", pRel));
915 if (VALID_PTR(pRel))
916 {
917 *pDevRelations = pRel;
918 }
919 else
920 DebugPrint(("Invalid pointer %p\n", pRel));
921 }
922
923 DebugPrint(("IoCallDriver returned %x\n", status));
924 return status;
925}
926
927#ifdef DEBUG
928
929PCHAR PnPMinorFunctionString(UCHAR MinorFunction)
930{
931 switch (MinorFunction)
932 {
933 case IRP_MN_START_DEVICE:
934 return "IRP_MN_START_DEVICE";
935 case IRP_MN_QUERY_REMOVE_DEVICE:
936 return "IRP_MN_QUERY_REMOVE_DEVICE";
937 case IRP_MN_REMOVE_DEVICE:
938 return "IRP_MN_REMOVE_DEVICE";
939 case IRP_MN_CANCEL_REMOVE_DEVICE:
940 return "IRP_MN_CANCEL_REMOVE_DEVICE";
941 case IRP_MN_STOP_DEVICE:
942 return "IRP_MN_STOP_DEVICE";
943 case IRP_MN_QUERY_STOP_DEVICE:
944 return "IRP_MN_QUERY_STOP_DEVICE";
945 case IRP_MN_CANCEL_STOP_DEVICE:
946 return "IRP_MN_CANCEL_STOP_DEVICE";
947 case IRP_MN_QUERY_DEVICE_RELATIONS:
948 return "IRP_MN_QUERY_DEVICE_RELATIONS";
949 case IRP_MN_QUERY_INTERFACE:
950 return "IRP_MN_QUERY_INTERFACE";
951 case IRP_MN_QUERY_CAPABILITIES:
952 return "IRP_MN_QUERY_CAPABILITIES";
953 case IRP_MN_QUERY_RESOURCES:
954 return "IRP_MN_QUERY_RESOURCES";
955 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
956 return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
957 case IRP_MN_QUERY_DEVICE_TEXT:
958 return "IRP_MN_QUERY_DEVICE_TEXT";
959 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
960 return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
961 case IRP_MN_READ_CONFIG:
962 return "IRP_MN_READ_CONFIG";
963 case IRP_MN_WRITE_CONFIG:
964 return "IRP_MN_WRITE_CONFIG";
965 case IRP_MN_EJECT:
966 return "IRP_MN_EJECT";
967 case IRP_MN_SET_LOCK:
968 return "IRP_MN_SET_LOCK";
969 case IRP_MN_QUERY_ID:
970 return "IRP_MN_QUERY_ID";
971 case IRP_MN_QUERY_PNP_DEVICE_STATE:
972 return "IRP_MN_QUERY_PNP_DEVICE_STATE";
973 case IRP_MN_QUERY_BUS_INFORMATION:
974 return "IRP_MN_QUERY_BUS_INFORMATION";
975 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
976 return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
977 case IRP_MN_SURPRISE_REMOVAL:
978 return "IRP_MN_SURPRISE_REMOVAL";
979
980 default:
981 return "unknown_pnp_irp";
982 }
983}
984
985void DebugPrintUnicodeString(PUNICODE_STRING pString)
986{
987 int i;
988
989 for (i=0;i<pString->Length/2;i++)
990 {
991 DebugPrint(("%c", pString->Buffer[i]));
992 }
993}
994
995#endif
996
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