VirtualBox

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

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

Main: Fixed memory errors and leaks found by valgrind.

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