VirtualBox

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

Last change on this file since 30045 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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