VirtualBox

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

Last change on this file since 2456 was 1, checked in by vboxsync, 55 years ago

import

  • 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 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
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
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
396int USBProxyService::captureDevice (HostUSBDevice *pDevice)
397{
398 return VERR_NOT_IMPLEMENTED;
399}
400
401
402int USBProxyService::holdDevice (HostUSBDevice *pDevice)
403{
404 return VERR_NOT_IMPLEMENTED;
405}
406
407
408int USBProxyService::releaseDevice (HostUSBDevice *pDevice)
409{
410 return VERR_NOT_IMPLEMENTED;
411}
412
413
414int USBProxyService::resetDevice (HostUSBDevice *pDevice)
415{
416 return VERR_NOT_IMPLEMENTED;
417}
418
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