VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/darwin/USBProxyServiceDarwin.cpp@ 47470

Last change on this file since 47470 was 41528, checked in by vboxsync, 13 years ago

Main/HostUSBDevice(all platforms)+USBProxyService: redo USB locking, fixes major regression, added lots of assertions to catch locking flaws early, whitespace cleanup
Main/Machine: small USB locking fix to be consistent with the remaining code
Main/Host+glue/AutoLock: replace USB list lock by host lock, small numbering cleanup
Main/Console: redo USB locking, do less in USB callbacks/EMT (addresses long standing todo items), eliminate unsafe iterator parameters

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/* $Id: USBProxyServiceDarwin.cpp 41528 2012-05-31 16:48:33Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service (in VBoxSVC), Darwin Specialization.
4 */
5
6/*
7 * Copyright (C) 2005-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "USBProxyService.h"
23#include "Logging.h"
24#include "iokit.h"
25
26#include <VBox/usb.h>
27#include <VBox/usblib.h>
28#include <VBox/err.h>
29
30#include <iprt/string.h>
31#include <iprt/alloc.h>
32#include <iprt/assert.h>
33#include <iprt/file.h>
34#include <iprt/err.h>
35#include <iprt/asm.h>
36
37
38/**
39 * Initialize data members.
40 */
41USBProxyServiceDarwin::USBProxyServiceDarwin(Host *aHost)
42 : USBProxyService(aHost), mServiceRunLoopRef(NULL), mNotifyOpaque(NULL), mWaitABitNextTime(false), mUSBLibInitialized(false)
43{
44 LogFlowThisFunc(("aHost=%p\n", aHost));
45}
46
47
48/**
49 * Initializes the object (called right after construction).
50 *
51 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
52 */
53HRESULT USBProxyServiceDarwin::init(void)
54{
55#ifdef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
56 /*
57 * Initialize the USB library.
58 */
59 int rc = USBLibInit();
60 if (RT_FAILURE(rc))
61 {
62 mLastError = rc;
63 return S_OK;
64 }
65 mUSBLibInitialized = true;
66#endif
67
68 /*
69 * Start the poller thread.
70 */
71 start();
72 return S_OK;
73}
74
75
76/**
77 * Stop all service threads and free the device chain.
78 */
79USBProxyServiceDarwin::~USBProxyServiceDarwin()
80{
81 LogFlowThisFunc(("\n"));
82
83 /*
84 * Stop the service.
85 */
86 if (isActive())
87 stop();
88
89#ifdef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
90 /*
91 * Terminate the USB library - it'll
92 */
93 if (mUSBLibInitialized)
94 {
95 USBLibTerm();
96 mUSBLibInitialized = false;
97 }
98#endif
99}
100
101
102#ifdef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
103void *USBProxyServiceDarwin::insertFilter(PCUSBFILTER aFilter)
104{
105 return USBLibAddFilter(aFilter);
106}
107
108
109void USBProxyServiceDarwin::removeFilter(void *aId)
110{
111 USBLibRemoveFilter(aId);
112}
113#endif /* VBOX_WITH_NEW_USB_CODE_ON_DARWIN */
114
115
116int USBProxyServiceDarwin::captureDevice(HostUSBDevice *aDevice)
117{
118 /*
119 * Check preconditions.
120 */
121 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
122 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
123
124 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
125 LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str()));
126
127 Assert(aDevice->getUnistate() == kHostUSBDeviceState_Capturing);
128
129#ifndef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
130 /*
131 * Fake it.
132 */
133 ASMAtomicWriteBool(&mFakeAsync, true);
134 devLock.release();
135 interruptWait();
136 return VINF_SUCCESS;
137
138#else
139 /*
140 * Create a one-shot capture filter for the device (don't
141 * match on port) and trigger a re-enumeration of it.
142 */
143 USBFILTER Filter;
144 USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_CAPTURE);
145 initFilterFromDevice(&Filter, aDevice);
146
147 void *pvId = USBLibAddFilter(&Filter);
148 if (!pvId)
149 return VERR_GENERAL_FAILURE;
150
151 int rc = DarwinReEnumerateUSBDevice(aDevice->mUsb);
152 if (RT_SUCCESS(rc))
153 aDevice->mOneShotId = pvId;
154 else
155 {
156 USBLibRemoveFilter(pvId);
157 pvId = NULL;
158 }
159 LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
160 return rc;
161#endif
162}
163
164
165void USBProxyServiceDarwin::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
166{
167 AssertReturnVoid(aDevice->isWriteLockOnCurrentThread());
168#ifdef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
169 /*
170 * Remove the one-shot filter if necessary.
171 */
172 LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->getName().c_str(), aSuccess, aDevice->mOneShotId));
173 if (!aSuccess && aDevice->mOneShotId)
174 USBLibRemoveFilter(aDevice->mOneShotId);
175 aDevice->mOneShotId = NULL;
176#endif
177}
178
179
180int USBProxyServiceDarwin::releaseDevice(HostUSBDevice *aDevice)
181{
182 /*
183 * Check preconditions.
184 */
185 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
186 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
187
188 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
189 LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str()));
190
191 Assert(aDevice->getUnistate() == kHostUSBDeviceState_ReleasingToHost);
192
193#ifndef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
194 /*
195 * Fake it.
196 */
197 ASMAtomicWriteBool(&mFakeAsync, true);
198 devLock.release();
199 interruptWait();
200 return VINF_SUCCESS;
201
202#else
203 /*
204 * Create a one-shot ignore filter for the device
205 * and trigger a re-enumeration of it.
206 */
207 USBFILTER Filter;
208 USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_IGNORE);
209 initFilterFromDevice(&Filter, aDevice);
210 Log(("USBFILTERIDX_PORT=%#x\n", USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
211 Log(("USBFILTERIDX_BUS=%#x\n", USBFilterGetNum(&Filter, USBFILTERIDX_BUS)));
212
213 void *pvId = USBLibAddFilter(&Filter);
214 if (!pvId)
215 return VERR_GENERAL_FAILURE;
216
217 int rc = DarwinReEnumerateUSBDevice(aDevice->mUsb);
218 if (RT_SUCCESS(rc))
219 aDevice->mOneShotId = pvId;
220 else
221 {
222 USBLibRemoveFilter(pvId);
223 pvId = NULL;
224 }
225 LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
226 return rc;
227#endif
228}
229
230
231void USBProxyServiceDarwin::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
232{
233 AssertReturnVoid(aDevice->isWriteLockOnCurrentThread());
234#ifdef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
235 /*
236 * Remove the one-shot filter if necessary.
237 */
238 LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->getName().c_str(), aSuccess, aDevice->mOneShotId));
239 if (!aSuccess && aDevice->mOneShotId)
240 USBLibRemoveFilter(aDevice->mOneShotId);
241 aDevice->mOneShotId = NULL;
242#endif
243}
244
245
246/** @todo unused */
247void USBProxyServiceDarwin::detachingDevice(HostUSBDevice *aDevice)
248{
249#ifndef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
250 aDevice->setLogicalReconnect(HostUSBDevice::kDetachingPendingDetach);
251#else
252 NOREF(aDevice);
253#endif
254}
255
256
257bool USBProxyServiceDarwin::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
258{
259 AssertReturn(aDevice, false);
260 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
261#ifndef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
262 /* We're faking async state stuff. */
263 return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
264#else
265 /* Nothing special here so far, so fall back on parent */
266 return USBProxyService::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
267#endif
268}
269
270
271int USBProxyServiceDarwin::wait(RTMSINTERVAL aMillies)
272{
273#ifndef VBOX_WITH_NEW_USB_CODE_ON_DARWIN
274 if ( mFakeAsync
275 && ASMAtomicXchgBool(&mFakeAsync, false))
276 return VINF_SUCCESS;
277#endif
278
279 SInt32 rc = CFRunLoopRunInMode(CFSTR(VBOX_IOKIT_MODE_STRING),
280 mWaitABitNextTime && aMillies >= 1000
281 ? 1.0 /* seconds */
282 : aMillies >= 5000 /* Temporary measure to poll for status changes (MSD). */
283 ? 5.0 /* seconds */
284 : aMillies / 1000.0,
285 true);
286 mWaitABitNextTime = rc != kCFRunLoopRunTimedOut;
287
288 return VINF_SUCCESS;
289}
290
291
292int USBProxyServiceDarwin::interruptWait(void)
293{
294 if (mServiceRunLoopRef)
295 CFRunLoopStop(mServiceRunLoopRef);
296 return 0;
297}
298
299
300PUSBDEVICE USBProxyServiceDarwin::getDevices(void)
301{
302 /* call iokit.cpp */
303 return DarwinGetUSBDevices();
304}
305
306
307void USBProxyServiceDarwin::serviceThreadInit(void)
308{
309 mServiceRunLoopRef = CFRunLoopGetCurrent();
310 mNotifyOpaque = DarwinSubscribeUSBNotifications();
311}
312
313
314void USBProxyServiceDarwin::serviceThreadTerm(void)
315{
316 DarwinUnsubscribeUSBNotifications(mNotifyOpaque);
317 mServiceRunLoopRef = NULL;
318}
319
320
321/**
322 * Wrapper called from iokit.cpp.
323 *
324 * @param pCur The USB device to free.
325 */
326void DarwinFreeUSBDeviceFromIOKit(PUSBDEVICE pCur)
327{
328 USBProxyService::freeDevice(pCur);
329}
330
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