VirtualBox

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

Last change on this file since 69250 was 69250, checked in by vboxsync, 7 years ago

HostDrivers: scm updates

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