VirtualBox

source: vbox/trunk/src/VBox/Main/HostUSBDeviceImpl.cpp@ 2397

Last change on this file since 2397 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: 18.9 KB
Line 
1/** @file
2 *
3 * VirtualBox IHostUSBDevice COM interface implementation
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "HostUSBDeviceImpl.h"
23#include "USBProxyService.h"
24#include "Logging.h"
25
26#include <VBox/err.h>
27
28
29// constructor / destructor
30/////////////////////////////////////////////////////////////////////////////
31
32HostUSBDevice::HostUSBDevice()
33 : mUSBProxyService (NULL), m_pUsb (NULL)
34{
35}
36
37HostUSBDevice::~HostUSBDevice()
38{
39 if (m_pUsb)
40 {
41 USBProxyService::freeDevice (m_pUsb);
42 m_pUsb = NULL;
43 }
44}
45
46// public initializer/uninitializer for internal purposes only
47/////////////////////////////////////////////////////////////////////////////
48
49/**
50 * Initializes the USB device object.
51 *
52 * @returns COM result indicator
53 * @param aUsb Pointer to the usb device structure for which the object is to be a wrapper.
54 * This structure is now fully owned by the HostUSBDevice object and will be
55 * freed when it is destructed.
56 * @param aUSBProxyService Pointer to the USB Proxy Service object.
57 */
58HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
59{
60 ComAssertRet (aUsb, E_INVALIDARG);
61
62 AutoLock alock (this);
63
64 /*
65 * We need a unique ID for this VBoxSVC session.
66 * The UUID isn't stored anywhere.
67 */
68 mId.create();
69
70 /*
71 * Convert from USBDEVICESTATE to USBDeviceState.
72 *
73 * Note that not all proxy backend can detect the HELD_BY_PROXY
74 * and USED_BY_GUEST states. But that shouldn't matter much.
75 */
76 switch (aUsb->enmState)
77 {
78 default:
79 AssertMsgFailed(("aUsb->enmState=%d\n", aUsb->enmState));
80 case USBDEVICESTATE_UNSUPPORTED:
81 mState = USBDeviceState_USBDeviceNotSupported;
82 break;
83 case USBDEVICESTATE_USED_BY_HOST:
84 mState = USBDeviceState_USBDeviceUnavailable;
85 break;
86 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
87 mState = USBDeviceState_USBDeviceBusy;
88 break;
89 case USBDEVICESTATE_UNUSED:
90 mState = USBDeviceState_USBDeviceAvailable;
91 break;
92 case USBDEVICESTATE_HELD_BY_PROXY:
93 mState = USBDeviceState_USBDeviceHeld;
94 break;
95 case USBDEVICESTATE_USED_BY_GUEST:
96 mState = USBDeviceState_USBDeviceCaptured;
97 break;
98 }
99
100 /*
101 * Other data members.
102 */
103 mIgnored = false;
104 mUSBProxyService = aUSBProxyService;
105 m_pUsb = aUsb;
106
107 setReady (true);
108 return S_OK;
109}
110
111// IUSBDevice properties
112/////////////////////////////////////////////////////////////////////////////
113
114/**
115 * Returns the GUID.
116 *
117 * @returns COM status code
118 * @param aId Address of result variable.
119 */
120STDMETHODIMP HostUSBDevice::COMGETTER(Id)(GUIDPARAMOUT aId)
121{
122 if (!aId)
123 return E_INVALIDARG;
124
125 AutoLock alock (this);
126 CHECK_READY();
127
128 mId.cloneTo (aId);
129 return S_OK;
130}
131
132
133/**
134 * Returns the vendor Id.
135 *
136 * @returns COM status code
137 * @param aVendorId Where to store the vendor id.
138 */
139STDMETHODIMP HostUSBDevice::COMGETTER(VendorId)(USHORT *aVendorId)
140{
141 if (!aVendorId)
142 return E_INVALIDARG;
143
144 AutoLock alock (this);
145 CHECK_READY();
146
147 *aVendorId = m_pUsb->idVendor;
148 return S_OK;
149}
150
151
152/**
153 * Returns the product Id.
154 *
155 * @returns COM status code
156 * @param aProductId Where to store the product id.
157 */
158STDMETHODIMP HostUSBDevice::COMGETTER(ProductId)(USHORT *aProductId)
159{
160 if (!aProductId)
161 return E_INVALIDARG;
162
163 AutoLock alock (this);
164 CHECK_READY();
165
166 *aProductId = m_pUsb->idProduct;
167 return S_OK;
168}
169
170
171/**
172 * Returns the revision BCD.
173 *
174 * @returns COM status code
175 * @param aRevision Where to store the revision BCD.
176 */
177STDMETHODIMP HostUSBDevice::COMGETTER(Revision)(USHORT *aRevision)
178{
179 if (!aRevision)
180 return E_INVALIDARG;
181
182 AutoLock alock (this);
183 CHECK_READY();
184
185 *aRevision = m_pUsb->bcdDevice;
186 return S_OK;
187}
188
189/**
190 * Returns the manufacturer string.
191 *
192 * @returns COM status code
193 * @param aManufacturer Where to put the return string.
194 */
195STDMETHODIMP HostUSBDevice::COMGETTER(Manufacturer)(BSTR *aManufacturer)
196{
197 if (!aManufacturer)
198 return E_INVALIDARG;
199
200 AutoLock alock (this);
201 CHECK_READY();
202
203 Bstr (m_pUsb->pszManufacturer).cloneTo (aManufacturer);
204 return S_OK;
205}
206
207
208/**
209 * Returns the product string.
210 *
211 * @returns COM status code
212 * @param aProduct Where to put the return string.
213 */
214STDMETHODIMP HostUSBDevice::COMGETTER(Product)(BSTR *aProduct)
215{
216 if (!aProduct)
217 return E_INVALIDARG;
218
219 AutoLock alock (this);
220 CHECK_READY();
221
222 Bstr (m_pUsb->pszProduct).cloneTo (aProduct);
223 return S_OK;
224}
225
226
227/**
228 * Returns the serial number string.
229 *
230 * @returns COM status code
231 * @param aSerialNumber Where to put the return string.
232 */
233STDMETHODIMP HostUSBDevice::COMGETTER(SerialNumber)(BSTR *aSerialNumber)
234{
235 if (!aSerialNumber)
236 return E_INVALIDARG;
237
238 AutoLock alock (this);
239 CHECK_READY();
240
241 Bstr (m_pUsb->pszSerialNumber).cloneTo (aSerialNumber);
242 return S_OK;
243}
244
245/**
246 * Returns the device address string.
247 *
248 * @returns COM status code
249 * @param aAddress Where to put the returned string.
250 */
251STDMETHODIMP HostUSBDevice::COMGETTER(Address)(BSTR *aAddress)
252{
253 if (!aAddress)
254 return E_INVALIDARG;
255
256 AutoLock alock (this);
257 CHECK_READY();
258
259 Bstr (m_pUsb->pszAddress).cloneTo (aAddress);
260 return S_OK;
261}
262
263STDMETHODIMP HostUSBDevice::COMGETTER(Port)(USHORT *aPort)
264{
265 if (!aPort)
266 return E_INVALIDARG;
267
268 AutoLock alock (this);
269 CHECK_READY();
270
271 ///@todo implement
272 aPort = 0;
273 return S_OK;
274}
275
276STDMETHODIMP HostUSBDevice::COMGETTER(Remote)(BOOL *aRemote)
277{
278 if (!aRemote)
279 return E_INVALIDARG;
280
281 AutoLock alock (this);
282 CHECK_READY();
283
284 *aRemote = FALSE;
285 return S_OK;
286}
287
288// IHostUSBDevice properties
289/////////////////////////////////////////////////////////////////////////////
290
291STDMETHODIMP HostUSBDevice::COMGETTER(State) (USBDeviceState_T *aState)
292{
293 if (!aState)
294 return E_POINTER;
295
296 AutoLock lock (this);
297 CHECK_READY();
298
299 *aState = mState;
300 return S_OK;
301}
302
303
304// public methods only for internal purposes
305////////////////////////////////////////////////////////////////////////////////
306
307Utf8Str HostUSBDevice::name()
308{
309 Utf8Str name;
310
311 AutoLock alock (this);
312 AssertReturn (isReady(), name);
313
314 bool haveManufacturer = m_pUsb->pszManufacturer && *m_pUsb->pszManufacturer;
315 bool haveProduct = m_pUsb->pszProduct && *m_pUsb->pszProduct;
316 if (haveManufacturer && haveProduct)
317 name = Utf8StrFmt ("%s %s", m_pUsb->pszManufacturer,
318 m_pUsb->pszProduct);
319 else if(haveManufacturer)
320 name = Utf8StrFmt ("%s", m_pUsb->pszManufacturer);
321 else if(haveProduct)
322 name = Utf8StrFmt ("%s", m_pUsb->pszManufacturer);
323 else
324 name = "<unknown>";
325
326 return name;
327}
328
329/** Sets the ignored flag and returns the device to the host */
330void HostUSBDevice::setIgnored()
331{
332 AutoLock alock (this);
333 AssertReturn (isReady(), (void) 0);
334
335 AssertReturn (!mIgnored, (void) 0);
336
337 mIgnored = false;
338 setHostDriven();
339}
340
341/** Requests the capture */
342bool HostUSBDevice::setCaptured (SessionMachine *aMachine)
343{
344 AssertReturn (aMachine, false);
345
346 AutoLock alock (this);
347 AssertReturn (isReady(), false);
348
349 AssertReturn (
350 mState == USBDeviceState_USBDeviceBusy ||
351 mState == USBDeviceState_USBDeviceAvailable ||
352 mState == USBDeviceState_USBDeviceHeld,
353 false);
354
355 mUSBProxyService->captureDevice (this);
356
357 mState = USBDeviceState_USBDeviceCaptured;
358 mMachine = aMachine;
359
360 return true;
361}
362
363/**
364 * Returns the device back to the host
365 *
366 * @returns VBox status code.
367 */
368int HostUSBDevice::setHostDriven()
369{
370 AutoLock alock (this);
371 AssertReturn (isReady(), VERR_INVALID_PARAMETER);
372
373 AssertReturn (mState == USBDeviceState_USBDeviceHeld, VERR_INVALID_PARAMETER);
374
375 mState = USBDeviceState_USBDeviceAvailable;
376
377 return mUSBProxyService->releaseDevice (this);
378}
379
380/**
381 * Resets the device as if it were just attached to the host
382 *
383 * @returns VBox status code.
384 */
385int HostUSBDevice::reset()
386{
387 AutoLock alock (this);
388 AssertReturn (isReady(), VERR_INVALID_PARAMETER);
389
390 mState = USBDeviceState_USBDeviceHeld;
391 mMachine.setNull();
392 mIgnored = false;
393
394 /** @todo this operation might fail and cause the device to the reattached with a different address and all that. */
395 return mUSBProxyService->resetDevice (this);
396}
397
398/**
399 * Sets the state of the device, as it was reported by the host.
400 * This method applicable only for devices currently controlled by the host.
401 *
402 * @param aState new state
403 */
404void HostUSBDevice::setHostState (USBDeviceState_T aState)
405{
406 AssertReturn (
407 aState == USBDeviceState_USBDeviceUnavailable ||
408 aState == USBDeviceState_USBDeviceBusy ||
409 aState == USBDeviceState_USBDeviceAvailable,
410 (void) 0);
411
412 AssertReturn (
413 mState == USBDeviceState_USBDeviceNotSupported || /* initial state */
414 mState == USBDeviceState_USBDeviceUnavailable ||
415 mState == USBDeviceState_USBDeviceBusy ||
416 mState == USBDeviceState_USBDeviceAvailable,
417 (void) 0);
418
419 if (mState != aState)
420 {
421 mState = aState;
422 }
423}
424
425/**
426 * Returns true if this device matches the given filter data.
427 *
428 * @note It is assumed, that the filter data owner is appropriately
429 * locked before calling this method.
430 *
431 * @note
432 * This method MUST correlate with
433 * USBController::hasMatchingFilter (IUSBDevice *)
434 * in the sense of the device matching logic.
435 */
436bool HostUSBDevice::isMatch (const USBDeviceFilter::Data &aData)
437{
438 AutoLock alock (this);
439 AssertReturn (isReady(), false);
440
441 if (!aData.mActive)
442 return false;
443
444 if (!aData.mVendorId.isMatch (m_pUsb->idVendor))
445 {
446 LogFlowMember (("HostUSBDevice::isMatch: vendor not match %04X\n",
447 m_pUsb->idVendor));
448 return false;
449 }
450 if (!aData.mProductId.isMatch (m_pUsb->idProduct))
451 {
452 LogFlowMember (("HostUSBDevice::isMatch: product id not match %04X\n",
453 m_pUsb->idProduct));
454 return false;
455 }
456 if (!aData.mRevision.isMatch (m_pUsb->bcdDevice))
457 {
458 LogFlowMember (("HostUSBDevice::isMatch: rev not match %04X\n",
459 m_pUsb->bcdDevice));
460 return false;
461 }
462
463#if !defined (__WIN__)
464 // these filters are temporarily ignored on Win32
465 if (!aData.mManufacturer.isMatch (Bstr (m_pUsb->pszManufacturer)))
466 return false;
467 if (!aData.mProduct.isMatch (Bstr (m_pUsb->pszProduct)))
468 return false;
469 if (!aData.mSerialNumber.isMatch (Bstr (m_pUsb->pszSerialNumber)))
470 return false;
471 /// @todo (dmik) pusPort is yet absent
472// if (!aData.mPort.isMatch (Bstr (m_pUsb->pusPort)))
473// return false;
474#endif
475
476 // Host USB devices are local, so remote is always FALSE
477 if (!aData.mRemote.isMatch (FALSE))
478 {
479 LogFlowMember (("Host::HostUSBDevice: remote not match FALSE\n"));
480 return false;
481 }
482
483 /// @todo (dmik): bird, I assumed isMatch() is called only for devices
484 // that are suitable for holding/capturing (also assuming that when the device
485 // is just attached it first goes to our filter driver, and only after applying
486 // filters goes back to the system when appropriate). So the below
487 // doesn't look too correct; moreover, currently there is no determinable
488 // "any match" state for intervalic filters, and it will be not so easy
489 // to determine this state for an arbitrary regexp expression...
490 // For now, I just check that the string filter is empty (which doesn't
491 // actually reflect all possible "any match" filters).
492 //
493 // bird: This method was called for any device some weeks back, and it most certainly
494 // should be called for 'busy' devices still. However, we do *not* want 'busy' devices
495 // to match empty filters (because that will for instance capture all USB keyboards & mice).
496 // You assumption about a filter driver is not correct on linux. We're racing with
497 // everyone else in the system there - see your problem with usbfs access.
498 //
499 // The customer *requires* a way of matching all devices which the host isn't using,
500 // if that is now difficult or the below method opens holes in the matching, this *must*
501 // be addresses immediately.
502
503 /*
504 * If all the criteria is empty, devices which are used by the host will not match.
505 */
506 if ( m_pUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
507 && aData.mVendorId.string().isEmpty()
508 && aData.mProductId.string().isEmpty()
509 && aData.mRevision.string().isEmpty()
510 && aData.mManufacturer.string().isEmpty()
511 && aData.mProduct.string().isEmpty()
512 && aData.mSerialNumber.string().isEmpty())
513 return false;
514
515 LogFlowMember (("HostUSBDevice::isMatch: returns true\n"));
516 return true;
517}
518
519
520/**
521 * Compares this device with a USBDEVICE and decides which comes first.
522 *
523 * @returns < 0 if this should come before pDev2.
524 * @returns 0 if this and pDev2 are equal.
525 * @returns > 0 if this should come after pDev2.
526 *
527 * @param pDev2 Device 2.
528 */
529int HostUSBDevice::compare (PCUSBDEVICE pDev2)
530{
531 return compare (m_pUsb, pDev2);
532}
533
534
535/**
536 * Compares two USB devices and decides which comes first.
537 *
538 * @returns < 0 if pDev1 should come before pDev2.
539 * @returns 0 if pDev1 and pDev2 are equal.
540 * @returns > 0 if pDev1 should come after pDev2.
541 *
542 * @param pDev1 Device 1.
543 * @param pDev2 Device 2.
544 */
545/*static*/ int HostUSBDevice::compare (PCUSBDEVICE pDev1, PCUSBDEVICE pDev2)
546{
547 int iDiff = pDev1->idVendor - pDev2->idVendor;
548 if (iDiff)
549 return iDiff;
550
551 iDiff = pDev1->idProduct - pDev2->idProduct;
552 if (iDiff)
553 return iDiff;
554
555 /** @todo Sander, will this work on windows as well? Linux won't reuse an address for quite a while. */
556 return strcmp(pDev1->pszAddress, pDev2->pszAddress);
557}
558
559/**
560 * Updates the state of the device.
561 *
562 * @returns true if the state has actually changed.
563 * @returns false if the stat didn't change, or the change might have been cause by VBox.
564 *
565 * @param aDev The current device state as seen by the proxy backend.
566 */
567bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
568{
569 AutoLock alock (this);
570
571 /*
572 * We have to be pretty conservative here because the proxy backend
573 * doesn't necessarily know everything that's going on. So, rather
574 * be overly careful than changing the state once when we shouldn't!
575 */
576 switch (aDev->enmState)
577 {
578 default:
579 AssertMsgFailed (("aDev->enmState=%d\n", aDev->enmState));
580 case USBDEVICESTATE_UNSUPPORTED:
581 Assert (mState == USBDeviceState_USBDeviceNotSupported);
582 return false;
583
584 case USBDEVICESTATE_USED_BY_HOST:
585 switch (mState)
586 {
587 case USBDeviceState_USBDeviceUnavailable:
588 /* the proxy may confuse following states with unavailable */
589 case USBDeviceState_USBDeviceHeld:
590 case USBDeviceState_USBDeviceCaptured:
591 return false;
592 default:
593 LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
594 mState, USBDeviceState_USBDeviceUnavailable));
595 mState = USBDeviceState_USBDeviceUnavailable;
596 return true;
597 }
598 break;
599
600 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
601 switch (mState)
602 {
603 case USBDeviceState_USBDeviceBusy:
604 /* the proxy may confuse following states with capturable */
605 case USBDeviceState_USBDeviceHeld:
606 case USBDeviceState_USBDeviceCaptured:
607 return false;
608 default:
609 LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
610 mState, USBDeviceState_USBDeviceBusy));
611 mState = USBDeviceState_USBDeviceBusy;
612 return true;
613 }
614 break;
615
616 case USBDEVICESTATE_UNUSED:
617 switch (mState)
618 {
619 case USBDeviceState_USBDeviceAvailable:
620 /* the proxy may confuse following state(s) with available */
621 case USBDeviceState_USBDeviceHeld:
622 case USBDeviceState_USBDeviceCaptured:
623 return false;
624 default:
625 LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
626 mState, USBDeviceState_USBDeviceAvailable));
627 mState = USBDeviceState_USBDeviceAvailable;
628 return true;
629 }
630 break;
631
632 case USBDEVICESTATE_HELD_BY_PROXY:
633 switch (mState)
634 {
635 case USBDeviceState_USBDeviceHeld:
636 /* the proxy may confuse following state(s) with held */
637 case USBDeviceState_USBDeviceAvailable:
638 case USBDeviceState_USBDeviceBusy:
639 case USBDeviceState_USBDeviceCaptured:
640 return false;
641 default:
642 LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
643 mState, USBDeviceState_USBDeviceHeld));
644 mState = USBDeviceState_USBDeviceHeld;
645 return true;
646 }
647 break;
648
649 case USBDEVICESTATE_USED_BY_GUEST:
650 switch (mState)
651 {
652 case USBDeviceState_USBDeviceCaptured:
653 /* the proxy may confuse following state(s) with captured */
654 case USBDeviceState_USBDeviceHeld:
655 case USBDeviceState_USBDeviceAvailable:
656 case USBDeviceState_USBDeviceBusy:
657 return false;
658 default:
659 LogFlowMember ((" HostUSBDevice::updateState: %d -> %d\n",
660 mState, USBDeviceState_USBDeviceHeld));
661 mState = USBDeviceState_USBDeviceHeld;
662 return true;
663 }
664 break;
665 }
666}
667
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