VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/darwin/VBoxUSB.cpp@ 57972

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

VBoxUSB/darwin: Workaround for IOUSBUserClientInit::probe returning NULL on 10.11 (El Capitan).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.0 KB
Line 
1/* $Id: VBoxUSB.cpp 57972 2015-09-30 15:19:05Z vboxsync $ */
2/** @file
3 * VirtualBox USB driver for Darwin.
4 *
5 * This driver is responsible for hijacking USB devices when any of the
6 * VBoxSVC daemons requests it. It is also responsible for arbitrating
7 * access to hijacked USB devices.
8 */
9
10/*
11 * Copyright (C) 2006-2015 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_USB_DRV
27/* Deal with conflicts first.
28 * (This is mess inherited from BSD. The *BSDs has clean this up long ago.) */
29#include <sys/param.h>
30#undef PVM
31#include <IOKit/IOLib.h> /* Assert as function */
32
33#include "VBoxUSBInterface.h"
34#include "VBoxUSBFilterMgr.h"
35#include <VBox/version.h>
36#include <VBox/usblib-darwin.h>
37#include <VBox/log.h>
38#include <iprt/types.h>
39#include <iprt/initterm.h>
40#include <iprt/assert.h>
41#include <iprt/semaphore.h>
42#include <iprt/process.h>
43#include <iprt/alloc.h>
44#include <iprt/err.h>
45#include <iprt/asm.h>
46
47#include <mach/kmod.h>
48#include <miscfs/devfs/devfs.h>
49#include <sys/conf.h>
50#include <sys/errno.h>
51#include <sys/ioccom.h>
52#include <sys/malloc.h>
53#include <sys/proc.h>
54#include <kern/task.h>
55#include <IOKit/IOService.h>
56#include <IOKit/IOUserClient.h>
57#include <IOKit/IOKitKeys.h>
58#include <IOKit/usb/USB.h>
59#include <IOKit/usb/IOUSBDevice.h>
60#include <IOKit/usb/IOUSBInterface.h>
61#include <IOKit/usb/IOUSBUserClient.h>
62
63/* private: */
64RT_C_DECLS_BEGIN
65extern void *get_bsdtask_info(task_t);
66RT_C_DECLS_END
67
68
69/*********************************************************************************************************************************
70* Defined Constants And Macros *
71*********************************************************************************************************************************/
72/** Locks the lists. */
73#define VBOXUSB_LOCK() do { int rc = RTSemFastMutexRequest(g_Mtx); AssertRC(rc); } while (0)
74/** Unlocks the lists. */
75#define VBOXUSB_UNLOCK() do { int rc = RTSemFastMutexRelease(g_Mtx); AssertRC(rc); } while (0)
76
77
78/*********************************************************************************************************************************
79* Internal Functions *
80*********************************************************************************************************************************/
81RT_C_DECLS_BEGIN
82static kern_return_t VBoxUSBStart(struct kmod_info *pKModInfo, void *pvData);
83static kern_return_t VBoxUSBStop(struct kmod_info *pKModInfo, void *pvData);
84RT_C_DECLS_END
85
86
87/*********************************************************************************************************************************
88* Structures and Typedefs *
89*********************************************************************************************************************************/
90/**
91 * The service class.
92 *
93 * This is the management service that VBoxSVC and the VMs speak to.
94 *
95 * @remark The method prototypes are ordered somewhat after their order of
96 * invocation, while the implementation is ordered by pair.
97 */
98class org_virtualbox_VBoxUSB : public IOService
99{
100 OSDeclareDefaultStructors(org_virtualbox_VBoxUSB);
101
102public:
103 /** @name IOService
104 * @{ */
105 virtual bool init(OSDictionary *pDictionary = 0);
106 virtual bool start(IOService *pProvider);
107 virtual bool open(IOService *pForClient, IOOptionBits fOptions = 0, void *pvArg = 0);
108 virtual bool terminate(IOOptionBits fOptions);
109 virtual void close(IOService *pForClient, IOOptionBits fOptions = 0);
110 virtual void stop(IOService *pProvider);
111 virtual void free();
112 /** @} */
113};
114OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSB, IOService);
115
116
117/**
118 * The user client class that pairs up with org_virtualbox_VBoxUSB.
119 */
120class org_virtualbox_VBoxUSBClient : public IOUserClient
121{
122 OSDeclareDefaultStructors(org_virtualbox_VBoxUSBClient);
123
124public:
125 /** @name IOService & IOUserClient
126 * @{ */
127 virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
128 virtual bool start(IOService *pProvider);
129 virtual IOReturn clientClose(void);
130 virtual IOReturn clientDied(void);
131 virtual bool terminate(IOOptionBits fOptions = 0);
132 virtual bool finalize(IOOptionBits fOptions);
133 virtual void stop(IOService *pProvider);
134 virtual void free();
135 virtual IOExternalMethod *getTargetAndMethodForIndex(IOService **ppService, UInt32 iMethod);
136 /** @} */
137
138 /** @name User client methods
139 * @{ */
140 IOReturn addFilter(PUSBFILTER pFilter, PVBOXUSBADDFILTEROUT pOut, IOByteCount cbFilter, IOByteCount *pcbOut);
141 IOReturn removeFilter(uintptr_t *puId, int *prc, IOByteCount cbIn, IOByteCount *pcbOut);
142 /** @} */
143
144 static bool isClientTask(task_t ClientTask);
145
146private:
147 /** The service provider. */
148 org_virtualbox_VBoxUSB *m_pProvider;
149 /** The client task. */
150 task_t m_Task;
151 /** The client process. */
152 RTPROCESS m_Process;
153 /** Pointer to the next user client. */
154 org_virtualbox_VBoxUSBClient * volatile m_pNext;
155 /** List of user clients. Protected by g_Mtx. */
156 static org_virtualbox_VBoxUSBClient * volatile s_pHead;
157};
158OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSBClient, IOUserClient);
159
160
161/**
162 * The IOUSBDevice driver class.
163 *
164 * The main purpose of this is hijack devices matching current filters.
165 *
166 * @remarks This is derived from IOUSBUserClientInit instead of IOService because we must make
167 * sure IOUSBUserClientInit::start() gets invoked for this provider. The problem is that
168 * there is some kind of magic that prevents this from happening if we boost the probe
169 * score to high. With the result that we don't have the required plugin entry for
170 * user land and consequently cannot open it.
171 *
172 * So, to avoid having to write a lot of code we just inherit from IOUSBUserClientInit
173 * and make some possibly bold assumptions about it not changing. This just means
174 * we'll have to keep an eye on the source apple releases or only call
175 * IOUSBUserClientInit::start() and hand the rest of the super calls to IOService. For
176 * now we're doing it by the C++ book.
177 */
178class org_virtualbox_VBoxUSBDevice : public IOUSBUserClientInit
179{
180 OSDeclareDefaultStructors(org_virtualbox_VBoxUSBDevice);
181
182public:
183 /** @name IOService
184 * @{ */
185 virtual bool init(OSDictionary *pDictionary = 0);
186 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
187 virtual bool start(IOService *pProvider);
188 virtual bool terminate(IOOptionBits fOptions = 0);
189 virtual void stop(IOService *pProvider);
190 virtual void free();
191 virtual IOReturn message(UInt32 enmMsg, IOService *pProvider, void *pvArg = 0);
192 /** @} */
193
194 static void scheduleReleaseByOwner(RTPROCESS Owner);
195private:
196 /** Padding to guard against parent class expanding (see class remarks). */
197 uint8_t m_abPadding[256];
198 /** The interface we're driving (aka. the provider). */
199 IOUSBDevice *m_pDevice;
200 /** The owner process, meaning the VBoxSVC process. */
201 RTPROCESS volatile m_Owner;
202 /** The client process, meaning the VM process. */
203 RTPROCESS volatile m_Client;
204 /** The ID of the matching filter. */
205 uintptr_t m_uId;
206 /** Have we opened the device or not? */
207 bool volatile m_fOpen;
208 /** Should be open the device on the next close notification message? */
209 bool volatile m_fOpenOnWasClosed;
210 /** Whether to re-enumerate this device when the client closes it.
211 * This is something we'll do when the filter owner dies. */
212 bool volatile m_fReleaseOnClose;
213 /** Whether we're being unloaded or not.
214 * Only valid in stop(). */
215 bool m_fBeingUnloaded;
216 /** Pointer to the next device in the list. */
217 org_virtualbox_VBoxUSBDevice * volatile m_pNext;
218 /** Pointer to the list head. Protected by g_Mtx. */
219 static org_virtualbox_VBoxUSBDevice * volatile s_pHead;
220
221#ifdef DEBUG
222 /** The interest notifier. */
223 IONotifier *m_pNotifier;
224
225 static IOReturn MyInterestHandler(void *pvTarget, void *pvRefCon, UInt32 enmMsgType,
226 IOService *pProvider, void * pvMsgArg, vm_size_t cbMsgArg);
227#endif
228};
229OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSBDevice, IOUSBUserClientInit);
230
231
232/**
233 * The IOUSBInterface driver class.
234 *
235 * The main purpose of this is hijack interfaces which device is driven
236 * by org_virtualbox_VBoxUSBDevice.
237 *
238 * @remarks See org_virtualbox_VBoxUSBDevice for why we use IOUSBUserClientInit.
239 */
240class org_virtualbox_VBoxUSBInterface : public IOUSBUserClientInit
241{
242 OSDeclareDefaultStructors(org_virtualbox_VBoxUSBInterface);
243
244public:
245 /** @name IOService
246 * @{ */
247 virtual bool init(OSDictionary *pDictionary = 0);
248 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
249 virtual bool start(IOService *pProvider);
250 virtual bool terminate(IOOptionBits fOptions = 0);
251 virtual void stop(IOService *pProvider);
252 virtual void free();
253 virtual IOReturn message(UInt32 enmMsg, IOService *pProvider, void *pvArg = 0);
254 /** @} */
255
256private:
257 /** The interface we're driving (aka. the provider). */
258 IOUSBInterface *m_pInterface;
259 /** Have we opened the device or not? */
260 bool volatile m_fOpen;
261 /** Should be open the device on the next close notification message? */
262 bool volatile m_fOpenOnWasClosed;
263};
264OSDefineMetaClassAndStructors(org_virtualbox_VBoxUSBInterface, IOUSBUserClientInit);
265
266
267
268
269
270/*********************************************************************************************************************************
271* Global Variables *
272*********************************************************************************************************************************/
273/*
274 * Declare the module stuff.
275 */
276RT_C_DECLS_BEGIN
277extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
278extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
279
280KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
281DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxUSBStart;
282DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxUSBStop;
283DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
284RT_C_DECLS_END
285
286/** Mutex protecting the lists. */
287static RTSEMFASTMUTEX g_Mtx = NIL_RTSEMFASTMUTEX;
288org_virtualbox_VBoxUSBClient * volatile org_virtualbox_VBoxUSBClient::s_pHead = NULL;
289org_virtualbox_VBoxUSBDevice * volatile org_virtualbox_VBoxUSBDevice::s_pHead = NULL;
290
291/** Global instance count - just for checking proving that everything is destroyed correctly. */
292static volatile uint32_t g_cInstances = 0;
293
294
295/**
296 * Start the kernel module.
297 */
298static kern_return_t VBoxUSBStart(struct kmod_info *pKModInfo, void *pvData)
299{
300 int rc;
301 Log(("VBoxUSBStart\n"));
302
303 /*
304 * Initialize IPRT.
305 */
306 rc = RTR0Init(0);
307 if (RT_SUCCESS(rc))
308 {
309 /*
310 * Create the spinlock.
311 */
312 rc = RTSemFastMutexCreate(&g_Mtx);
313 if (RT_SUCCESS(rc))
314 {
315 rc = VBoxUSBFilterInit();
316 if (RT_SUCCESS(rc))
317 {
318#if 0 /* testing */
319 USBFILTER Flt;
320 USBFilterInit(&Flt, USBFILTERTYPE_CAPTURE);
321 USBFilterSetNumExact(&Flt, USBFILTERIDX_VENDOR_ID, 0x096e, true);
322 uintptr_t uId;
323 rc = VBoxUSBFilterAdd(&Flt, 1, &uId);
324 printf("VBoxUSB: VBoxUSBFilterAdd #1 -> %d + %p\n", rc, uId);
325
326 USBFilterInit(&Flt, USBFILTERTYPE_CAPTURE);
327 USBFilterSetStringPattern(&Flt, USBFILTERIDX_PRODUCT_STR, "*DISK*", true);
328 rc = VBoxUSBFilterAdd(&Flt, 2, &uId);
329 printf("VBoxUSB: VBoxUSBFilterAdd #2 -> %d + %p\n", rc, uId);
330#endif
331 return KMOD_RETURN_SUCCESS;
332 }
333 printf("VBoxUSB: VBoxUSBFilterInit failed (rc=%d)\n", rc);
334 RTSemFastMutexDestroy(g_Mtx);
335 g_Mtx = NIL_RTSEMFASTMUTEX;
336 }
337 else
338 printf("VBoxUSB: RTSemFastMutexCreate failed (rc=%d)\n", rc);
339 RTR0Term();
340 }
341 else
342 printf("VBoxUSB: failed to initialize IPRT (rc=%d)\n", rc);
343
344 return KMOD_RETURN_FAILURE;
345}
346
347
348/**
349 * Stop the kernel module.
350 */
351static kern_return_t VBoxUSBStop(struct kmod_info *pKModInfo, void *pvData)
352{
353 int rc;
354 Log(("VBoxUSBStop: g_cInstances=%d\n", g_cInstances));
355
356 /** @todo Fix problem with crashing when unloading a driver that's in use. */
357
358 /*
359 * Undo the work done during start (in reverse order).
360 */
361 VBoxUSBFilterTerm();
362
363 rc = RTSemFastMutexDestroy(g_Mtx);
364 AssertRC(rc);
365 g_Mtx = NIL_RTSEMFASTMUTEX;
366
367 RTR0Term();
368
369 Log(("VBoxUSBStop - done\n"));
370 return KMOD_RETURN_SUCCESS;
371}
372
373
374
375
376
377
378/**
379 * Gets the name of a IOKit message.
380 *
381 * @returns Message name (read only).
382 * @param enmMsg The message.
383 */
384DECLINLINE(const char *) DbgGetIOKitMessageName(UInt32 enmMsg)
385{
386#ifdef DEBUG
387 switch (enmMsg)
388 {
389#define MY_CASE(enm) case enm: return #enm; break
390 MY_CASE(kIOMessageServiceIsTerminated);
391 MY_CASE(kIOMessageServiceIsSuspended);
392 MY_CASE(kIOMessageServiceIsResumed);
393 MY_CASE(kIOMessageServiceIsRequestingClose);
394 MY_CASE(kIOMessageServiceIsAttemptingOpen);
395 MY_CASE(kIOMessageServiceWasClosed);
396 MY_CASE(kIOMessageServiceBusyStateChange);
397 MY_CASE(kIOMessageServicePropertyChange);
398 MY_CASE(kIOMessageCanDevicePowerOff);
399 MY_CASE(kIOMessageDeviceWillPowerOff);
400 MY_CASE(kIOMessageDeviceWillNotPowerOff);
401 MY_CASE(kIOMessageDeviceHasPoweredOn);
402 MY_CASE(kIOMessageCanSystemPowerOff);
403 MY_CASE(kIOMessageSystemWillPowerOff);
404 MY_CASE(kIOMessageSystemWillNotPowerOff);
405 MY_CASE(kIOMessageCanSystemSleep);
406 MY_CASE(kIOMessageSystemWillSleep);
407 MY_CASE(kIOMessageSystemWillNotSleep);
408 MY_CASE(kIOMessageSystemHasPoweredOn);
409 MY_CASE(kIOMessageSystemWillRestart);
410 MY_CASE(kIOMessageSystemWillPowerOn);
411 MY_CASE(kIOUSBMessageHubResetPort);
412 MY_CASE(kIOUSBMessageHubSuspendPort);
413 MY_CASE(kIOUSBMessageHubResumePort);
414 MY_CASE(kIOUSBMessageHubIsDeviceConnected);
415 MY_CASE(kIOUSBMessageHubIsPortEnabled);
416 MY_CASE(kIOUSBMessageHubReEnumeratePort);
417 MY_CASE(kIOUSBMessagePortHasBeenReset);
418 MY_CASE(kIOUSBMessagePortHasBeenResumed);
419 MY_CASE(kIOUSBMessageHubPortClearTT);
420 MY_CASE(kIOUSBMessagePortHasBeenSuspended);
421 MY_CASE(kIOUSBMessageFromThirdParty);
422 MY_CASE(kIOUSBMessagePortWasNotSuspended);
423 MY_CASE(kIOUSBMessageExpressCardCantWake);
424// MY_CASE(kIOUSBMessageCompositeDriverReconfigured);
425#undef MY_CASE
426 }
427#endif /* DEBUG */
428 return "unknown";
429}
430
431
432
433
434
435/*
436 *
437 * org_virtualbox_VBoxUSB
438 *
439 */
440
441
442/**
443 * Initialize the object.
444 * @remark Only for logging.
445 */
446bool
447org_virtualbox_VBoxUSB::init(OSDictionary *pDictionary)
448{
449 uint32_t cInstances = ASMAtomicIncU32(&g_cInstances);
450 Log(("VBoxUSB::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances));
451 if (IOService::init(pDictionary))
452 {
453 /* init members. */
454 return true;
455 }
456 ASMAtomicDecU32(&g_cInstances);
457 return false;
458}
459
460
461/**
462 * Free the object.
463 * @remark Only for logging.
464 */
465void
466org_virtualbox_VBoxUSB::free()
467{
468 uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances);
469 Log(("VBoxUSB::free([%p]) new g_cInstances=%d\n", this, cInstances));
470 IOService::free();
471}
472
473
474/**
475 * Start this service.
476 */
477bool
478org_virtualbox_VBoxUSB::start(IOService *pProvider)
479{
480 Log(("VBoxUSB::start([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
481
482 if (IOService::start(pProvider))
483 {
484 /* register the service. */
485 registerService();
486 return true;
487 }
488 return false;
489}
490
491
492/**
493 * Stop this service.
494 * @remark Only for logging.
495 */
496void
497org_virtualbox_VBoxUSB::stop(IOService *pProvider)
498{
499 Log(("VBoxUSB::stop([%p], %p (%s))\n", this, pProvider, pProvider->getName()));
500 IOService::stop(pProvider);
501}
502
503
504/**
505 * Stop this service.
506 * @remark Only for logging.
507 */
508bool
509org_virtualbox_VBoxUSB::open(IOService *pForClient, IOOptionBits fOptions/* = 0*/, void *pvArg/* = 0*/)
510{
511 Log(("VBoxUSB::open([%p], %p, %#x, %p)\n", this, pForClient, fOptions, pvArg));
512 bool fRc = IOService::open(pForClient, fOptions, pvArg);
513 Log(("VBoxUSB::open([%p], %p, %#x, %p) -> %d\n", this, pForClient, fOptions, pvArg, fRc));
514 return fRc;
515}
516
517
518/**
519 * Stop this service.
520 * @remark Only for logging.
521 */
522void
523org_virtualbox_VBoxUSB::close(IOService *pForClient, IOOptionBits fOptions/* = 0*/)
524{
525 Log(("VBoxUSB::close([%p], %p, %#x)\n", this, pForClient, fOptions));
526 IOService::close(pForClient, fOptions);
527}
528
529
530/**
531 * Terminate request.
532 * @remark Only for logging.
533 */
534bool
535org_virtualbox_VBoxUSB::terminate(IOOptionBits fOptions)
536{
537 Log(("VBoxUSB::terminate([%p], %#x): g_cInstances=%d\n", this, fOptions, g_cInstances));
538 bool fRc = IOService::terminate(fOptions);
539 Log(("VBoxUSB::terminate([%p], %#x): returns %d\n", this, fOptions, fRc));
540 return fRc;
541}
542
543
544
545
546
547
548
549
550
551
552
553/*
554 *
555 * org_virtualbox_VBoxUSBClient
556 *
557 */
558
559
560/**
561 * Initializer called when the client opens the service.
562 */
563bool
564org_virtualbox_VBoxUSBClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
565{
566 if (!OwningTask)
567 {
568 Log(("VBoxUSBClient::initWithTask([%p], %p, %p, %#x) -> false (no task)\n", this, OwningTask, pvSecurityId, u32Type));
569 return false;
570 }
571 if (u32Type != VBOXUSB_DARWIN_IOSERVICE_COOKIE)
572 {
573 Log(("VBoxUSBClient::initWithTask: Bade cookie %#x\n", u32Type));
574 return false;
575 }
576
577 proc_t pProc = (proc_t)get_bsdtask_info(OwningTask); /* we need the pid */
578 Log(("VBoxUSBClient::initWithTask([%p], %p(->%p:{.pid=%d}, %p, %#x)\n",
579 this, OwningTask, pProc, pProc ? proc_pid(pProc) : -1, pvSecurityId, u32Type));
580
581 if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
582 {
583 m_pProvider = NULL;
584 m_Task = OwningTask;
585 m_Process = pProc ? proc_pid(pProc) : NIL_RTPROCESS;
586 m_pNext = NULL;
587
588 uint32_t cInstances = ASMAtomicIncU32(&g_cInstances);
589 Log(("VBoxUSBClient::initWithTask([%p], %p(->%p:{.pid=%d}, %p, %#x) -> true; new g_cInstances=%d\n",
590 this, OwningTask, pProc, pProc ? proc_pid(pProc) : -1, pvSecurityId, u32Type, cInstances));
591 return true;
592 }
593
594 Log(("VBoxUSBClient::initWithTask([%p], %p(->%p:{.pid=%d}, %p, %#x) -> false\n",
595 this, OwningTask, pProc, pProc ? proc_pid(pProc) : -1, pvSecurityId, u32Type));
596 return false;
597}
598
599
600/**
601 * Free the object.
602 * @remark Only for logging.
603 */
604void
605org_virtualbox_VBoxUSBClient::free()
606{
607 uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances);
608 Log(("VBoxUSBClient::free([%p]) new g_cInstances=%d\n", this, cInstances));
609 IOUserClient::free();
610}
611
612
613/**
614 * Start the client service.
615 */
616bool
617org_virtualbox_VBoxUSBClient::start(IOService *pProvider)
618{
619 Log(("VBoxUSBClient::start([%p], %p)\n", this, pProvider));
620 if (IOUserClient::start(pProvider))
621 {
622 m_pProvider = OSDynamicCast(org_virtualbox_VBoxUSB, pProvider);
623 if (m_pProvider)
624 {
625 /*
626 * Add ourselves to the list of user clients.
627 */
628 VBOXUSB_LOCK();
629
630 m_pNext = s_pHead;
631 s_pHead = this;
632
633 VBOXUSB_UNLOCK();
634
635 return true;
636 }
637 Log(("VBoxUSBClient::start: %p isn't org_virtualbox_VBoxUSB\n", pProvider));
638 }
639 return false;
640}
641
642
643/**
644 * Client exits normally.
645 */
646IOReturn
647org_virtualbox_VBoxUSBClient::clientClose(void)
648{
649 Log(("VBoxUSBClient::clientClose([%p:{.m_Process=%d}])\n", this, (int)m_Process));
650
651 /*
652 * Remove this process from the client list.
653 */
654 VBOXUSB_LOCK();
655
656 org_virtualbox_VBoxUSBClient *pPrev = NULL;
657 for (org_virtualbox_VBoxUSBClient *pCur = s_pHead; pCur; pCur = pCur->m_pNext)
658 {
659 if (pCur == this)
660 {
661 if (pPrev)
662 pPrev->m_pNext = m_pNext;
663 else
664 s_pHead = m_pNext;
665 m_pNext = NULL;
666 break;
667 }
668 pPrev = pCur;
669 }
670
671 VBOXUSB_UNLOCK();
672
673 /*
674 * Drop all filters owned by this client.
675 */
676 if (m_Process != NIL_RTPROCESS)
677 VBoxUSBFilterRemoveOwner(m_Process);
678
679 /*
680 * Schedule all devices owned (filtered) by this process for
681 * immediate release or release upon close.
682 */
683 if (m_Process != NIL_RTPROCESS)
684 org_virtualbox_VBoxUSBDevice::scheduleReleaseByOwner(m_Process);
685
686 /*
687 * Initiate termination.
688 */
689 m_pProvider = NULL;
690 terminate();
691
692 return kIOReturnSuccess;
693}
694
695
696/**
697 * The client exits abnormally / forgets to do cleanups.
698 * @remark Only for logging.
699 */
700IOReturn
701org_virtualbox_VBoxUSBClient::clientDied(void)
702{
703 Log(("VBoxUSBClient::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n",
704 this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
705
706 /* IOUserClient::clientDied() calls clientClose... */
707 return IOUserClient::clientDied();
708}
709
710
711/**
712 * Terminate the service (initiate the destruction).
713 * @remark Only for logging.
714 */
715bool
716org_virtualbox_VBoxUSBClient::terminate(IOOptionBits fOptions)
717{
718 /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */
719 Log(("VBoxUSBClient::terminate([%p], %#x)\n", this, fOptions));
720 return IOUserClient::terminate(fOptions);
721}
722
723
724/**
725 * The final stage of the client service destruction.
726 * @remark Only for logging.
727 */
728bool
729org_virtualbox_VBoxUSBClient::finalize(IOOptionBits fOptions)
730{
731 Log(("VBoxUSBClient::finalize([%p], %#x)\n", this, fOptions));
732 return IOUserClient::finalize(fOptions);
733}
734
735
736/**
737 * Stop the client service.
738 */
739void
740org_virtualbox_VBoxUSBClient::stop(IOService *pProvider)
741{
742 Log(("VBoxUSBClient::stop([%p])\n", this));
743 IOUserClient::stop(pProvider);
744
745 /*
746 * Paranoia.
747 */
748 VBOXUSB_LOCK();
749
750 org_virtualbox_VBoxUSBClient *pPrev = NULL;
751 for (org_virtualbox_VBoxUSBClient *pCur = s_pHead; pCur; pCur = pCur->m_pNext)
752 {
753 if (pCur == this)
754 {
755 if (pPrev)
756 pPrev->m_pNext = m_pNext;
757 else
758 s_pHead = m_pNext;
759 m_pNext = NULL;
760 break;
761 }
762 pPrev = pCur;
763 }
764
765 VBOXUSB_UNLOCK();
766}
767
768
769/**
770 * Translate a user method index into a service object and an external method structure.
771 *
772 * @returns Pointer to external method structure descripting the method.
773 * NULL if the index isn't valid.
774 * @param ppService Where to store the service object on success.
775 * @param iMethod The method index.
776 */
777IOExternalMethod *
778org_virtualbox_VBoxUSBClient::getTargetAndMethodForIndex(IOService **ppService, UInt32 iMethod)
779{
780 static IOExternalMethod s_aMethods[VBOXUSBMETHOD_END] =
781 {
782 /*[VBOXUSBMETHOD_ADD_FILTER] = */
783 {
784 (IOService *)0, /* object */
785 (IOMethod)&org_virtualbox_VBoxUSBClient::addFilter, /* func */
786 kIOUCStructIStructO, /* flags - struct input (count0) and struct output (count1) */
787 sizeof(USBFILTER), /* count0 - size of the input struct. */
788 sizeof(VBOXUSBADDFILTEROUT) /* count1 - size of the return struct. */
789 },
790 /* [VBOXUSBMETHOD_FILTER_REMOVE] = */
791 {
792 (IOService *)0, /* object */
793 (IOMethod)&org_virtualbox_VBoxUSBClient::removeFilter, /* func */
794 kIOUCStructIStructO, /* flags - struct input (count0) and struct output (count1) */
795 sizeof(uintptr_t), /* count0 - size of the input (id) */
796 sizeof(int) /* count1 - size of the output (rc) */
797 },
798 };
799
800 if (RT_UNLIKELY(iMethod >= RT_ELEMENTS(s_aMethods)))
801 return NULL;
802
803 *ppService = this;
804 return &s_aMethods[iMethod];
805}
806
807
808/**
809 * Add filter user request.
810 *
811 * @returns IOKit status code.
812 * @param pFilter The filter to add.
813 * @param pOut Pointer to the output structure.
814 * @param cbFilter Size of the filter structure.
815 * @param pcbOut In/Out - sizeof(*pOut).
816 */
817IOReturn
818org_virtualbox_VBoxUSBClient::addFilter(PUSBFILTER pFilter, PVBOXUSBADDFILTEROUT pOut, IOByteCount cbFilter, IOByteCount *pcbOut)
819{
820 Log(("VBoxUSBClient::addFilter: [%p:{.m_Process=%d}] pFilter=%p pOut=%p\n", this, (int)m_Process, pFilter, pOut));
821
822 /*
823 * Validate input.
824 */
825 if (RT_UNLIKELY( cbFilter != sizeof(*pFilter)
826 || *pcbOut != sizeof(*pOut)))
827 {
828 printf("VBoxUSBClient::addFilter: cbFilter=%#x expected %#x; *pcbOut=%#x expected %#x\n",
829 (int)cbFilter, (int)sizeof(*pFilter), (int)*pcbOut, (int)sizeof(*pOut));
830 return kIOReturnBadArgument;
831 }
832
833 /*
834 * Log the filter details.
835 */
836#ifdef DEBUG
837 Log2(("VBoxUSBClient::addFilter: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
838 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
839 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
840 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
841 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
842 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
843 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
844 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
845 USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
846 Log2(("VBoxUSBClient::addFilter: Manufacturer=%s Product=%s Serial=%s\n",
847 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
848 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
849 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
850#endif
851
852 /*
853 * Since we cannot query the bus number, make sure the filter
854 * isn't requiring that field to be present.
855 */
856 int rc = USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false /* fMustBePresent */); AssertRC(rc);
857
858 /*
859 * Add the filter.
860 */
861 pOut->uId = 0;
862 pOut->rc = VBoxUSBFilterAdd(pFilter, m_Process, &pOut->uId);
863
864 Log(("VBoxUSBClient::addFilter: returns *pOut={.rc=%d, .uId=%p}\n", pOut->rc, (void *)pOut->uId));
865 return kIOReturnSuccess;
866}
867
868
869/**
870 * Removes filter user request.
871 *
872 * @returns IOKit status code.
873 * @param puId Where to get the filter ID.
874 * @param prc Where to store the return code.
875 * @param cbIn sizeof(*puId).
876 * @param pcbOut In/Out - sizeof(*prc).
877 */
878IOReturn
879org_virtualbox_VBoxUSBClient::removeFilter(uintptr_t *puId, int *prc, IOByteCount cbIn, IOByteCount *pcbOut)
880{
881 Log(("VBoxUSBClient::removeFilter: [%p:{.m_Process=%d}] *puId=%p m_Proc\n", this, (int)m_Process, *puId));
882
883 /*
884 * Validate input.
885 */
886 if (RT_UNLIKELY( cbIn != sizeof(*puId)
887 || *pcbOut != sizeof(*prc)))
888 {
889 printf("VBoxUSBClient::removeFilter: cbIn=%#x expected %#x; *pcbOut=%#x expected %#x\n",
890 (int)cbIn, (int)sizeof(*puId), (int)*pcbOut, (int)sizeof(*prc));
891 return kIOReturnBadArgument;
892 }
893
894 /*
895 * Remove the filter.
896 */
897 *prc = VBoxUSBFilterRemove(m_Process, *puId);
898
899 Log(("VBoxUSBClient::removeFilter: returns *prc=%d\n", *prc));
900 return kIOReturnSuccess;
901}
902
903
904/**
905 * Checks whether the specified task is a VBoxUSB client task or not.
906 *
907 * This is used to validate clients trying to open any of the device
908 * or interfaces that we've hijacked.
909 *
910 * @returns true / false.
911 * @param ClientTask The task.
912 *
913 * @remark This protecting against other user clients is not currently implemented
914 * as it turned out to be more bothersome than first imagined.
915 */
916/* static*/ bool
917org_virtualbox_VBoxUSBClient::isClientTask(task_t ClientTask)
918{
919 VBOXUSB_LOCK();
920
921 for (org_virtualbox_VBoxUSBClient *pCur = s_pHead; pCur; pCur = pCur->m_pNext)
922 if (pCur->m_Task == ClientTask)
923 {
924 VBOXUSB_UNLOCK();
925 return true;
926 }
927
928 VBOXUSB_UNLOCK();
929 return false;
930}
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945/*
946 *
947 * org_virtualbox_VBoxUSBDevice
948 *
949 */
950
951/**
952 * Initialize instance data.
953 *
954 * @returns Success indicator.
955 * @param pDictionary The dictionary that will become the registry entry's
956 * property table, or NULL. Hand it up to our parents.
957 */
958bool
959org_virtualbox_VBoxUSBDevice::init(OSDictionary *pDictionary)
960{
961 uint32_t cInstances = ASMAtomicIncU32(&g_cInstances);
962 Log(("VBoxUSBDevice::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances));
963
964 m_pDevice = NULL;
965 m_Owner = NIL_RTPROCESS;
966 m_Client = NIL_RTPROCESS;
967 m_uId = ~(uintptr_t)0;
968 m_fOpen = false;
969 m_fOpenOnWasClosed = false;
970 m_fReleaseOnClose = false;
971 m_fBeingUnloaded = false;
972 m_pNext = NULL;
973#ifdef DEBUG
974 m_pNotifier = NULL;
975#endif
976
977 return IOUSBUserClientInit::init(pDictionary);
978}
979
980/**
981 * Free the object.
982 * @remark Only for logging.
983 */
984void
985org_virtualbox_VBoxUSBDevice::free()
986{
987 uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances);
988 Log(("VBoxUSBDevice::free([%p]) new g_cInstances=%d\n", this, cInstances));
989 IOUSBUserClientInit::free();
990}
991
992
993/**
994 * The device/driver probing.
995 *
996 * I/O Kit will iterate all device drivers suitable for this kind of device
997 * (this is something it figures out from the property file) and call their
998 * probe() method in order to try determine which is the best match for the
999 * device. We will match the device against the registered filters and set
1000 * a ridiculously high score if we find it, thus making it extremely likely
1001 * that we'll be the first driver to be started. We'll also set a couple of
1002 * attributes so that it's not necessary to do a rematch in init to find
1003 * the appropriate filter (might not be necessary..., see todo).
1004 *
1005 * @returns Service instance to be started and *pi32Score if matching.
1006 * NULL if not a device suitable for this driver.
1007 *
1008 * @param pProvider The provider instance.
1009 * @param pi32Score Where to store the probe score.
1010 */
1011IOService *
1012org_virtualbox_VBoxUSBDevice::probe(IOService *pProvider, SInt32 *pi32Score)
1013{
1014 Log(("VBoxUSBDevice::probe([%p], %p {%s}, %p={%d})\n", this,
1015 pProvider, pProvider->getName(), pi32Score, pi32Score ? *pi32Score : 0));
1016
1017 /*
1018 * Check against filters.
1019 */
1020 USBFILTER Device;
1021 USBFilterInit(&Device, USBFILTERTYPE_CAPTURE);
1022
1023 static const struct
1024 {
1025 const char *pszName;
1026 USBFILTERIDX enmIdx;
1027 bool fNumeric;
1028 } s_aProps[] =
1029 {
1030 { kUSBVendorID, USBFILTERIDX_VENDOR_ID, true },
1031 { kUSBProductID, USBFILTERIDX_PRODUCT_ID, true },
1032 { kUSBDeviceReleaseNumber, USBFILTERIDX_DEVICE_REV, true },
1033 { kUSBDeviceClass, USBFILTERIDX_DEVICE_CLASS, true },
1034 { kUSBDeviceSubClass, USBFILTERIDX_DEVICE_SUB_CLASS, true },
1035 { kUSBDeviceProtocol, USBFILTERIDX_DEVICE_PROTOCOL, true },
1036 { "PortNum", USBFILTERIDX_PORT, true },
1037 /// @todo { , USBFILTERIDX_BUS, true }, - must be derived :-/
1038 /// Seems to be the upper byte of locationID and our "grand parent" has a USBBusNumber prop.
1039 { "USB Vendor Name", USBFILTERIDX_MANUFACTURER_STR, false },
1040 { "USB Product Name", USBFILTERIDX_PRODUCT_STR, false },
1041 { "USB Serial Number", USBFILTERIDX_SERIAL_NUMBER_STR, false },
1042 };
1043 for (unsigned i = 0; i < RT_ELEMENTS(s_aProps); i++)
1044 {
1045 OSObject *pObj = pProvider->getProperty(s_aProps[i].pszName);
1046 if (!pObj)
1047 continue;
1048 if (s_aProps[i].fNumeric)
1049 {
1050 OSNumber *pNum = OSDynamicCast(OSNumber, pObj);
1051 if (pNum)
1052 {
1053 uint16_t u16 = pNum->unsigned16BitValue();
1054 Log2(("VBoxUSBDevice::probe: %d/%s - %#x (32bit=%#x)\n", i, s_aProps[i].pszName, u16, pNum->unsigned32BitValue()));
1055 int vrc = USBFilterSetNumExact(&Device, s_aProps[i].enmIdx, u16, true);
1056 if (RT_FAILURE(vrc))
1057 Log(("VBoxUSBDevice::probe: pObj=%p pNum=%p - %d/%s - rc=%d!\n", pObj, pNum, i, s_aProps[i].pszName, vrc));
1058 }
1059 else
1060 Log(("VBoxUSBDevice::probe: pObj=%p pNum=%p - %d/%s!\n", pObj, pNum, i, s_aProps[i].pszName));
1061 }
1062 else
1063 {
1064 OSString *pStr = OSDynamicCast(OSString, pObj);
1065 if (pStr)
1066 {
1067 Log2(("VBoxUSBDevice::probe: %d/%s - %s\n", i, s_aProps[i].pszName, pStr->getCStringNoCopy()));
1068 int vrc = USBFilterSetStringExact(&Device, s_aProps[i].enmIdx, pStr->getCStringNoCopy(), true);
1069 if (RT_FAILURE(vrc))
1070 Log(("VBoxUSBDevice::probe: pObj=%p pStr=%p - %d/%s - rc=%d!\n", pObj, pStr, i, s_aProps[i].pszName, vrc));
1071 }
1072 else
1073 Log(("VBoxUSBDevice::probe: pObj=%p pStr=%p - %d/%s\n", pObj, pStr, i, s_aProps[i].pszName));
1074 }
1075 }
1076 /** @todo try figure the blasted bus number */
1077
1078 /*
1079 * Run filters on it.
1080 */
1081 uintptr_t uId = 0;
1082 RTPROCESS Owner = VBoxUSBFilterMatch(&Device, &uId);
1083 USBFilterDelete(&Device);
1084 if (Owner == NIL_RTPROCESS)
1085 {
1086 Log(("VBoxUSBDevice::probe: returns NULL uId=%d\n", uId));
1087 return NULL;
1088 }
1089
1090 /*
1091 * It matched. Save the owner in the provider registry (hope that works).
1092 */
1093 IOService *pRet = IOUSBUserClientInit::probe(pProvider, pi32Score);
1094 /*AssertMsg(pRet == this, ("pRet=%p this=%p *pi32Score=%d \n", pRet, this, pi32Score ? *pi32Score : 0)); - call always returns NULL on 10.11+ */
1095 pRet = this;
1096 m_Owner = Owner;
1097 m_uId = uId;
1098 Log(("%p: m_Owner=%d m_uId=%d\n", this, (int)m_Owner, (int)m_uId));
1099 *pi32Score = _1G;
1100 Log(("VBoxUSBDevice::probe: returns %p and *pi32Score=%d\n", pRet, *pi32Score));
1101 return pRet;
1102}
1103
1104
1105/**
1106 * Try start the device driver.
1107 *
1108 * We will do device linking, copy the filter and owner properties from the provider,
1109 * set the client property, retain the device, and try open (seize) the device.
1110 *
1111 * @returns Success indicator.
1112 * @param pProvider The provider instance.
1113 */
1114bool
1115org_virtualbox_VBoxUSBDevice::start(IOService *pProvider)
1116{
1117 Log(("VBoxUSBDevice::start([%p:{.m_Owner=%d, .m_uId=%p}], %p {%s})\n",
1118 this, m_Owner, m_uId, pProvider, pProvider->getName()));
1119
1120 m_pDevice = OSDynamicCast(IOUSBDevice, pProvider);
1121 if (!m_pDevice)
1122 {
1123 printf("VBoxUSBDevice::start([%p], %p {%s}): failed!\n", this, pProvider, pProvider->getName());
1124 return false;
1125 }
1126
1127#ifdef DEBUG
1128 /* for some extra log messages */
1129 m_pNotifier = pProvider->registerInterest(gIOGeneralInterest,
1130 &org_virtualbox_VBoxUSBDevice::MyInterestHandler,
1131 this, /* pvTarget */
1132 NULL); /* pvRefCon */
1133#endif
1134
1135 /*
1136 * Exploit IOUSBUserClientInit to process IOProviderMergeProperties.
1137 */
1138 IOUSBUserClientInit::start(pProvider); /* returns false */
1139
1140 /*
1141 * Link ourselves into the list of hijacked device.
1142 */
1143 VBOXUSB_LOCK();
1144
1145 m_pNext = s_pHead;
1146 s_pHead = this;
1147
1148 VBOXUSB_UNLOCK();
1149
1150 /*
1151 * Set the VBoxUSB properties.
1152 */
1153 if (!setProperty(VBOXUSB_OWNER_KEY, (unsigned long long)m_Owner, sizeof(m_Owner) * 8 /* bits */))
1154 Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_OWNER_KEY "' property!\n"));
1155 if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */))
1156 Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n"));
1157 if (!setProperty(VBOXUSB_FILTER_KEY, (unsigned long long)m_uId, sizeof(m_uId) * 8 /* bits */))
1158 Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_FILTER_KEY "' property!\n"));
1159
1160 /*
1161 * Retain and open the device.
1162 */
1163 m_pDevice->retain();
1164 m_fOpen = m_pDevice->open(this, kIOServiceSeize, 0);
1165 if (!m_fOpen)
1166 Log(("VBoxUSBDevice::start: failed to open the device!\n"));
1167 m_fOpenOnWasClosed = !m_fOpen;
1168
1169 Log(("VBoxUSBDevice::start: returns %d\n", true));
1170 return true;
1171}
1172
1173
1174/**
1175 * Stop the device driver.
1176 *
1177 * We'll unlink the device, start device re-enumeration and close it. And call
1178 * the parent stop method of course.
1179 *
1180 * @param pProvider The provider instance.
1181 */
1182void
1183org_virtualbox_VBoxUSBDevice::stop(IOService *pProvider)
1184{
1185 Log(("VBoxUSBDevice::stop([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
1186
1187 /*
1188 * Remove ourselves from the list of device.
1189 */
1190 VBOXUSB_LOCK();
1191
1192 org_virtualbox_VBoxUSBDevice *pPrev = NULL;
1193 for (org_virtualbox_VBoxUSBDevice *pCur = s_pHead; pCur; pCur = pCur->m_pNext)
1194 {
1195 if (pCur == this)
1196 {
1197 if (pPrev)
1198 pPrev->m_pNext = m_pNext;
1199 else
1200 s_pHead = m_pNext;
1201 m_pNext = NULL;
1202 break;
1203 }
1204 pPrev = pCur;
1205 }
1206
1207 VBOXUSB_UNLOCK();
1208
1209 /*
1210 * Should we release the device?
1211 */
1212 if (m_fBeingUnloaded)
1213 {
1214 if (m_pDevice)
1215 {
1216 IOReturn irc = m_pDevice->ReEnumerateDevice(0); NOREF(irc);
1217 Log(("VBoxUSBDevice::stop([%p], %p {%s}): m_pDevice=%p unload & ReEnumerateDevice -> %#x\n",
1218 this, pProvider, pProvider->getName(), m_pDevice, irc));
1219 }
1220 else
1221 {
1222 IOUSBDevice *pDevice = OSDynamicCast(IOUSBDevice, pProvider);
1223 if (pDevice)
1224 {
1225 IOReturn irc = pDevice->ReEnumerateDevice(0); NOREF(irc);
1226 Log(("VBoxUSBDevice::stop([%p], %p {%s}): pDevice=%p unload & ReEnumerateDevice -> %#x\n",
1227 this, pProvider, pProvider->getName(), pDevice, irc));
1228 }
1229 else
1230 Log(("VBoxUSBDevice::stop([%p], %p {%s}): failed to cast provider to IOUSBDevice\n",
1231 this, pProvider, pProvider->getName()));
1232 }
1233 }
1234 else if (m_fReleaseOnClose)
1235 {
1236 ASMAtomicWriteBool(&m_fReleaseOnClose, false);
1237 if (m_pDevice)
1238 {
1239 IOReturn irc = m_pDevice->ReEnumerateDevice(0); NOREF(irc);
1240 Log(("VBoxUSBDevice::stop([%p], %p {%s}): m_pDevice=%p close & ReEnumerateDevice -> %#x\n",
1241 this, pProvider, pProvider->getName(), m_pDevice, irc));
1242 }
1243 }
1244
1245 /*
1246 * Close and release the IOUSBDevice if didn't do that already in message().
1247 */
1248 if (m_pDevice)
1249 {
1250 /* close it */
1251 if (m_fOpen)
1252 {
1253 m_fOpenOnWasClosed = false;
1254 m_fOpen = false;
1255 m_pDevice->close(this, 0);
1256 }
1257
1258 /* release it (see start()) */
1259 m_pDevice->release();
1260 m_pDevice = NULL;
1261 }
1262
1263#ifdef DEBUG
1264 /* avoid crashing on unload. */
1265 if (m_pNotifier)
1266 {
1267 m_pNotifier->release();
1268 m_pNotifier = NULL;
1269 }
1270#endif
1271
1272 IOUSBUserClientInit::stop(pProvider);
1273 Log(("VBoxUSBDevice::stop: returns void\n"));
1274}
1275
1276
1277/**
1278 * Terminate the service (initiate the destruction).
1279 * @remark Only for logging.
1280 */
1281bool
1282org_virtualbox_VBoxUSBDevice::terminate(IOOptionBits fOptions)
1283{
1284 /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */
1285 Log(("VBoxUSBDevice::terminate([%p], %#x)\n", this, fOptions));
1286
1287 /*
1288 * There aren't too many reasons why we gets terminated.
1289 * The most common one is that the device is being unplugged. Another is
1290 * that we've triggered reenumeration. In both cases we'll get a
1291 * kIOMessageServiceIsTerminated message before we're stopped.
1292 *
1293 * But, when we're unloaded the provider service isn't terminated, and
1294 * for some funny reason we're frequently causing kernel panics when the
1295 * device is detached (after we're unloaded). So, for now, let's try
1296 * re-enumerate it in stop.
1297 *
1298 * To avoid creating unnecessary trouble we'll try guess if we're being
1299 * unloaded from the option bit mask. (kIOServiceRecursing is private btw.)
1300 */
1301 /** @todo would be nice if there was a documented way of doing the unload detection this, or
1302 * figure out what exactly we're doing wrong in the unload scenario. */
1303 if ((fOptions & 0xffff) == (kIOServiceRequired | kIOServiceSynchronous))
1304 m_fBeingUnloaded = true;
1305
1306 return IOUSBUserClientInit::terminate(fOptions);
1307}
1308
1309
1310/**
1311 * Intercept open requests and only let Mr. Right (the VM process) open the device.
1312 * This is where it all gets a bit complicated...
1313 *
1314 * @return Status code.
1315 *
1316 * @param enmMsg The message number.
1317 * @param pProvider Pointer to the provider instance.
1318 * @param pvArg Message argument.
1319 */
1320IOReturn
1321org_virtualbox_VBoxUSBDevice::message(UInt32 enmMsg, IOService *pProvider, void *pvArg)
1322{
1323 Log(("VBoxUSBDevice::message([%p], %#x {%s}, %p {%s}, %p) - pid=%d\n",
1324 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, RTProcSelf()));
1325
1326 IOReturn irc;
1327 switch (enmMsg)
1328 {
1329 /*
1330 * This message is send to the current IOService client from IOService::handleOpen(),
1331 * expecting it to call pProvider->close() if it agrees to the other party seizing
1332 * the service. It is also called in IOService::didTerminate() and perhaps some other
1333 * odd places. The way to find out is to examin the pvArg, which would be including
1334 * kIOServiceSeize if it's the handleOpen case.
1335 *
1336 * How to validate that the other end is actually our VM process? Well, IOKit doesn't
1337 * provide any clue about the new client really. But fortunately, it seems like the
1338 * calling task/process context when the VM tries to open the device is the VM process.
1339 * We'll ASSUME this'll remain like this for now...
1340 */
1341 case kIOMessageServiceIsRequestingClose:
1342 irc = kIOReturnExclusiveAccess;
1343 /* If it's not a seize request, assume it's didTerminate and pray that it isn't a rouge driver.
1344 ... weird, doesn't seem to match for the post has-terminated messages. */
1345 if (!((uintptr_t)pvArg & kIOServiceSeize))
1346 {
1347 Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d: not seize - closing...\n",
1348 this, pProvider, pProvider->getName(), pvArg, RTProcSelf()));
1349 m_fOpen = false;
1350 m_fOpenOnWasClosed = false;
1351 if (m_pDevice)
1352 m_pDevice->close(this, 0);
1353 m_Client = NIL_RTPROCESS;
1354 irc = kIOReturnSuccess;
1355 }
1356 else
1357 {
1358 if (org_virtualbox_VBoxUSBClient::isClientTask(current_task()))
1359 {
1360 Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d task=%p: client process, closing.\n",
1361 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1362 m_fOpen = false;
1363 m_fOpenOnWasClosed = false;
1364 if (m_pDevice)
1365 m_pDevice->close(this, 0);
1366 m_fOpenOnWasClosed = true;
1367 m_Client = RTProcSelf();
1368 irc = kIOReturnSuccess;
1369 }
1370 else
1371 Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d task=%p: not client process!\n",
1372 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1373 }
1374 if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */))
1375 Log(("VBoxUSBDevice::message: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n"));
1376 break;
1377
1378 /*
1379 * The service was closed by the current client.
1380 * Update the client property, check for scheduled re-enumeration and re-open.
1381 *
1382 * Note that we will not be called if we're doing the closing. (Even if we was
1383 * called in that case, the code should be able to handle it.)
1384 */
1385 case kIOMessageServiceWasClosed:
1386 /*
1387 * Update the client property value.
1388 */
1389 if (m_Client != NIL_RTPROCESS)
1390 {
1391 m_Client = NIL_RTPROCESS;
1392 if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */))
1393 Log(("VBoxUSBDevice::message: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n"));
1394 }
1395
1396 if (m_pDevice)
1397 {
1398 /*
1399 * Should we release the device?
1400 */
1401 if (ASMAtomicXchgBool(&m_fReleaseOnClose, false))
1402 {
1403 m_fOpenOnWasClosed = false;
1404 irc = m_pDevice->ReEnumerateDevice(0);
1405 Log(("VBoxUSBDevice::message([%p], %p {%s}) - ReEnumerateDevice() -> %#x\n",
1406 this, pProvider, pProvider->getName(), irc));
1407 }
1408 /*
1409 * Should we attempt to re-open the device?
1410 */
1411 else if (m_fOpenOnWasClosed)
1412 {
1413 Log(("VBoxUSBDevice::message: attempting to re-open the device...\n"));
1414 m_fOpenOnWasClosed = false;
1415 m_fOpen = m_pDevice->open(this, kIOServiceSeize, 0);
1416 if (!m_fOpen)
1417 Log(("VBoxUSBDevice::message: failed to open the device!\n"));
1418 m_fOpenOnWasClosed = !m_fOpen;
1419 }
1420 }
1421
1422 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1423 break;
1424
1425 /*
1426 * The IOUSBDevice is shutting down, so close it if we've opened it.
1427 */
1428 case kIOMessageServiceIsTerminated:
1429 m_fBeingUnloaded = false;
1430 ASMAtomicWriteBool(&m_fReleaseOnClose, false);
1431 if (m_pDevice)
1432 {
1433 /* close it */
1434 if (m_fOpen)
1435 {
1436 m_fOpen = false;
1437 m_fOpenOnWasClosed = false;
1438 Log(("VBoxUSBDevice::message: closing the device (%p)...\n", m_pDevice));
1439 m_pDevice->close(this, 0);
1440 }
1441
1442 /* release it (see start()) */
1443 Log(("VBoxUSBDevice::message: releasing the device (%p)...\n", m_pDevice));
1444 m_pDevice->release();
1445 m_pDevice = NULL;
1446 }
1447
1448 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1449 break;
1450
1451 default:
1452 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1453 break;
1454 }
1455
1456 Log(("VBoxUSBDevice::message([%p], %#x {%s}, %p {%s}, %p) -> %#x\n",
1457 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, irc));
1458 return irc;
1459}
1460
1461
1462/**
1463 * Schedule all devices belonging to the specified process for release.
1464 *
1465 * Devices that aren't currently in use will be released immediately.
1466 *
1467 * @param Owner The owner process.
1468 */
1469/* static */ void
1470org_virtualbox_VBoxUSBDevice::scheduleReleaseByOwner(RTPROCESS Owner)
1471{
1472 Log2(("VBoxUSBDevice::scheduleReleaseByOwner: Owner=%d\n", Owner));
1473 AssertReturnVoid(Owner && Owner != NIL_RTPROCESS);
1474
1475 /*
1476 * Walk the list of devices looking for device belonging to this process.
1477 *
1478 * If we release a device, we have to lave the spinlock and will therefore
1479 * have to restart the search.
1480 */
1481 VBOXUSB_LOCK();
1482
1483 org_virtualbox_VBoxUSBDevice *pCur;
1484 do
1485 {
1486 for (pCur = s_pHead; pCur; pCur = pCur->m_pNext)
1487 {
1488 Log2(("VBoxUSBDevice::scheduleReleaseByOwner: pCur=%p m_Owner=%d (%s) m_fReleaseOnClose=%d\n",
1489 pCur, pCur->m_Owner, pCur->m_Owner == Owner ? "match" : "mismatch", pCur->m_fReleaseOnClose));
1490 if (pCur->m_Owner == Owner)
1491 {
1492 /* make sure we won't hit it again. */
1493 pCur->m_Owner = NIL_RTPROCESS;
1494 IOUSBDevice *pDevice = pCur->m_pDevice;
1495 if ( pDevice
1496 && !pCur->m_fReleaseOnClose)
1497 {
1498 pCur->m_fOpenOnWasClosed = false;
1499 if (pCur->m_Client != NIL_RTPROCESS)
1500 {
1501 /* It's currently open, so just schedule it for re-enumeration on close. */
1502 ASMAtomicWriteBool(&pCur->m_fReleaseOnClose, true);
1503 Log(("VBoxUSBDevice::scheduleReleaseByOwner: %p {%s} - used by %d\n",
1504 pDevice, pDevice->getName(), pCur->m_Client));
1505 }
1506 else
1507 {
1508 /*
1509 * Get the USBDevice object and do the re-enumeration now.
1510 * Retain the device so we don't run into any trouble.
1511 */
1512 pDevice->retain();
1513 VBOXUSB_UNLOCK();
1514
1515 IOReturn irc = pDevice->ReEnumerateDevice(0); NOREF(irc);
1516 Log(("VBoxUSBDevice::scheduleReleaseByOwner: %p {%s} - ReEnumerateDevice -> %#x\n",
1517 pDevice, pDevice->getName(), irc));
1518
1519 pDevice->release();
1520 VBOXUSB_LOCK();
1521 break;
1522 }
1523 }
1524 }
1525 }
1526 } while (pCur);
1527
1528 VBOXUSB_UNLOCK();
1529}
1530
1531
1532#ifdef DEBUG
1533/*static*/ IOReturn
1534org_virtualbox_VBoxUSBDevice::MyInterestHandler(void *pvTarget, void *pvRefCon, UInt32 enmMsgType,
1535 IOService *pProvider, void * pvMsgArg, vm_size_t cbMsgArg)
1536{
1537 org_virtualbox_VBoxUSBDevice *pThis = (org_virtualbox_VBoxUSBDevice *)pvTarget;
1538 if (!pThis)
1539 return kIOReturnError;
1540
1541 switch (enmMsgType)
1542 {
1543 case kIOMessageServiceIsAttemptingOpen:
1544 /* pvMsgArg == the open() fOptions, so we could check for kIOServiceSeize if we care.
1545 We'll also get a kIIOServiceRequestingClose message() for that... */
1546 Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceIsAttemptingOpen - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1547 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1548 break;
1549
1550 case kIOMessageServiceWasClosed:
1551 Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceWasClosed - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1552 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1553 break;
1554
1555 case kIOMessageServiceIsTerminated:
1556 Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceIsTerminated - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1557 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1558 break;
1559
1560 case kIOUSBMessagePortHasBeenReset:
1561 Log(("VBoxUSBDevice::MyInterestHandler: kIOUSBMessagePortHasBeenReset - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1562 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1563 break;
1564
1565 default:
1566 Log(("VBoxUSBDevice::MyInterestHandler: %#x (%s) - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1567 enmMsgType, DbgGetIOKitMessageName(enmMsgType), pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1568 break;
1569 }
1570
1571 return kIOReturnSuccess;
1572}
1573#endif /* DEBUG */
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588/*
1589 *
1590 * org_virtualbox_VBoxUSBInterface
1591 *
1592 */
1593
1594/**
1595 * Initialize our data members.
1596 */
1597bool
1598org_virtualbox_VBoxUSBInterface::init(OSDictionary *pDictionary)
1599{
1600 uint32_t cInstances = ASMAtomicIncU32(&g_cInstances);
1601 Log(("VBoxUSBInterface::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances));
1602
1603 m_pInterface = NULL;
1604 m_fOpen = false;
1605 m_fOpenOnWasClosed = false;
1606
1607 return IOUSBUserClientInit::init(pDictionary);
1608}
1609
1610
1611/**
1612 * Free the object.
1613 * @remark Only for logging.
1614 */
1615void
1616org_virtualbox_VBoxUSBInterface::free()
1617{
1618 uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances);
1619 Log(("VBoxUSBInterfaces::free([%p]) new g_cInstances=%d\n", this, cInstances));
1620 IOUSBUserClientInit::free();
1621}
1622
1623
1624/**
1625 * Probe the interface to see if we're the right driver for it.
1626 *
1627 * We implement this similarly to org_virtualbox_VBoxUSBDevice, except that
1628 * we don't bother matching filters but instead just check if the parent is
1629 * handled by org_virtualbox_VBoxUSBDevice or not.
1630 */
1631IOService *
1632org_virtualbox_VBoxUSBInterface::probe(IOService *pProvider, SInt32 *pi32Score)
1633{
1634 Log(("VBoxUSBInterface::probe([%p], %p {%s}, %p={%d})\n", this,
1635 pProvider, pProvider->getName(), pi32Score, pi32Score ? *pi32Score : 0));
1636
1637 /*
1638 * Check if VBoxUSBDevice is the parent's driver.
1639 */
1640 bool fHijackIt = false;
1641 const IORegistryPlane *pServicePlane = getPlane(kIOServicePlane);
1642 IORegistryEntry *pParent = pProvider->getParentEntry(pServicePlane);
1643 if (pParent)
1644 {
1645 Log(("VBoxUSBInterface::probe: pParent=%p {%s}\n", pParent, pParent->getName()));
1646
1647 OSIterator *pSiblings = pParent->getChildIterator(pServicePlane);
1648 if (pSiblings)
1649 {
1650 IORegistryEntry *pSibling;
1651 while ( (pSibling = OSDynamicCast(IORegistryEntry, pSiblings->getNextObject())) )
1652 {
1653 const OSMetaClass *pMetaClass = pSibling->getMetaClass();
1654 Log2(("sibling: %p - %s - %s\n", pMetaClass, pSibling->getName(), pMetaClass->getClassName()));
1655 if (pMetaClass == &org_virtualbox_VBoxUSBDevice::gMetaClass)
1656 {
1657 fHijackIt = true;
1658 break;
1659 }
1660 }
1661 pSiblings->release();
1662 }
1663 }
1664 if (!fHijackIt)
1665 {
1666 Log(("VBoxUSBInterface::probe: returns NULL\n"));
1667 return NULL;
1668 }
1669
1670 IOService *pRet = IOUSBUserClientInit::probe(pProvider, pi32Score);
1671 *pi32Score = _1G;
1672 Log(("VBoxUSBInterface::probe: returns %p and *pi32Score=%d - hijack it.\n", pRet, *pi32Score));
1673 return pRet;
1674}
1675
1676
1677/**
1678 * Start the driver (this), retain and open the USB interface object (pProvider).
1679 */
1680bool
1681org_virtualbox_VBoxUSBInterface::start(IOService *pProvider)
1682{
1683 Log(("VBoxUSBInterface::start([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
1684
1685 /*
1686 * Exploit IOUSBUserClientInit to process IOProviderMergeProperties.
1687 */
1688 IOUSBUserClientInit::start(pProvider); /* returns false */
1689
1690 /*
1691 * Retain the and open the interface (stop() or message() cleans up).
1692 */
1693 bool fRc = true;
1694 m_pInterface = OSDynamicCast(IOUSBInterface, pProvider);
1695 if (m_pInterface)
1696 {
1697 m_pInterface->retain();
1698 m_fOpen = m_pInterface->open(this, kIOServiceSeize, 0);
1699 if (!m_fOpen)
1700 Log(("VBoxUSBInterface::start: failed to open the interface!\n"));
1701 m_fOpenOnWasClosed = !m_fOpen;
1702 }
1703 else
1704 {
1705 printf("VBoxUSBInterface::start([%p], %p {%s}): failed!\n", this, pProvider, pProvider->getName());
1706 fRc = false;
1707 }
1708
1709 Log(("VBoxUSBInterface::start: returns %d\n", fRc));
1710 return fRc;
1711}
1712
1713
1714/**
1715 * Close and release the USB interface object (pProvider) and stop the driver (this).
1716 */
1717void
1718org_virtualbox_VBoxUSBInterface::stop(IOService *pProvider)
1719{
1720 Log(("org_virtualbox_VBoxUSBInterface::stop([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
1721
1722 /*
1723 * Close and release the IOUSBInterface if didn't do that already in message().
1724 */
1725 if (m_pInterface)
1726 {
1727 /* close it */
1728 if (m_fOpen)
1729 {
1730 m_fOpenOnWasClosed = false;
1731 m_fOpen = false;
1732 m_pInterface->close(this, 0);
1733 }
1734
1735 /* release it (see start()) */
1736 m_pInterface->release();
1737 m_pInterface = NULL;
1738 }
1739
1740 IOUSBUserClientInit::stop(pProvider);
1741 Log(("VBoxUSBInterface::stop: returns void\n"));
1742}
1743
1744
1745/**
1746 * Terminate the service (initiate the destruction).
1747 * @remark Only for logging.
1748 */
1749bool
1750org_virtualbox_VBoxUSBInterface::terminate(IOOptionBits fOptions)
1751{
1752 /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */
1753 Log(("VBoxUSBInterface::terminate([%p], %#x)\n", this, fOptions));
1754 return IOUSBUserClientInit::terminate(fOptions);
1755}
1756
1757
1758/**
1759 * @copydoc org_virtualbox_VBoxUSBDevice::message
1760 */
1761IOReturn
1762org_virtualbox_VBoxUSBInterface::message(UInt32 enmMsg, IOService *pProvider, void *pvArg)
1763{
1764 Log(("VBoxUSBInterface::message([%p], %#x {%s}, %p {%s}, %p)\n",
1765 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg));
1766
1767 IOReturn irc;
1768 switch (enmMsg)
1769 {
1770 /*
1771 * See explanation in org_virtualbox_VBoxUSBDevice::message.
1772 */
1773 case kIOMessageServiceIsRequestingClose:
1774 irc = kIOReturnExclusiveAccess;
1775 if (!((uintptr_t)pvArg & kIOServiceSeize))
1776 {
1777 Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d: not seize - closing...\n",
1778 this, pProvider, pProvider->getName(), pvArg, RTProcSelf()));
1779 m_fOpen = false;
1780 m_fOpenOnWasClosed = false;
1781 if (m_pInterface)
1782 m_pInterface->close(this, 0);
1783 irc = kIOReturnSuccess;
1784 }
1785 else
1786 {
1787 if (org_virtualbox_VBoxUSBClient::isClientTask(current_task()))
1788 {
1789 Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d task=%p: client process, closing.\n",
1790 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1791 m_fOpen = false;
1792 m_fOpenOnWasClosed = false;
1793 if (m_pInterface)
1794 m_pInterface->close(this, 0);
1795 m_fOpenOnWasClosed = true;
1796 irc = kIOReturnSuccess;
1797 }
1798 else
1799 Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d task=%p: not client process!\n",
1800 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1801 }
1802 break;
1803
1804 /*
1805 * The service was closed by the current client, check for re-open.
1806 */
1807 case kIOMessageServiceWasClosed:
1808 if (m_pInterface && m_fOpenOnWasClosed)
1809 {
1810 Log(("VBoxUSBInterface::message: attempting to re-open the interface...\n"));
1811 m_fOpenOnWasClosed = false;
1812 m_fOpen = m_pInterface->open(this, kIOServiceSeize, 0);
1813 if (!m_fOpen)
1814 Log(("VBoxUSBInterface::message: failed to open the interface!\n"));
1815 m_fOpenOnWasClosed = !m_fOpen;
1816 }
1817
1818 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1819 break;
1820
1821 /*
1822 * The IOUSBInterface/Device is shutting down, so close and release.
1823 */
1824 case kIOMessageServiceIsTerminated:
1825 if (m_pInterface)
1826 {
1827 /* close it */
1828 if (m_fOpen)
1829 {
1830 m_fOpen = false;
1831 m_fOpenOnWasClosed = false;
1832 m_pInterface->close(this, 0);
1833 }
1834
1835 /* release it (see start()) */
1836 m_pInterface->release();
1837 m_pInterface = NULL;
1838 }
1839
1840 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1841 break;
1842
1843 default:
1844 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1845 break;
1846 }
1847
1848 Log(("VBoxUSBInterface::message([%p], %#x {%s}, %p {%s}, %p) -> %#x\n",
1849 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, irc));
1850 return irc;
1851}
1852
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