VirtualBox

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

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

VBoxUSB: warnings (clang)

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