VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 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
305/*static*/ void USBProxyService::freeDevice (PUSBDEVICE pDevice)
306{
307 PUSBCONFIG pCfg = pDevice->paConfigurations;
308 unsigned cCfgs = pDevice->bNumConfigurations;
309 while (cCfgs-- > 0)
310 {
311 PUSBINTERFACE pIf = pCfg->paInterfaces;
312 unsigned cIfs = pCfg->bNumInterfaces;
313 while (cIfs-- > 0)
314 {
315 RTMemFree (pIf->paEndpoints);
316 pIf->paEndpoints = NULL;
317 RTStrFree ((char *)pIf->pszDriver);
318 pIf->pszDriver = NULL;
319 RTStrFree ((char *)pIf->pszInterface);
320 pIf->pszInterface = NULL;
321 /* next */
322 pIf++;
323 }
324 RTMemFree (pCfg->paInterfaces);
325 pCfg->paInterfaces = NULL;
326 RTStrFree ((char *)pCfg->pszConfiguration);
327 pCfg->pszConfiguration = NULL;
328
329 /* next */
330 pCfg++;
331 }
332 RTMemFree (pDevice->paConfigurations);
333 pDevice->paConfigurations = NULL;
334
335 RTStrFree ((char *)pDevice->pszManufacturer);
336 pDevice->pszManufacturer = NULL;
337 RTStrFree ((char *)pDevice->pszProduct);
338 pDevice->pszProduct = NULL;
339 RTStrFree ((char *)pDevice->pszSerialNumber);
340 pDevice->pszSerialNumber = NULL;
341
342 RTStrFree ((char *)pDevice->pszAddress);
343 pDevice->pszAddress = NULL;
344
345 RTMemFree (pDevice);
346
347}
348
349
350/* static */ uint64_t USBProxyService::calcSerialHash (const char *aSerial)
351{
352 if (!aSerial)
353 aSerial = "";
354
355 register const uint8_t *pu8 = (const uint8_t *)aSerial;
356 register uint64_t u64 = 14695981039346656037ULL;
357 for (;;)
358 {
359 register uint8_t u8 = *pu8;
360 if (!u8)
361 break;
362 u64 = (u64 * 1099511628211ULL) ^ u8;
363 pu8++;
364 }
365
366 return u64;
367}
368
369
370
371/* Stubs which the host specific classes overrides: */
372
373
374int USBProxyService::wait (unsigned aMillies)
375{
376 return RTThreadSleep (250);
377}
378
379
380int USBProxyService::interruptWait (void)
381{
382 return VERR_NOT_IMPLEMENTED;
383}
384
385
386PUSBDEVICE USBProxyService::getDevices (void)
387{
388 return NULL;
389}
390
391
392int USBProxyService::captureDevice (HostUSBDevice *pDevice)
393{
394 return VERR_NOT_IMPLEMENTED;
395}
396
397
398int USBProxyService::holdDevice (HostUSBDevice *pDevice)
399{
400 return VERR_NOT_IMPLEMENTED;
401}
402
403
404int USBProxyService::releaseDevice (HostUSBDevice *pDevice)
405{
406 return VERR_NOT_IMPLEMENTED;
407}
408
409
410int USBProxyService::resetDevice (HostUSBDevice *pDevice)
411{
412 return VERR_NOT_IMPLEMENTED;
413}
414
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