VirtualBox

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

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

HostDrivers/Darwin,VBoxGuest/Darwin: Some notes about why we don't require to call task_reference() in initWithTask()

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