VirtualBox

source: vbox/trunk/src/VBox/Main/USBProxyService.cpp@ 7964

Last change on this file since 7964 was 7964, checked in by vboxsync, 17 years ago

Attempt at making OSE build again.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/* $Id: USBProxyService.cpp 7964 2008-04-14 17:56:52Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service (base) class.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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#include "USBProxyService.h"
19#include "HostUSBDeviceImpl.h"
20#include "Logging.h"
21#include "HostImpl.h"
22
23#include <VBox/err.h>
24#include <iprt/asm.h>
25#include <iprt/semaphore.h>
26#include <iprt/thread.h>
27#include <iprt/mem.h>
28#include <iprt/string.h>
29
30
31
32/** @todo add the required locking. */
33
34/**
35 * Initialize data members.
36 */
37USBProxyService::USBProxyService (Host *aHost)
38 : mHost (aHost), mThread (NIL_RTTHREAD), mTerminate (false), mLastError (VINF_SUCCESS), mDevices ()
39{
40 LogFlowThisFunc (("aHost=%p\n", aHost));
41}
42
43
44/**
45 * Empty destructor.
46 */
47USBProxyService::~USBProxyService()
48{
49 LogFlowThisFunc (("\n"));
50 Assert (mThread == NIL_RTTHREAD);
51 mDevices.clear();
52 mTerminate = true;
53 mHost = NULL;
54}
55
56
57bool USBProxyService::isActive (void)
58{
59 return mThread != NIL_RTTHREAD;
60}
61
62
63int USBProxyService::getLastError (void)
64{
65 return mLastError;
66}
67
68
69int USBProxyService::start (void)
70{
71 int rc = VINF_SUCCESS;
72 if (mThread == NIL_RTTHREAD)
73 {
74 /*
75 * Force update before starting the poller thread.
76 */
77 wait (0);
78 processChanges ();
79
80 /*
81 * Create the poller thread which will look for changes.
82 */
83 mTerminate = false;
84 rc = RTThreadCreate (&mThread, USBProxyService::serviceThread, this,
85 0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "USBPROXY");
86 AssertRC (rc);
87 if (VBOX_SUCCESS (rc))
88 LogFlowThisFunc (("started mThread=%RTthrd\n", mThread));
89 else
90 {
91 mThread = NIL_RTTHREAD;
92 mLastError = rc;
93 }
94 }
95 else
96 LogFlowThisFunc (("already running, mThread=%RTthrd\n", mThread));
97 return rc;
98}
99
100
101int USBProxyService::stop (void)
102{
103 int rc = VINF_SUCCESS;
104 if (mThread != NIL_RTTHREAD)
105 {
106 /*
107 * Mark the thread for termination and kick it.
108 */
109 ASMAtomicXchgSize (&mTerminate, true);
110 rc = interruptWait();
111 AssertRC (rc);
112
113 /*
114 * Wait for the thread to finish and then update the state.
115 */
116 rc = RTThreadWait (mThread, 60000, NULL);
117 if (rc == VERR_INVALID_HANDLE)
118 rc = VINF_SUCCESS;
119 if (VBOX_SUCCESS (rc))
120 {
121 LogFlowThisFunc (("stopped mThread=%RTthrd\n", mThread));
122 mThread = NIL_RTTHREAD;
123 mTerminate = false;
124 }
125 else
126 {
127 AssertRC (rc);
128 mLastError = rc;
129 }
130 }
131 else
132 LogFlowThisFunc (("not active\n"));
133
134 return rc;
135}
136
137
138/**
139 * Sort a list of USB devices.
140 *
141 * @returns Pointer to the head of the sorted doubly linked list.
142 * @param aDevices Head pointer (can be both singly and doubly linked list).
143 */
144static PUSBDEVICE sortDevices (PUSBDEVICE pDevices)
145{
146 PUSBDEVICE pHead = NULL;
147 PUSBDEVICE pTail = NULL;
148 while (pDevices)
149 {
150 /* unlink head */
151 PUSBDEVICE pDev = pDevices;
152 pDevices = pDev->pNext;
153 if (pDevices)
154 pDevices->pPrev = NULL;
155
156 /* find location. */
157 PUSBDEVICE pCur = pTail;
158 while ( pCur
159 && HostUSBDevice::compare (pCur, pDev) > 0)
160 pCur = pCur->pPrev;
161
162 /* insert (after pCur) */
163 pDev->pPrev = pCur;
164 if (pCur)
165 {
166 pDev->pNext = pCur->pNext;
167 pCur->pNext = pDev;
168 if (pDev->pNext)
169 pDev->pNext->pPrev = pDev;
170 else
171 pTail = pDev;
172 }
173 else
174 {
175 pDev->pNext = pHead;
176 if (pHead)
177 pHead->pPrev = pDev;
178 else
179 pTail = pDev;
180 pHead = pDev;
181 }
182 }
183
184 return pHead;
185}
186
187
188void USBProxyService::processChanges (void)
189{
190 LogFlowThisFunc (("\n"));
191
192 /*
193 * Get the sorted list of USB devices.
194 */
195 PUSBDEVICE pDevices = getDevices();
196 if (pDevices)
197 {
198 pDevices = sortDevices (pDevices);
199
200 /*
201 * We need to lock the host object for writing because
202 * a) the subsequent code may call Host methods that require a write
203 * lock
204 * b) we will lock HostUSBDevice objects below and want to make sure
205 * the lock order is always the same (Host, HostUSBDevice, as
206 * expected by Host) to avoid cross-deadlocks
207 */
208 AutoLock hostLock (mHost);
209
210 /*
211 * Compare previous list with the previous list of devices
212 * and merge in any changes while notifying Host.
213 */
214 HostUSBDeviceList::iterator It = this->mDevices.begin();
215 while ( It != mDevices.end()
216 || pDevices)
217 {
218 ComObjPtr <HostUSBDevice> DevPtr;
219
220 if (It != mDevices.end())
221 DevPtr = *It;
222
223 /*
224 * Assert that the object is still alive (we still reference it in
225 * the collection and we're the only one who calls uninit() on it
226 */
227 HostUSBDevice::AutoCaller devCaller (DevPtr.isNull() ? NULL : DevPtr);
228 AssertComRC (devCaller.rc());
229
230 /*
231 * Lock the device object since we will read/write it's
232 * properties. All Host callbacks also imply the object is locked.
233 */
234 AutoLock devLock (DevPtr.isNull() ? NULL : DevPtr);
235
236 /*
237 * Compare.
238 */
239 int iDiff;
240 if (DevPtr.isNull())
241 iDiff = 1;
242 else
243 {
244 if (!pDevices)
245 iDiff = -1;
246 else
247 iDiff = DevPtr->compare (pDevices);
248 }
249 if (!iDiff)
250 {
251 /*
252 * The device still there, update the state and move on. The PUSBDEVICE
253 * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
254 */
255 PUSBDEVICE pCur = pDevices;
256 pDevices = pDevices->pNext;
257 pCur->pPrev = pCur->pNext = NULL;
258
259 if (updateDeviceState (DevPtr, pCur))
260 {
261 Log (("USBProxyService::processChanges: state change %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"} state=%d%s\n",
262 (HostUSBDevice *)DevPtr, pCur->idVendor, pCur->idProduct, pCur->pszProduct, pCur->pszManufacturer, DevPtr->state(), DevPtr->isStatePending() ? " (pending async op)" : ""));
263 mHost->onUSBDeviceStateChanged (DevPtr);
264 }
265 It++;
266 }
267 else
268 {
269 if (iDiff > 0)
270 {
271 /*
272 * Head of pDevices was attached.
273 */
274 PUSBDEVICE pNew = pDevices;
275 pDevices = pDevices->pNext;
276 pNew->pPrev = pNew->pNext = NULL;
277
278 ComObjPtr <HostUSBDevice> NewObj;
279 NewObj.createObject();
280 NewObj->init (pNew, this);
281 Log (("USBProxyService::processChanges: attached %p/%p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
282 (HostUSBDevice *)NewObj, pNew, pNew->idVendor, pNew->idProduct, pNew->pszProduct, pNew->pszManufacturer));
283 deviceAdded (NewObj, pNew);
284
285 /* Not really necessary to lock here, but make Assert checks happy. */
286 AutoLock newDevLock (NewObj);
287
288 mDevices.insert (It, NewObj);
289 mHost->onUSBDeviceAttached (NewObj);
290 }
291 else
292 {
293 /*
294 * DevPtr was detached, unless there is a pending async request.
295 * Check if the async request timed out before making a decision.
296 */
297 if (DevPtr->isStatePending())
298 DevPtr->checkForAsyncTimeout();
299 if (DevPtr->isStatePending())
300 {
301 if (DevPtr->pendingStateEx() == HostUSBDevice::kDetachingPendingDetach)
302 DevPtr->setLogicalReconnect (HostUSBDevice::kDetachingPendingAttach);
303 else if (DevPtr->pendingStateEx() == HostUSBDevice::kDetachingPendingDetachFilters)
304 DevPtr->setLogicalReconnect (HostUSBDevice::kDetachingPendingAttachFilters);
305 It++;
306 Log (("USBProxyService::processChanges: detached but pending %d/%d %p\n",
307 DevPtr->pendingState(), DevPtr->pendingStateEx(), (HostUSBDevice *)DevPtr));
308 }
309 else
310 {
311 It = mDevices.erase (It);
312 deviceRemoved (DevPtr);
313 mHost->onUSBDeviceDetached (DevPtr);
314 Log (("USBProxyService::processChanges: detached %p\n",
315 (HostUSBDevice *)DevPtr)); /** @todo add details .*/
316
317 /* from now on, the object is no more valid,
318 * uninitialize to avoid abuse */
319 devCaller.release();
320 DevPtr->uninit();
321 }
322 }
323 }
324 } /* while */
325 }
326 else
327 {
328 /* we need to lock the host object for writing because
329 * a) the subsequent code may call Host methods that require a write
330 * lock
331 * b) we will lock HostUSBDevice objects below and want to make sure
332 * the lock order is always the same (Host, HostUSBDevice, as
333 * expected by Host) to avoid cross-deadlocks */
334
335 AutoLock hostLock (mHost);
336
337 /* All devices were detached */
338 HostUSBDeviceList::iterator It = this->mDevices.begin();
339 while (It != mDevices.end())
340 {
341 ComObjPtr <HostUSBDevice> DevPtr = *It;
342
343 /* assert that the object is still alive (we still reference it in
344 * the collection and we're the only one who calls uninit() on it */
345 HostUSBDevice::AutoCaller devCaller (DevPtr);
346 AssertComRC (devCaller.rc());
347
348 AutoLock devLock (DevPtr);
349
350 /*
351 * DevPtr was detached.
352 */
353 It = mDevices.erase (It);
354 mHost->onUSBDeviceDetached (DevPtr);
355 Log (("USBProxyService::processChanges: detached %p\n",
356 (HostUSBDevice *)DevPtr)); /** @todo add details .*/
357
358 /* from now on, the object is no more valid,
359 * uninitialize to avoid abuse */
360 devCaller.release();
361 DevPtr->uninit();
362 }
363 }
364
365 LogFlowThisFunc (("returns void\n"));
366}
367
368
369/*static*/ DECLCALLBACK (int) USBProxyService::serviceThread (RTTHREAD Thread, void *pvUser)
370{
371 USBProxyService *pThis = (USBProxyService *)pvUser;
372 LogFlowFunc (("pThis=%p\n", pThis));
373 pThis->serviceThreadInit();
374
375 /*
376 * Processing loop.
377 */
378 for (;;)
379 {
380 pThis->wait (RT_INDEFINITE_WAIT);
381 if (pThis->mTerminate)
382 break;
383 pThis->processChanges();
384 }
385
386 pThis->serviceThreadTerm();
387 LogFlowFunc (("returns VINF_SUCCESS\n"));
388 return VINF_SUCCESS;
389}
390
391
392/*static*/ void USBProxyService::freeInterfaceMembers (PUSBINTERFACE pIf, unsigned cIfs)
393{
394 while (cIfs-- > 0)
395 {
396 RTMemFree (pIf->paEndpoints);
397 pIf->paEndpoints = NULL;
398 RTStrFree ((char *)pIf->pszDriver);
399 pIf->pszDriver = NULL;
400 RTStrFree ((char *)pIf->pszInterface);
401 pIf->pszInterface = NULL;
402
403 freeInterfaceMembers(pIf->paAlts, pIf->cAlts);
404 RTMemFree(pIf->paAlts);
405 pIf->paAlts = NULL;
406 pIf->cAlts = 0;
407
408 /* next */
409 pIf++;
410 }
411}
412
413/*static*/ void USBProxyService::freeDeviceMembers (PUSBDEVICE pDevice)
414{
415 PUSBCONFIG pCfg = pDevice->paConfigurations;
416 unsigned cCfgs = pDevice->bNumConfigurations;
417 while (cCfgs-- > 0)
418 {
419 freeInterfaceMembers (pCfg->paInterfaces, pCfg->bNumInterfaces);
420 RTMemFree (pCfg->paInterfaces);
421 pCfg->paInterfaces = NULL;
422 pCfg->bNumInterfaces = 0;
423
424 RTStrFree ((char *)pCfg->pszConfiguration);
425 pCfg->pszConfiguration = NULL;
426
427 /* next */
428 pCfg++;
429 }
430 RTMemFree (pDevice->paConfigurations);
431 pDevice->paConfigurations = NULL;
432
433 RTStrFree ((char *)pDevice->pszManufacturer);
434 pDevice->pszManufacturer = NULL;
435 RTStrFree ((char *)pDevice->pszProduct);
436 pDevice->pszProduct = NULL;
437 RTStrFree ((char *)pDevice->pszSerialNumber);
438 pDevice->pszSerialNumber = NULL;
439
440 RTStrFree ((char *)pDevice->pszAddress);
441 pDevice->pszAddress = NULL;
442}
443
444/*static*/ void USBProxyService::freeDevice (PUSBDEVICE pDevice)
445{
446 freeDeviceMembers (pDevice);
447 RTMemFree (pDevice);
448}
449
450
451/* static */ uint64_t USBProxyService::calcSerialHash (const char *aSerial)
452{
453 if (!aSerial)
454 aSerial = "";
455
456 register const uint8_t *pu8 = (const uint8_t *)aSerial;
457 register uint64_t u64 = 14695981039346656037ULL;
458 for (;;)
459 {
460 register uint8_t u8 = *pu8;
461 if (!u8)
462 break;
463 u64 = (u64 * 1099511628211ULL) ^ u8;
464 pu8++;
465 }
466
467 return u64;
468}
469
470
471/*static*/ void USBProxyService::initFilterFromDevice (PUSBFILTER aFilter, HostUSBDevice *aDevice)
472{
473 PCUSBDEVICE pDev = aDevice->mUsb;
474 int vrc;
475
476 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_VENDOR_ID, pDev->idVendor, true); AssertRC(vrc);
477 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_PRODUCT_ID, pDev->idProduct, true); AssertRC(vrc);
478 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_DEVICE_REV, pDev->bcdDevice, true); AssertRC(vrc);
479 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_DEVICE_CLASS, pDev->bDeviceClass, true); AssertRC(vrc);
480 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_DEVICE_SUB_CLASS, pDev->bDeviceSubClass, true); AssertRC(vrc);
481 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_DEVICE_PROTOCOL, pDev->bDeviceProtocol, true); AssertRC(vrc);
482 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_PORT, pDev->bPort, true); AssertRC(vrc);
483 vrc = USBFilterSetNumExact (aFilter, USBFILTERIDX_BUS, pDev->bBus, false); AssertRC(vrc); /* not available on darwin yet... */
484 if (pDev->pszSerialNumber)
485 {
486 vrc = USBFilterSetStringExact (aFilter, USBFILTERIDX_SERIAL_NUMBER_STR, pDev->pszSerialNumber, true);
487 AssertRC (vrc);
488 }
489 if (pDev->pszProduct)
490 {
491 vrc = USBFilterSetStringExact (aFilter, USBFILTERIDX_PRODUCT_STR, pDev->pszProduct, true);
492 AssertRC (vrc);
493 }
494 if (pDev->pszManufacturer)
495 {
496 vrc = USBFilterSetStringExact (aFilter, USBFILTERIDX_MANUFACTURER_STR, pDev->pszManufacturer, true);
497 AssertRC (vrc);
498 }
499}
500
501
502bool USBProxyService::updateDeviceStateFake (HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice)
503{
504 AssertReturn (aDevice, false);
505 AssertReturn (aDevice->isLockedOnCurrentThread(), false);
506
507 if (aDevice->isStatePending())
508 {
509 switch (aDevice->pendingStateEx())
510 {
511 case HostUSBDevice::kNothingPending:
512 switch (aDevice->pendingState())
513 {
514 /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used anywhere in the proxy code; it's
515 * quite logical because the proxy doesn't know anything about guest VMs. We use HELD_BY_PROXY
516 * instead -- it is sufficient and is what Main expects. */
517 case USBDeviceState_Captured: aUSBDevice->enmState = USBDEVICESTATE_HELD_BY_PROXY; break;
518 case USBDeviceState_Held: aUSBDevice->enmState = USBDEVICESTATE_HELD_BY_PROXY; break;
519 case USBDeviceState_Available: aUSBDevice->enmState = USBDEVICESTATE_UNUSED; break;
520 case USBDeviceState_Unavailable: aUSBDevice->enmState = USBDEVICESTATE_USED_BY_HOST; break;
521 case USBDeviceState_Busy: aUSBDevice->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE; break;
522 default:
523 AssertMsgFailed(("%d\n", aDevice->pendingState()));
524 break;
525 }
526 break;
527
528 /* don't call updateDeviceState until it's reattached. */
529 case HostUSBDevice::kDetachingPendingDetach:
530 case HostUSBDevice::kDetachingPendingDetachFilters:
531 freeDevice(aUSBDevice);
532 return false;
533
534 /* Let updateDeviceState / HostUSBDevice::updateState deal with this. */
535 case HostUSBDevice::kDetachingPendingAttach:
536 case HostUSBDevice::kDetachingPendingAttachFilters:
537 break;
538
539 default:
540 AssertMsgFailed(("%d\n", aDevice->pendingStateEx()));
541 break;
542 }
543 }
544
545 return USBProxyService::updateDeviceState (aDevice, aUSBDevice);
546}
547
548
549
550/* Stubs which the host specific classes overrides: */
551
552
553int USBProxyService::wait (unsigned aMillies)
554{
555 return RTThreadSleep (250);
556}
557
558
559int USBProxyService::interruptWait (void)
560{
561 return VERR_NOT_IMPLEMENTED;
562}
563
564
565PUSBDEVICE USBProxyService::getDevices (void)
566{
567 return NULL;
568}
569
570
571void USBProxyService::serviceThreadInit (void)
572{
573}
574
575
576void USBProxyService::serviceThreadTerm (void)
577{
578}
579
580
581/**
582 * The default implementation returns non-NULL to emulate successful insertions
583 * for those subclasses that don't reimplement this method.
584 */
585void *USBProxyService::insertFilter (PCUSBFILTER /* aFilter */)
586{
587 // return non-NULL to prevent failed assertions in Main
588 return (void *) 1;
589}
590
591
592void USBProxyService::removeFilter (void * /* aId */)
593{
594}
595
596
597int USBProxyService::captureDevice (HostUSBDevice * /* aDevice */)
598{
599 return VERR_NOT_IMPLEMENTED;
600}
601
602
603void USBProxyService::detachingDevice (HostUSBDevice * /* aDevice */)
604{
605}
606
607
608int USBProxyService::releaseDevice (HostUSBDevice * /* aDevice */)
609{
610 return VERR_NOT_IMPLEMENTED;
611}
612
613
614bool USBProxyService::updateDeviceState (HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice)
615{
616 AssertReturn (aDevice, false);
617 AssertReturn (aDevice->isLockedOnCurrentThread(), false);
618
619 bool fRc = aDevice->updateState (aUSBDevice);
620 /* A little hack to work around state quirks wrt detach/reattach. */
621 if ( !fRc
622 && aDevice->isStatePending()
623 && ( aDevice->pendingStateEx() == HostUSBDevice::kDetachingPendingAttach
624 || aDevice->pendingStateEx() == HostUSBDevice::kDetachingPendingAttachFilters))
625 fRc = true;
626 return fRc;
627}
628
629
630void USBProxyService::deviceAdded (HostUSBDevice * /* aDevice */, PUSBDEVICE /* aUSBDevice */)
631{
632}
633
634
635void USBProxyService::deviceRemoved (HostUSBDevice * /* aDevice */)
636{
637}
638
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