VirtualBox

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

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

VBoxUSB: Don't call IOUSBUserClientInit::probe because the result is not used anyway

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.7 KB
Line 
1/* $Id: VBoxUSB.cpp 59399 2016-01-19 08:06:25Z 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 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(), true);
1085 if (RT_FAILURE(vrc))
1086 Log(("VBoxUSBDevice::probe: pObj=%p pStr=%p - %d/%s - rc=%d!\n", pObj, pStr, i, s_aProps[i].pszName, vrc));
1087 }
1088 else
1089 Log(("VBoxUSBDevice::probe: pObj=%p pStr=%p - %d/%s\n", pObj, pStr, i, s_aProps[i].pszName));
1090 }
1091 }
1092 /** @todo try figure the blasted bus number */
1093
1094 /*
1095 * Run filters on it.
1096 */
1097 uintptr_t uId = 0;
1098 RTPROCESS Owner = VBoxUSBFilterMatch(&Device, &uId);
1099 USBFilterDelete(&Device);
1100 if (Owner == NIL_RTPROCESS)
1101 {
1102 Log(("VBoxUSBDevice::probe: returns NULL uId=%d\n", uId));
1103 return NULL;
1104 }
1105
1106 /*
1107 * It matched. Save the owner in the provider registry (hope that works).
1108 */
1109 /*IOService *pRet = IOUSBUserClientInit::probe(pProvider, pi32Score); - call always returns NULL on 10.11+ */
1110 /*AssertMsg(pRet == this, ("pRet=%p this=%p *pi32Score=%d \n", pRet, this, pi32Score ? *pi32Score : 0)); - call always returns NULL on 10.11+ */
1111 pRet = this;
1112 m_Owner = Owner;
1113 m_uId = uId;
1114 Log(("%p: m_Owner=%d m_uId=%d\n", this, (int)m_Owner, (int)m_uId));
1115 *pi32Score = _1G;
1116 Log(("VBoxUSBDevice::probe: returns %p and *pi32Score=%d\n", pRet, *pi32Score));
1117 return pRet;
1118}
1119
1120
1121/**
1122 * Try start the device driver.
1123 *
1124 * We will do device linking, copy the filter and owner properties from the provider,
1125 * set the client property, retain the device, and try open (seize) the device.
1126 *
1127 * @returns Success indicator.
1128 * @param pProvider The provider instance.
1129 */
1130bool
1131org_virtualbox_VBoxUSBDevice::start(IOService *pProvider)
1132{
1133 Log(("VBoxUSBDevice::start([%p:{.m_Owner=%d, .m_uId=%p}], %p {%s})\n",
1134 this, m_Owner, m_uId, pProvider, pProvider->getName()));
1135
1136 m_pDevice = OSDynamicCast(IOUSBDevice, pProvider);
1137 if (!m_pDevice)
1138 {
1139 printf("VBoxUSBDevice::start([%p], %p {%s}): failed!\n", this, pProvider, pProvider->getName());
1140 return false;
1141 }
1142
1143#ifdef DEBUG
1144 /* for some extra log messages */
1145 m_pNotifier = pProvider->registerInterest(gIOGeneralInterest,
1146 &org_virtualbox_VBoxUSBDevice::MyInterestHandler,
1147 this, /* pvTarget */
1148 NULL); /* pvRefCon */
1149#endif
1150
1151 /*
1152 * Exploit IOUSBUserClientInit to process IOProviderMergeProperties.
1153 */
1154 IOUSBUserClientInit::start(pProvider); /* returns false */
1155
1156 /*
1157 * Link ourselves into the list of hijacked device.
1158 */
1159 VBOXUSB_LOCK();
1160
1161 m_pNext = s_pHead;
1162 s_pHead = this;
1163
1164 VBOXUSB_UNLOCK();
1165
1166 /*
1167 * Set the VBoxUSB properties.
1168 */
1169 if (!setProperty(VBOXUSB_OWNER_KEY, (unsigned long long)m_Owner, sizeof(m_Owner) * 8 /* bits */))
1170 Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_OWNER_KEY "' property!\n"));
1171 if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */))
1172 Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n"));
1173 if (!setProperty(VBOXUSB_FILTER_KEY, (unsigned long long)m_uId, sizeof(m_uId) * 8 /* bits */))
1174 Log(("VBoxUSBDevice::start: failed to set the '" VBOXUSB_FILTER_KEY "' property!\n"));
1175
1176 /*
1177 * Retain and open the device.
1178 */
1179 m_pDevice->retain();
1180 m_fOpen = m_pDevice->open(this, kIOServiceSeize, 0);
1181 if (!m_fOpen)
1182 Log(("VBoxUSBDevice::start: failed to open the device!\n"));
1183 m_fOpenOnWasClosed = !m_fOpen;
1184
1185 Log(("VBoxUSBDevice::start: returns %d\n", true));
1186 return true;
1187}
1188
1189
1190/**
1191 * Stop the device driver.
1192 *
1193 * We'll unlink the device, start device re-enumeration and close it. And call
1194 * the parent stop method of course.
1195 *
1196 * @param pProvider The provider instance.
1197 */
1198void
1199org_virtualbox_VBoxUSBDevice::stop(IOService *pProvider)
1200{
1201 Log(("VBoxUSBDevice::stop([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
1202
1203 /*
1204 * Remove ourselves from the list of device.
1205 */
1206 VBOXUSB_LOCK();
1207
1208 org_virtualbox_VBoxUSBDevice *pPrev = NULL;
1209 for (org_virtualbox_VBoxUSBDevice *pCur = s_pHead; pCur; pCur = pCur->m_pNext)
1210 {
1211 if (pCur == this)
1212 {
1213 if (pPrev)
1214 pPrev->m_pNext = m_pNext;
1215 else
1216 s_pHead = m_pNext;
1217 m_pNext = NULL;
1218 break;
1219 }
1220 pPrev = pCur;
1221 }
1222
1223 VBOXUSB_UNLOCK();
1224
1225 /*
1226 * Should we release the device?
1227 */
1228 if (m_fBeingUnloaded)
1229 {
1230 if (m_pDevice)
1231 {
1232 IOReturn irc = m_pDevice->ReEnumerateDevice(0); NOREF(irc);
1233 Log(("VBoxUSBDevice::stop([%p], %p {%s}): m_pDevice=%p unload & ReEnumerateDevice -> %#x\n",
1234 this, pProvider, pProvider->getName(), m_pDevice, irc));
1235 }
1236 else
1237 {
1238 IOUSBDevice *pDevice = OSDynamicCast(IOUSBDevice, pProvider);
1239 if (pDevice)
1240 {
1241 IOReturn irc = pDevice->ReEnumerateDevice(0); NOREF(irc);
1242 Log(("VBoxUSBDevice::stop([%p], %p {%s}): pDevice=%p unload & ReEnumerateDevice -> %#x\n",
1243 this, pProvider, pProvider->getName(), pDevice, irc));
1244 }
1245 else
1246 Log(("VBoxUSBDevice::stop([%p], %p {%s}): failed to cast provider to IOUSBDevice\n",
1247 this, pProvider, pProvider->getName()));
1248 }
1249 }
1250 else if (m_fReleaseOnClose)
1251 {
1252 ASMAtomicWriteBool(&m_fReleaseOnClose, false);
1253 if (m_pDevice)
1254 {
1255 IOReturn irc = m_pDevice->ReEnumerateDevice(0); NOREF(irc);
1256 Log(("VBoxUSBDevice::stop([%p], %p {%s}): m_pDevice=%p close & ReEnumerateDevice -> %#x\n",
1257 this, pProvider, pProvider->getName(), m_pDevice, irc));
1258 }
1259 }
1260
1261 /*
1262 * Close and release the IOUSBDevice if didn't do that already in message().
1263 */
1264 if (m_pDevice)
1265 {
1266 /* close it */
1267 if (m_fOpen)
1268 {
1269 m_fOpenOnWasClosed = false;
1270 m_fOpen = false;
1271 m_pDevice->close(this, 0);
1272 }
1273
1274 /* release it (see start()) */
1275 m_pDevice->release();
1276 m_pDevice = NULL;
1277 }
1278
1279#ifdef DEBUG
1280 /* avoid crashing on unload. */
1281 if (m_pNotifier)
1282 {
1283 m_pNotifier->release();
1284 m_pNotifier = NULL;
1285 }
1286#endif
1287
1288 IOUSBUserClientInit::stop(pProvider);
1289 Log(("VBoxUSBDevice::stop: returns void\n"));
1290}
1291
1292
1293/**
1294 * Terminate the service (initiate the destruction).
1295 * @remark Only for logging.
1296 */
1297bool
1298org_virtualbox_VBoxUSBDevice::terminate(IOOptionBits fOptions)
1299{
1300 /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */
1301 Log(("VBoxUSBDevice::terminate([%p], %#x)\n", this, fOptions));
1302
1303 /*
1304 * There aren't too many reasons why we gets terminated.
1305 * The most common one is that the device is being unplugged. Another is
1306 * that we've triggered reenumeration. In both cases we'll get a
1307 * kIOMessageServiceIsTerminated message before we're stopped.
1308 *
1309 * But, when we're unloaded the provider service isn't terminated, and
1310 * for some funny reason we're frequently causing kernel panics when the
1311 * device is detached (after we're unloaded). So, for now, let's try
1312 * re-enumerate it in stop.
1313 *
1314 * To avoid creating unnecessary trouble we'll try guess if we're being
1315 * unloaded from the option bit mask. (kIOServiceRecursing is private btw.)
1316 */
1317 /** @todo would be nice if there was a documented way of doing the unload detection this, or
1318 * figure out what exactly we're doing wrong in the unload scenario. */
1319 if ((fOptions & 0xffff) == (kIOServiceRequired | kIOServiceSynchronous))
1320 m_fBeingUnloaded = true;
1321
1322 return IOUSBUserClientInit::terminate(fOptions);
1323}
1324
1325
1326/**
1327 * Intercept open requests and only let Mr. Right (the VM process) open the device.
1328 * This is where it all gets a bit complicated...
1329 *
1330 * @return Status code.
1331 *
1332 * @param enmMsg The message number.
1333 * @param pProvider Pointer to the provider instance.
1334 * @param pvArg Message argument.
1335 */
1336IOReturn
1337org_virtualbox_VBoxUSBDevice::message(UInt32 enmMsg, IOService *pProvider, void *pvArg)
1338{
1339 Log(("VBoxUSBDevice::message([%p], %#x {%s}, %p {%s}, %p) - pid=%d\n",
1340 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, RTProcSelf()));
1341
1342 IOReturn irc;
1343 switch (enmMsg)
1344 {
1345 /*
1346 * This message is send to the current IOService client from IOService::handleOpen(),
1347 * expecting it to call pProvider->close() if it agrees to the other party seizing
1348 * the service. It is also called in IOService::didTerminate() and perhaps some other
1349 * odd places. The way to find out is to examin the pvArg, which would be including
1350 * kIOServiceSeize if it's the handleOpen case.
1351 *
1352 * How to validate that the other end is actually our VM process? Well, IOKit doesn't
1353 * provide any clue about the new client really. But fortunately, it seems like the
1354 * calling task/process context when the VM tries to open the device is the VM process.
1355 * We'll ASSUME this'll remain like this for now...
1356 */
1357 case kIOMessageServiceIsRequestingClose:
1358 irc = kIOReturnExclusiveAccess;
1359 /* If it's not a seize request, assume it's didTerminate and pray that it isn't a rouge driver.
1360 ... weird, doesn't seem to match for the post has-terminated messages. */
1361 if (!((uintptr_t)pvArg & kIOServiceSeize))
1362 {
1363 Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d: not seize - closing...\n",
1364 this, pProvider, pProvider->getName(), pvArg, RTProcSelf()));
1365 m_fOpen = false;
1366 m_fOpenOnWasClosed = false;
1367 if (m_pDevice)
1368 m_pDevice->close(this, 0);
1369 m_Client = NIL_RTPROCESS;
1370 irc = kIOReturnSuccess;
1371 }
1372 else
1373 {
1374 if (org_virtualbox_VBoxUSBClient::isClientTask(current_task()))
1375 {
1376 Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d task=%p: client process, closing.\n",
1377 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1378 m_fOpen = false;
1379 m_fOpenOnWasClosed = false;
1380 if (m_pDevice)
1381 m_pDevice->close(this, 0);
1382 m_fOpenOnWasClosed = true;
1383 m_Client = RTProcSelf();
1384 irc = kIOReturnSuccess;
1385 }
1386 else
1387 Log(("VBoxUSBDevice::message([%p],%p {%s}, %p) - pid=%d task=%p: not client process!\n",
1388 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1389 }
1390 if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */))
1391 Log(("VBoxUSBDevice::message: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n"));
1392 break;
1393
1394 /*
1395 * The service was closed by the current client.
1396 * Update the client property, check for scheduled re-enumeration and re-open.
1397 *
1398 * Note that we will not be called if we're doing the closing. (Even if we was
1399 * called in that case, the code should be able to handle it.)
1400 */
1401 case kIOMessageServiceWasClosed:
1402 /*
1403 * Update the client property value.
1404 */
1405 if (m_Client != NIL_RTPROCESS)
1406 {
1407 m_Client = NIL_RTPROCESS;
1408 if (!setProperty(VBOXUSB_CLIENT_KEY, (unsigned long long)m_Client, sizeof(m_Client) * 8 /* bits */))
1409 Log(("VBoxUSBDevice::message: failed to set the '" VBOXUSB_CLIENT_KEY "' property!\n"));
1410 }
1411
1412 if (m_pDevice)
1413 {
1414 /*
1415 * Should we release the device?
1416 */
1417 if (ASMAtomicXchgBool(&m_fReleaseOnClose, false))
1418 {
1419 m_fOpenOnWasClosed = false;
1420 irc = m_pDevice->ReEnumerateDevice(0);
1421 Log(("VBoxUSBDevice::message([%p], %p {%s}) - ReEnumerateDevice() -> %#x\n",
1422 this, pProvider, pProvider->getName(), irc));
1423 }
1424 /*
1425 * Should we attempt to re-open the device?
1426 */
1427 else if (m_fOpenOnWasClosed)
1428 {
1429 Log(("VBoxUSBDevice::message: attempting to re-open the device...\n"));
1430 m_fOpenOnWasClosed = false;
1431 m_fOpen = m_pDevice->open(this, kIOServiceSeize, 0);
1432 if (!m_fOpen)
1433 Log(("VBoxUSBDevice::message: failed to open the device!\n"));
1434 m_fOpenOnWasClosed = !m_fOpen;
1435 }
1436 }
1437
1438 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1439 break;
1440
1441 /*
1442 * The IOUSBDevice is shutting down, so close it if we've opened it.
1443 */
1444 case kIOMessageServiceIsTerminated:
1445 m_fBeingUnloaded = false;
1446 ASMAtomicWriteBool(&m_fReleaseOnClose, false);
1447 if (m_pDevice)
1448 {
1449 /* close it */
1450 if (m_fOpen)
1451 {
1452 m_fOpen = false;
1453 m_fOpenOnWasClosed = false;
1454 Log(("VBoxUSBDevice::message: closing the device (%p)...\n", m_pDevice));
1455 m_pDevice->close(this, 0);
1456 }
1457
1458 /* release it (see start()) */
1459 Log(("VBoxUSBDevice::message: releasing the device (%p)...\n", m_pDevice));
1460 m_pDevice->release();
1461 m_pDevice = NULL;
1462 }
1463
1464 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1465 break;
1466
1467 default:
1468 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1469 break;
1470 }
1471
1472 Log(("VBoxUSBDevice::message([%p], %#x {%s}, %p {%s}, %p) -> %#x\n",
1473 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, irc));
1474 return irc;
1475}
1476
1477
1478/**
1479 * Schedule all devices belonging to the specified process for release.
1480 *
1481 * Devices that aren't currently in use will be released immediately.
1482 *
1483 * @param Owner The owner process.
1484 */
1485/* static */ void
1486org_virtualbox_VBoxUSBDevice::scheduleReleaseByOwner(RTPROCESS Owner)
1487{
1488 Log2(("VBoxUSBDevice::scheduleReleaseByOwner: Owner=%d\n", Owner));
1489 AssertReturnVoid(Owner && Owner != NIL_RTPROCESS);
1490
1491 /*
1492 * Walk the list of devices looking for device belonging to this process.
1493 *
1494 * If we release a device, we have to lave the spinlock and will therefore
1495 * have to restart the search.
1496 */
1497 VBOXUSB_LOCK();
1498
1499 org_virtualbox_VBoxUSBDevice *pCur;
1500 do
1501 {
1502 for (pCur = s_pHead; pCur; pCur = pCur->m_pNext)
1503 {
1504 Log2(("VBoxUSBDevice::scheduleReleaseByOwner: pCur=%p m_Owner=%d (%s) m_fReleaseOnClose=%d\n",
1505 pCur, pCur->m_Owner, pCur->m_Owner == Owner ? "match" : "mismatch", pCur->m_fReleaseOnClose));
1506 if (pCur->m_Owner == Owner)
1507 {
1508 /* make sure we won't hit it again. */
1509 pCur->m_Owner = NIL_RTPROCESS;
1510 IOUSBDevice *pDevice = pCur->m_pDevice;
1511 if ( pDevice
1512 && !pCur->m_fReleaseOnClose)
1513 {
1514 pCur->m_fOpenOnWasClosed = false;
1515 if (pCur->m_Client != NIL_RTPROCESS)
1516 {
1517 /* It's currently open, so just schedule it for re-enumeration on close. */
1518 ASMAtomicWriteBool(&pCur->m_fReleaseOnClose, true);
1519 Log(("VBoxUSBDevice::scheduleReleaseByOwner: %p {%s} - used by %d\n",
1520 pDevice, pDevice->getName(), pCur->m_Client));
1521 }
1522 else
1523 {
1524 /*
1525 * Get the USBDevice object and do the re-enumeration now.
1526 * Retain the device so we don't run into any trouble.
1527 */
1528 pDevice->retain();
1529 VBOXUSB_UNLOCK();
1530
1531 IOReturn irc = pDevice->ReEnumerateDevice(0); NOREF(irc);
1532 Log(("VBoxUSBDevice::scheduleReleaseByOwner: %p {%s} - ReEnumerateDevice -> %#x\n",
1533 pDevice, pDevice->getName(), irc));
1534
1535 pDevice->release();
1536 VBOXUSB_LOCK();
1537 break;
1538 }
1539 }
1540 }
1541 }
1542 } while (pCur);
1543
1544 VBOXUSB_UNLOCK();
1545}
1546
1547
1548#ifdef DEBUG
1549/*static*/ IOReturn
1550org_virtualbox_VBoxUSBDevice::MyInterestHandler(void *pvTarget, void *pvRefCon, UInt32 enmMsgType,
1551 IOService *pProvider, void * pvMsgArg, vm_size_t cbMsgArg)
1552{
1553 org_virtualbox_VBoxUSBDevice *pThis = (org_virtualbox_VBoxUSBDevice *)pvTarget;
1554 if (!pThis)
1555 return kIOReturnError;
1556
1557 switch (enmMsgType)
1558 {
1559 case kIOMessageServiceIsAttemptingOpen:
1560 /* pvMsgArg == the open() fOptions, so we could check for kIOServiceSeize if we care.
1561 We'll also get a kIIOServiceRequestingClose message() for that... */
1562 Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceIsAttemptingOpen - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1563 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1564 break;
1565
1566 case kIOMessageServiceWasClosed:
1567 Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceWasClosed - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1568 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1569 break;
1570
1571 case kIOMessageServiceIsTerminated:
1572 Log(("VBoxUSBDevice::MyInterestHandler: kIOMessageServiceIsTerminated - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1573 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1574 break;
1575
1576 case kIOUSBMessagePortHasBeenReset:
1577 Log(("VBoxUSBDevice::MyInterestHandler: kIOUSBMessagePortHasBeenReset - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1578 pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1579 break;
1580
1581 default:
1582 Log(("VBoxUSBDevice::MyInterestHandler: %#x (%s) - pvRefCon=%p pProvider=%p pvMsgArg=%p cbMsgArg=%d\n",
1583 enmMsgType, DbgGetIOKitMessageName(enmMsgType), pvRefCon, pProvider, pvMsgArg, cbMsgArg));
1584 break;
1585 }
1586
1587 return kIOReturnSuccess;
1588}
1589#endif /* DEBUG */
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604/*
1605 *
1606 * org_virtualbox_VBoxUSBInterface
1607 *
1608 */
1609
1610/**
1611 * Initialize our data members.
1612 */
1613bool
1614org_virtualbox_VBoxUSBInterface::init(OSDictionary *pDictionary)
1615{
1616 uint32_t cInstances = ASMAtomicIncU32(&g_cInstances);
1617 Log(("VBoxUSBInterface::init([%p], %p) new g_cInstances=%d\n", this, pDictionary, cInstances));
1618
1619 m_pInterface = NULL;
1620 m_fOpen = false;
1621 m_fOpenOnWasClosed = false;
1622
1623 return IOUSBUserClientInit::init(pDictionary);
1624}
1625
1626
1627/**
1628 * Free the object.
1629 * @remark Only for logging.
1630 */
1631void
1632org_virtualbox_VBoxUSBInterface::free()
1633{
1634 uint32_t cInstances = ASMAtomicDecU32(&g_cInstances); NOREF(cInstances);
1635 Log(("VBoxUSBInterfaces::free([%p]) new g_cInstances=%d\n", this, cInstances));
1636 IOUSBUserClientInit::free();
1637}
1638
1639
1640/**
1641 * Probe the interface to see if we're the right driver for it.
1642 *
1643 * We implement this similarly to org_virtualbox_VBoxUSBDevice, except that
1644 * we don't bother matching filters but instead just check if the parent is
1645 * handled by org_virtualbox_VBoxUSBDevice or not.
1646 */
1647IOService *
1648org_virtualbox_VBoxUSBInterface::probe(IOService *pProvider, SInt32 *pi32Score)
1649{
1650 Log(("VBoxUSBInterface::probe([%p], %p {%s}, %p={%d})\n", this,
1651 pProvider, pProvider->getName(), pi32Score, pi32Score ? *pi32Score : 0));
1652
1653 /*
1654 * Check if VBoxUSBDevice is the parent's driver.
1655 */
1656 bool fHijackIt = false;
1657 const IORegistryPlane *pServicePlane = getPlane(kIOServicePlane);
1658 IORegistryEntry *pParent = pProvider->getParentEntry(pServicePlane);
1659 if (pParent)
1660 {
1661 Log(("VBoxUSBInterface::probe: pParent=%p {%s}\n", pParent, pParent->getName()));
1662
1663 OSIterator *pSiblings = pParent->getChildIterator(pServicePlane);
1664 if (pSiblings)
1665 {
1666 IORegistryEntry *pSibling;
1667 while ( (pSibling = OSDynamicCast(IORegistryEntry, pSiblings->getNextObject())) )
1668 {
1669 const OSMetaClass *pMetaClass = pSibling->getMetaClass();
1670 Log2(("sibling: %p - %s - %s\n", pMetaClass, pSibling->getName(), pMetaClass->getClassName()));
1671 if (pMetaClass == &org_virtualbox_VBoxUSBDevice::gMetaClass)
1672 {
1673 fHijackIt = true;
1674 break;
1675 }
1676 }
1677 pSiblings->release();
1678 }
1679 }
1680 if (!fHijackIt)
1681 {
1682 Log(("VBoxUSBInterface::probe: returns NULL\n"));
1683 return NULL;
1684 }
1685
1686 /* IOService *pRet = IOUSBUserClientInit::probe(pProvider, pi32Score); - call always returns NULL on 10.11+ */
1687 pRet = this;
1688 *pi32Score = _1G;
1689 Log(("VBoxUSBInterface::probe: returns %p and *pi32Score=%d - hijack it.\n", pRet, *pi32Score));
1690 return pRet;
1691}
1692
1693
1694/**
1695 * Start the driver (this), retain and open the USB interface object (pProvider).
1696 */
1697bool
1698org_virtualbox_VBoxUSBInterface::start(IOService *pProvider)
1699{
1700 Log(("VBoxUSBInterface::start([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
1701
1702 /*
1703 * Exploit IOUSBUserClientInit to process IOProviderMergeProperties.
1704 */
1705 IOUSBUserClientInit::start(pProvider); /* returns false */
1706
1707 /*
1708 * Retain the and open the interface (stop() or message() cleans up).
1709 */
1710 bool fRc = true;
1711 m_pInterface = OSDynamicCast(IOUSBInterface, pProvider);
1712 if (m_pInterface)
1713 {
1714 m_pInterface->retain();
1715 m_fOpen = m_pInterface->open(this, kIOServiceSeize, 0);
1716 if (!m_fOpen)
1717 Log(("VBoxUSBInterface::start: failed to open the interface!\n"));
1718 m_fOpenOnWasClosed = !m_fOpen;
1719 }
1720 else
1721 {
1722 printf("VBoxUSBInterface::start([%p], %p {%s}): failed!\n", this, pProvider, pProvider->getName());
1723 fRc = false;
1724 }
1725
1726 Log(("VBoxUSBInterface::start: returns %d\n", fRc));
1727 return fRc;
1728}
1729
1730
1731/**
1732 * Close and release the USB interface object (pProvider) and stop the driver (this).
1733 */
1734void
1735org_virtualbox_VBoxUSBInterface::stop(IOService *pProvider)
1736{
1737 Log(("org_virtualbox_VBoxUSBInterface::stop([%p], %p {%s})\n", this, pProvider, pProvider->getName()));
1738
1739 /*
1740 * Close and release the IOUSBInterface if didn't do that already in message().
1741 */
1742 if (m_pInterface)
1743 {
1744 /* close it */
1745 if (m_fOpen)
1746 {
1747 m_fOpenOnWasClosed = false;
1748 m_fOpen = false;
1749 m_pInterface->close(this, 0);
1750 }
1751
1752 /* release it (see start()) */
1753 m_pInterface->release();
1754 m_pInterface = NULL;
1755 }
1756
1757 IOUSBUserClientInit::stop(pProvider);
1758 Log(("VBoxUSBInterface::stop: returns void\n"));
1759}
1760
1761
1762/**
1763 * Terminate the service (initiate the destruction).
1764 * @remark Only for logging.
1765 */
1766bool
1767org_virtualbox_VBoxUSBInterface::terminate(IOOptionBits fOptions)
1768{
1769 /* kIOServiceRecursing, kIOServiceRequired, kIOServiceTerminate, kIOServiceSynchronous - interesting option bits */
1770 Log(("VBoxUSBInterface::terminate([%p], %#x)\n", this, fOptions));
1771 return IOUSBUserClientInit::terminate(fOptions);
1772}
1773
1774
1775/**
1776 * @copydoc org_virtualbox_VBoxUSBDevice::message
1777 */
1778IOReturn
1779org_virtualbox_VBoxUSBInterface::message(UInt32 enmMsg, IOService *pProvider, void *pvArg)
1780{
1781 Log(("VBoxUSBInterface::message([%p], %#x {%s}, %p {%s}, %p)\n",
1782 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg));
1783
1784 IOReturn irc;
1785 switch (enmMsg)
1786 {
1787 /*
1788 * See explanation in org_virtualbox_VBoxUSBDevice::message.
1789 */
1790 case kIOMessageServiceIsRequestingClose:
1791 irc = kIOReturnExclusiveAccess;
1792 if (!((uintptr_t)pvArg & kIOServiceSeize))
1793 {
1794 Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d: not seize - closing...\n",
1795 this, pProvider, pProvider->getName(), pvArg, RTProcSelf()));
1796 m_fOpen = false;
1797 m_fOpenOnWasClosed = false;
1798 if (m_pInterface)
1799 m_pInterface->close(this, 0);
1800 irc = kIOReturnSuccess;
1801 }
1802 else
1803 {
1804 if (org_virtualbox_VBoxUSBClient::isClientTask(current_task()))
1805 {
1806 Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d task=%p: client process, closing.\n",
1807 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1808 m_fOpen = false;
1809 m_fOpenOnWasClosed = false;
1810 if (m_pInterface)
1811 m_pInterface->close(this, 0);
1812 m_fOpenOnWasClosed = true;
1813 irc = kIOReturnSuccess;
1814 }
1815 else
1816 Log(("VBoxUSBInterface::message([%p],%p {%s}, %p) - pid=%d task=%p: not client process!\n",
1817 this, pProvider, pProvider->getName(), pvArg, RTProcSelf(), current_task()));
1818 }
1819 break;
1820
1821 /*
1822 * The service was closed by the current client, check for re-open.
1823 */
1824 case kIOMessageServiceWasClosed:
1825 if (m_pInterface && m_fOpenOnWasClosed)
1826 {
1827 Log(("VBoxUSBInterface::message: attempting to re-open the interface...\n"));
1828 m_fOpenOnWasClosed = false;
1829 m_fOpen = m_pInterface->open(this, kIOServiceSeize, 0);
1830 if (!m_fOpen)
1831 Log(("VBoxUSBInterface::message: failed to open the interface!\n"));
1832 m_fOpenOnWasClosed = !m_fOpen;
1833 }
1834
1835 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1836 break;
1837
1838 /*
1839 * The IOUSBInterface/Device is shutting down, so close and release.
1840 */
1841 case kIOMessageServiceIsTerminated:
1842 if (m_pInterface)
1843 {
1844 /* close it */
1845 if (m_fOpen)
1846 {
1847 m_fOpen = false;
1848 m_fOpenOnWasClosed = false;
1849 m_pInterface->close(this, 0);
1850 }
1851
1852 /* release it (see start()) */
1853 m_pInterface->release();
1854 m_pInterface = NULL;
1855 }
1856
1857 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1858 break;
1859
1860 default:
1861 irc = IOUSBUserClientInit::message(enmMsg, pProvider, pvArg);
1862 break;
1863 }
1864
1865 Log(("VBoxUSBInterface::message([%p], %#x {%s}, %p {%s}, %p) -> %#x\n",
1866 this, enmMsg, DbgGetIOKitMessageName(enmMsg), pProvider, pProvider->getName(), pvArg, irc));
1867 return irc;
1868}
1869
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