VirtualBox

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

Last change on this file since 49779 was 49779, checked in by vboxsync, 11 years ago

Mac OS X host: HID LEDs sync: resume built-in kbd before set its LEDs (extended VBoxUSB.kext and USBLib); introduce GUI/HidLedsSync extradata option in order to enable LEDs sync (not set/disabled by default); all Apple kbd devices removed from blacklist; SCROLL LED sync enabled again.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette