VirtualBox

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

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

Removed the USBDEVICE_WITH_EVERYTHING code. (we can fish it out of svn if we ever need it again)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.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
309/*static*/ void USBProxyService::freeDevice (PUSBDEVICE pDevice)
310{
311 RTStrFree ((char *)pDevice->pszManufacturer);
312 pDevice->pszManufacturer = NULL;
313 RTStrFree ((char *)pDevice->pszProduct);
314 pDevice->pszProduct = NULL;
315 RTStrFree ((char *)pDevice->pszSerialNumber);
316 pDevice->pszSerialNumber = NULL;
317
318 RTStrFree ((char *)pDevice->pszAddress);
319 pDevice->pszAddress = NULL;
320
321 RTMemFree (pDevice);
322
323}
324
325
326/* static */ uint64_t USBProxyService::calcSerialHash (const char *aSerial)
327{
328 if (!aSerial)
329 aSerial = "";
330
331 register const uint8_t *pu8 = (const uint8_t *)aSerial;
332 register uint64_t u64 = 14695981039346656037ULL;
333 for (;;)
334 {
335 register uint8_t u8 = *pu8;
336 if (!u8)
337 break;
338 u64 = (u64 * 1099511628211ULL) ^ u8;
339 pu8++;
340 }
341
342 return u64;
343}
344
345
346
347/* Stubs which the host specific classes overrides: */
348
349
350int USBProxyService::wait (unsigned aMillies)
351{
352 return RTThreadSleep (250);
353}
354
355
356int USBProxyService::interruptWait (void)
357{
358 return VERR_NOT_IMPLEMENTED;
359}
360
361
362PUSBDEVICE USBProxyService::getDevices (void)
363{
364 return NULL;
365}
366
367
368int USBProxyService::captureDevice (HostUSBDevice *pDevice)
369{
370 return VERR_NOT_IMPLEMENTED;
371}
372
373
374int USBProxyService::holdDevice (HostUSBDevice *pDevice)
375{
376 return VERR_NOT_IMPLEMENTED;
377}
378
379
380int USBProxyService::releaseDevice (HostUSBDevice *pDevice)
381{
382 return VERR_NOT_IMPLEMENTED;
383}
384
385
386int USBProxyService::resetDevice (HostUSBDevice *pDevice)
387{
388 return VERR_NOT_IMPLEMENTED;
389}
390
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