VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/USBProxyService.cpp@ 8216

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

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implemenation of USBProxyService class
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include "USBProxyService.h"
24#include "Logging.h"
25
26#include <VBox/err.h>
27#include <iprt/asm.h>
28#include <iprt/semaphore.h>
29
30
31
32/** @todo add the required locking. */
33
34/**
35 * Initialize data members.
36 */
37USBProxyService::USBProxyService (HostUSB *aHost)
38 : mHost (aHost), mThread (NIL_RTTHREAD), mTerminate (false), mDevices (), mLastError (VINF_SUCCESS)
39{
40 LogFlowMember (("USBProxyService::USBProxyService: aHost=%p\n", aHost));
41}
42
43
44/**
45 * Empty destructor.
46 */
47USBProxyService::~USBProxyService()
48{
49 LogFlowMember (("USBProxyService::~USBProxyService: \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 LogFlow (("USBProxyService::start: started mThread=%RTthrd\n", mThread));
89 else
90 {
91 mThread = NIL_RTTHREAD;
92 mLastError = rc;
93 }
94 }
95 else
96 LogFlow (("USBProxyService::start: 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 LogFlowMember (("USBProxyService::stop: 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 LogFlowMember (("USBProxyService::stop: 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 LogFlowMember (("USBProxyService::processChanges: \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 * Compare previous list with the previous list of devices
202 * and merge in any changes while notifying Host.
203 */
204 HostUSBDeviceList::iterator It = this->mDevices.begin();
205 while ( It != mDevices.end()
206 || pDevices)
207 {
208 /*
209 * Compare.
210 */
211 HostUSBDevice *DevPtr = 0; /* shut up gcc */
212 int iDiff;
213 if (It == mDevices.end())
214 iDiff = 1;
215 else
216 {
217 DevPtr = *It;
218 if (!pDevices)
219 iDiff = -1;
220 else
221 iDiff = DevPtr->compare (pDevices);
222 }
223 if (!iDiff)
224 {
225 /*
226 * Device still there, update the state and move on.
227 */
228 if (DevPtr->updateState (pDevices))
229 mHost->onUSBDeviceStateChanged (DevPtr);
230 It++;
231 PUSBDEVICE pFree = pDevices;
232 pDevices = pDevices->pNext; /* treated as singly linked */
233 freeDevice (pFree);
234 /** @todo detect status changes! */
235 }
236 else
237 {
238 if (iDiff > 0)
239 {
240 /*
241 * Head of pDevices was attached.
242 */
243 PUSBDEVICE pNew = pDevices;
244 pDevices = pDevices->pNext;
245 pNew->pPrev = pNew->pNext = NULL;
246
247 HostUSBDevice *NewObj = new HostUSBDevice;
248 NewObj->init (pNew, this);
249 Log (("USBProxyService::processChanges: attached %p/%p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
250 NewObj, pNew, pNew->idVendor, pNew->idProduct,
251 pNew->pszProduct, pNew->pszManufacturer));
252
253 mDevices.insert (It, NewObj);
254 mHost->onUSBDeviceAttached (NewObj);
255 }
256 else
257 {
258 /*
259 * DevPtr was detached.
260 */
261 It = mDevices.erase (It);
262 mHost->onUSBDeviceDetached (DevPtr);
263 Log (("USBProxyService::processChanges: detached %p\n", (HostUSBDevice *)DevPtr)); /** @todo add details .*/
264 }
265 }
266 } /* while */
267 }
268 else
269 {
270 /* All devices were detached */
271 HostUSBDeviceList::iterator It = this->mDevices.begin();
272 while (It != mDevices.end())
273 {
274 HostUSBDevice *DevPtr = *It;
275 /*
276 * DevPtr was detached.
277 */
278 It = mDevices.erase (It);
279 mHost->onUSBDeviceDetached (DevPtr);
280 Log (("USBProxyService::processChanges: detached %p\n", (HostUSBDevice *)DevPtr)); /** @todo add details .*/
281 }
282 }
283
284 LogFlowMember (("USBProxyService::processChanges: returns void\n"));
285}
286
287
288/*static*/ DECLCALLBACK (int) USBProxyService::serviceThread (RTTHREAD Thread, void *pvUser)
289{
290 USBProxyService *pThis = (USBProxyService *)pvUser;
291 LogFlow (("USBProxyService::serviceThread: pThis=%p\n", pThis));
292
293 /*
294 * Processing loop.
295 */
296 for (;;)
297 {
298 pThis->wait (RT_INDEFINITE_WAIT);
299 if (pThis->mTerminate)
300 break;
301 pThis->processChanges();
302 }
303
304 LogFlow (("USBProxyService::serviceThread: returns VINF_SUCCESS\n"));
305 return VINF_SUCCESS;
306}
307
308/*static*/ void USBProxyService::freeInterfaceMembers (PUSBINTERFACE pIf, unsigned cIfs)
309{
310 while (cIfs-- > 0)
311 {
312 RTMemFree (pIf->paEndpoints);
313 pIf->paEndpoints = NULL;
314 RTStrFree ((char *)pIf->pszDriver);
315 pIf->pszDriver = NULL;
316 RTStrFree ((char *)pIf->pszInterface);
317 pIf->pszInterface = NULL;
318
319 freeInterfaceMembers(pIf->paAlts, pIf->cAlts);
320 RTMemFree(pIf->paAlts);
321 pIf->paAlts = NULL;
322 pIf->cAlts = 0;
323
324 /* next */
325 pIf++;
326 }
327}
328
329/*static*/ void USBProxyService::freeDevice (PUSBDEVICE pDevice)
330{
331 PUSBCONFIG pCfg = pDevice->paConfigurations;
332 unsigned cCfgs = pDevice->bNumConfigurations;
333 while (cCfgs-- > 0)
334 {
335 freeInterfaceMembers (pCfg->paInterfaces, pCfg->bNumInterfaces);
336 RTMemFree (pCfg->paInterfaces);
337 pCfg->paInterfaces = NULL;
338 pCfg->bNumInterfaces = 0;
339
340 RTStrFree ((char *)pCfg->pszConfiguration);
341 pCfg->pszConfiguration = NULL;
342
343 /* next */
344 pCfg++;
345 }
346 RTMemFree (pDevice->paConfigurations);
347 pDevice->paConfigurations = NULL;
348
349 RTStrFree ((char *)pDevice->pszManufacturer);
350 pDevice->pszManufacturer = NULL;
351 RTStrFree ((char *)pDevice->pszProduct);
352 pDevice->pszProduct = NULL;
353 RTStrFree ((char *)pDevice->pszSerialNumber);
354 pDevice->pszSerialNumber = NULL;
355
356 RTStrFree ((char *)pDevice->pszAddress);
357 pDevice->pszAddress = NULL;
358
359 RTMemFree (pDevice);
360
361}
362
363
364/* static */ uint64_t USBProxyService::calcSerialHash (const char *aSerial)
365{
366 if (!aSerial)
367 aSerial = "";
368
369 register const uint8_t *pu8 = (const uint8_t *)aSerial;
370 register uint64_t u64 = 14695981039346656037ULL;
371 for (;;)
372 {
373 register uint8_t u8 = *pu8;
374 if (!u8)
375 break;
376 u64 = (u64 * 1099511628211ULL) ^ u8;
377 pu8++;
378 }
379
380 return u64;
381}
382
383
384
385/* Stubs which the host specific classes overrides: */
386
387
388int USBProxyService::wait (unsigned aMillies)
389{
390 return RTThreadSleep (250);
391}
392
393
394int USBProxyService::interruptWait (void)
395{
396 return VERR_NOT_IMPLEMENTED;
397}
398
399
400PUSBDEVICE USBProxyService::getDevices (void)
401{
402 return NULL;
403}
404
405
406int USBProxyService::captureDevice (HostUSBDevice *pDevice)
407{
408 return VERR_NOT_IMPLEMENTED;
409}
410
411
412int USBProxyService::holdDevice (HostUSBDevice *pDevice)
413{
414 return VERR_NOT_IMPLEMENTED;
415}
416
417
418int USBProxyService::releaseDevice (HostUSBDevice *pDevice)
419{
420 return VERR_NOT_IMPLEMENTED;
421}
422
423
424int USBProxyService::resetDevice (HostUSBDevice *pDevice)
425{
426 return VERR_NOT_IMPLEMENTED;
427}
428
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