VirtualBox

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

Last change on this file since 62490 was 62490, checked in by vboxsync, 8 years ago

(C) 2016

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