VirtualBox

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

Last change on this file since 2705 was 2587, checked in by vboxsync, 18 years ago

Darwin USB (work in progress)...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1/** @file
2 * VirtualBox USB Proxy Service (base) class.
3 */
4
5/*
6 * Copyright (C) 2006 InnoTek Systemberatung GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License as published by the Free Software Foundation,
12 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13 * distribution. VirtualBox OSE is distributed in the hope that it will
14 * be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * If you received this file as part of a commercial VirtualBox
17 * distribution, then only the terms of your commercial VirtualBox
18 * license agreement apply instead of the previous paragraph.
19 */
20
21#include "USBProxyService.h"
22#include "Logging.h"
23
24#include <VBox/err.h>
25#include <iprt/asm.h>
26#include <iprt/semaphore.h>
27
28
29
30/** @todo add the required locking. */
31
32/**
33 * Initialize data members.
34 */
35USBProxyService::USBProxyService (Host *aHost)
36 : mHost (aHost), mThread (NIL_RTTHREAD), mTerminate (false), mDevices (), mLastError (VINF_SUCCESS)
37{
38 LogFlowMember (("USBProxyService::USBProxyService: aHost=%p\n", aHost));
39}
40
41
42/**
43 * Empty destructor.
44 */
45USBProxyService::~USBProxyService()
46{
47 LogFlowMember (("USBProxyService::~USBProxyService: \n"));
48 Assert (mThread == NIL_RTTHREAD);
49 mDevices.clear();
50 mTerminate = true;
51 mHost = NULL;
52}
53
54
55bool USBProxyService::isActive (void)
56{
57 return mThread != NIL_RTTHREAD;
58}
59
60
61int USBProxyService::getLastError (void)
62{
63 return mLastError;
64}
65
66
67int USBProxyService::start (void)
68{
69 int rc = VINF_SUCCESS;
70 if (mThread == NIL_RTTHREAD)
71 {
72 /*
73 * Force update before starting the poller thread.
74 */
75 wait (0);
76 processChanges ();
77
78 /*
79 * Create the poller thread which will look for changes.
80 */
81 mTerminate = false;
82 rc = RTThreadCreate (&mThread, USBProxyService::serviceThread, this,
83 0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "USBPROXY");
84 AssertRC (rc);
85 if (VBOX_SUCCESS (rc))
86 LogFlow (("USBProxyService::start: started mThread=%RTthrd\n", mThread));
87 else
88 {
89 mThread = NIL_RTTHREAD;
90 mLastError = rc;
91 }
92 }
93 else
94 LogFlow (("USBProxyService::start: already running, mThread=%RTthrd\n", mThread));
95 return rc;
96}
97
98
99int USBProxyService::stop (void)
100{
101 int rc = VINF_SUCCESS;
102 if (mThread != NIL_RTTHREAD)
103 {
104 /*
105 * Mark the thread for termination and kick it.
106 */
107 ASMAtomicXchgSize (&mTerminate, true);
108 rc = interruptWait();
109 AssertRC (rc);
110
111 /*
112 * Wait for the thread to finish and then update the state.
113 */
114 rc = RTThreadWait (mThread, 60000, NULL);
115 if (rc == VERR_INVALID_HANDLE)
116 rc = VINF_SUCCESS;
117 if (VBOX_SUCCESS (rc))
118 {
119 LogFlowMember (("USBProxyService::stop: stopped mThread=%RTthrd\n", mThread));
120 mThread = NIL_RTTHREAD;
121 mTerminate = false;
122 }
123 else
124 {
125 AssertRC (rc);
126 mLastError = rc;
127 }
128 }
129 else
130 LogFlowMember (("USBProxyService::stop: not active\n"));
131
132 return rc;
133}
134
135
136/**
137 * Sort a list of USB devices.
138 *
139 * @returns Pointer to the head of the sorted doubly linked list.
140 * @param aDevices Head pointer (can be both singly and doubly linked list).
141 */
142static PUSBDEVICE sortDevices (PUSBDEVICE pDevices)
143{
144 PUSBDEVICE pHead = NULL;
145 PUSBDEVICE pTail = NULL;
146 while (pDevices)
147 {
148 /* unlink head */
149 PUSBDEVICE pDev = pDevices;
150 pDevices = pDev->pNext;
151 if (pDevices)
152 pDevices->pPrev = NULL;
153
154 /* find location. */
155 PUSBDEVICE pCur = pTail;
156 while ( pCur
157 && HostUSBDevice::compare (pCur, pDev) > 0)
158 pCur = pCur->pPrev;
159
160 /* insert (after pCur) */
161 pDev->pPrev = pCur;
162 if (pCur)
163 {
164 pDev->pNext = pCur->pNext;
165 pCur->pNext = pDev;
166 if (pDev->pNext)
167 pDev->pNext->pPrev = pDev;
168 else
169 pTail = pDev;
170 }
171 else
172 {
173 pDev->pNext = pHead;
174 if (pHead)
175 pHead->pPrev = pDev;
176 else
177 pTail = pDev;
178 pHead = pDev;
179 }
180 }
181
182 return pHead;
183}
184
185
186void USBProxyService::processChanges (void)
187{
188 LogFlowMember (("USBProxyService::processChanges: \n"));
189
190 /*
191 * Get the sorted list of USB devices.
192 */
193 PUSBDEVICE pDevices = getDevices();
194 if (pDevices)
195 {
196 pDevices = sortDevices (pDevices);
197
198 /*
199 * Compare previous list with the previous list of devices
200 * and merge in any changes while notifying Host.
201 */
202 HostUSBDeviceList::iterator It = this->mDevices.begin();
203 while ( It != mDevices.end()
204 || pDevices)
205 {
206 /*
207 * Compare.
208 */
209 ComObjPtr <HostUSBDevice> DevPtr;
210 int iDiff;
211 if (It == mDevices.end())
212 iDiff = 1;
213 else
214 {
215 DevPtr = *It;
216 if (!pDevices)
217 iDiff = -1;
218 else
219 iDiff = DevPtr->compare (pDevices);
220 }
221 if (!iDiff)
222 {
223 /*
224 * Device still there, update the state and move on.
225 */
226 if (DevPtr->updateState (pDevices))
227 mHost->onUSBDeviceStateChanged (DevPtr);
228 It++;
229 PUSBDEVICE pFree = pDevices;
230 pDevices = pDevices->pNext; /* treated as singly linked */
231 freeDevice (pFree);
232 /** @todo detect status changes! */
233 }
234 else
235 {
236 if (iDiff > 0)
237 {
238 /*
239 * Head of pDevices was attached.
240 */
241 PUSBDEVICE pNew = pDevices;
242 pDevices = pDevices->pNext;
243 pNew->pPrev = pNew->pNext = NULL;
244
245 ComObjPtr <HostUSBDevice> NewObj;
246 NewObj.createObject();
247 NewObj->init (pNew, this);
248 Log (("USBProxyService::processChanges: attached %p/%p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
249 (HostUSBDevice *)NewObj, pNew, pNew->idVendor, pNew->idProduct, pNew->pszProduct, pNew->pszManufacturer));
250
251 mDevices.insert (It, NewObj);
252 mHost->onUSBDeviceAttached (NewObj);
253 }
254 else
255 {
256 /*
257 * DevPtr was detached.
258 */
259 It = mDevices.erase (It);
260 mHost->onUSBDeviceDetached (DevPtr);
261 Log (("USBProxyService::processChanges: detached %p\n", (HostUSBDevice *)DevPtr)); /** @todo add details .*/
262 }
263 }
264 } /* while */
265 }
266 else
267 {
268 /* All devices were detached */
269 HostUSBDeviceList::iterator It = this->mDevices.begin();
270 while (It != mDevices.end())
271 {
272 ComObjPtr <HostUSBDevice> DevPtr = *It;
273 /*
274 * DevPtr was detached.
275 */
276 It = mDevices.erase (It);
277 mHost->onUSBDeviceDetached (DevPtr);
278 Log (("USBProxyService::processChanges: detached %p\n", (HostUSBDevice *)DevPtr)); /** @todo add details .*/
279 }
280 }
281
282 LogFlowMember (("USBProxyService::processChanges: returns void\n"));
283}
284
285
286/*static*/ DECLCALLBACK (int) USBProxyService::serviceThread (RTTHREAD Thread, void *pvUser)
287{
288 USBProxyService *pThis = (USBProxyService *)pvUser;
289 LogFlow (("USBProxyService::serviceThread: pThis=%p\n", pThis));
290 pThis->serviceThreadInit();
291
292 /*
293 * Processing loop.
294 */
295 for (;;)
296 {
297 pThis->wait (RT_INDEFINITE_WAIT);
298 if (pThis->mTerminate)
299 break;
300 pThis->processChanges();
301 }
302
303 pThis->serviceThreadTerm();
304 LogFlow (("USBProxyService::serviceThread: returns VINF_SUCCESS\n"));
305 return VINF_SUCCESS;
306}
307
308
309/*static*/ void USBProxyService::freeDevice (PUSBDEVICE pDevice)
310{
311 PUSBCONFIG pCfg = pDevice->paConfigurations;
312 unsigned cCfgs = pDevice->bNumConfigurations;
313 while (cCfgs-- > 0)
314 {
315 PUSBINTERFACE pIf = pCfg->paInterfaces;
316 unsigned cIfs = pCfg->bNumInterfaces;
317 while (cIfs-- > 0)
318 {
319 RTMemFree (pIf->paEndpoints);
320 pIf->paEndpoints = NULL;
321 RTStrFree ((char *)pIf->pszDriver);
322 pIf->pszDriver = NULL;
323 RTStrFree ((char *)pIf->pszInterface);
324 pIf->pszInterface = NULL;
325 /* next */
326 pIf++;
327 }
328 RTMemFree (pCfg->paInterfaces);
329 pCfg->paInterfaces = NULL;
330 RTStrFree ((char *)pCfg->pszConfiguration);
331 pCfg->pszConfiguration = NULL;
332
333 /* next */
334 pCfg++;
335 }
336 RTMemFree (pDevice->paConfigurations);
337 pDevice->paConfigurations = NULL;
338
339 RTStrFree ((char *)pDevice->pszManufacturer);
340 pDevice->pszManufacturer = NULL;
341 RTStrFree ((char *)pDevice->pszProduct);
342 pDevice->pszProduct = NULL;
343 RTStrFree ((char *)pDevice->pszSerialNumber);
344 pDevice->pszSerialNumber = NULL;
345
346 RTStrFree ((char *)pDevice->pszAddress);
347 pDevice->pszAddress = NULL;
348
349 RTMemFree (pDevice);
350
351}
352
353
354/* static */ uint64_t USBProxyService::calcSerialHash (const char *aSerial)
355{
356 if (!aSerial)
357 aSerial = "";
358
359 register const uint8_t *pu8 = (const uint8_t *)aSerial;
360 register uint64_t u64 = 14695981039346656037ULL;
361 for (;;)
362 {
363 register uint8_t u8 = *pu8;
364 if (!u8)
365 break;
366 u64 = (u64 * 1099511628211ULL) ^ u8;
367 pu8++;
368 }
369
370 return u64;
371}
372
373
374
375/* Stubs which the host specific classes overrides: */
376
377
378int USBProxyService::wait (unsigned aMillies)
379{
380 return RTThreadSleep (250);
381}
382
383
384int USBProxyService::interruptWait (void)
385{
386 return VERR_NOT_IMPLEMENTED;
387}
388
389
390PUSBDEVICE USBProxyService::getDevices (void)
391{
392 return NULL;
393}
394
395
396void USBProxyService::serviceThreadInit (void)
397{
398}
399
400
401void USBProxyService::serviceThreadTerm (void)
402{
403}
404
405
406/**
407 * The default implementation returns non-NULL to emulate successful insertions
408 * for those subclasses that don't reimplement this method.
409 */
410void *USBProxyService::insertFilter (IUSBDeviceFilter * /* aFilter */)
411{
412 // return non-NULL to prevent failed assertions in Main
413 return (void *) 1;
414}
415
416
417void USBProxyService::removeFilter (void * /* aID */)
418{
419}
420
421
422int USBProxyService::captureDevice (HostUSBDevice *pDevice)
423{
424 return VERR_NOT_IMPLEMENTED;
425}
426
427
428int USBProxyService::holdDevice (HostUSBDevice *pDevice)
429{
430 return VERR_NOT_IMPLEMENTED;
431}
432
433
434int USBProxyService::releaseDevice (HostUSBDevice *pDevice)
435{
436 return VERR_NOT_IMPLEMENTED;
437}
438
439
440int USBProxyService::resetDevice (HostUSBDevice *pDevice)
441{
442 return VERR_NOT_IMPLEMENTED;
443}
444
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