VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/HostUSBImpl.cpp@ 24422

Last change on this file since 24422 was 23021, checked in by vboxsync, 15 years ago

VBoxBFE: VMR3ReqCall w/ RT_INDEFINITE_WAIT -> VMR3ReqCallWait

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implementation of HostUSB
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/* r=michael: I have removed almost all functionality from the Main
24 * version of this file, but left the structure as similar
25 * as I could in case we do need some of it some day. */
26
27#include <string>
28
29#ifdef RT_OS_LINUX
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <unistd.h>
33#include <sys/ioctl.h>
34#include <fcntl.h>
35#include <mntent.h>
36/* bird: This is a hack to work around conflicts between these linux kernel headers
37 * and the GLIBC tcpip headers. They have different declarations of the 4
38 * standard byte order functions. */
39#define _LINUX_BYTEORDER_GENERIC_H
40#include <linux/cdrom.h>
41#include <errno.h>
42#endif /* RT_OS_LINUX */
43
44#include "HostUSBImpl.h"
45#include "HostUSBDeviceImpl.h"
46#include "USBProxyService.h"
47#include "Logging.h"
48
49#include <VBox/pdm.h>
50#include <VBox/vusb.h>
51#include <VBox/usb.h>
52#include <VBox/err.h>
53#include <iprt/string.h>
54#include <iprt/time.h>
55#include <stdio.h>
56
57#include <algorithm>
58
59// destructor
60/////////////////////////////////////////////////////////////////////////////
61
62HostUSB::~HostUSB()
63{
64 if (isReady())
65 uninit();
66}
67
68// public initializer/uninitializer for internal purposes only
69/////////////////////////////////////////////////////////////////////////////
70
71/**
72 * Initializes the host USB object.
73 *
74 * @returns COM result indicator
75 * @param parent handle of our parent object
76 */
77HRESULT HostUSB::init(PVM pVM)
78{
79 LogFlowMember(("HostUSB::init(): isReady=%d\n", isReady()));
80
81 ComAssertRet (!isReady(), E_UNEXPECTED);
82
83 /* Save pointer to the VM */
84 mpVM = pVM;
85
86/*
87#ifdef RT_OS_LINUX
88 mUSBProxyService = new USBProxyServiceLinux (this);
89#elif defined RT_OS_WINDOWS
90 mUSBProxyService = new USBProxyServiceWin32 (this);
91*/
92#ifdef RT_OS_L4
93 mUSBProxyService = new USBProxyServiceLinux (this);
94#else
95 mUSBProxyService = new USBProxyService (this);
96#endif
97 /** @todo handle !mUSBProxySerivce->isActive() and mUSBProxyService->getLastError()
98 * and somehow report or whatever that the proxy failed to startup.
99 * Also, there might be init order issues... */
100
101 setReady(true);
102 return S_OK;
103}
104
105/**
106 * Uninitializes the host object and sets the ready flag to FALSE.
107 * Called either from FinalRelease() or by the parent when it gets destroyed.
108 */
109void HostUSB::uninit()
110{
111 LogFlowMember(("HostUSB::uninit(): isReady=%d\n", isReady()));
112
113 AssertReturn (isReady(), (void) 0);
114
115 delete mUSBProxyService;
116 mUSBProxyService = NULL;
117
118 mUSBDevices.clear();
119
120 setReady (FALSE);
121}
122
123// private methods
124////////////////////////////////////////////////////////////////////////////////
125
126/**
127 * Called by USB proxy service when a new device is physically attached
128 * to the host.
129 *
130 * @param aDevice Pointer to the device which has been attached.
131 */
132void HostUSB::onUSBDeviceAttached (HostUSBDevice *aDevice)
133{
134 LogFlowMember (("HostUSB::onUSBDeviceAttached: aDevice=%p\n",
135 aDevice));
136 HostUSB::AutoLock alock (this);
137
138 // add to the collecion
139 mUSBDevices.push_back (aDevice);
140
141 // apply all filters (no need to lock the device, nobody can access it yet)
142 HRESULT rc = AttachUSBDevice(aDevice);
143 AssertComRC (rc);
144}
145
146/**
147 * Called by USB proxy service (?) when the device is physically detached
148 * from the host.
149 *
150 * @param aDevice Pointer to the device which has been detached.
151 */
152void HostUSB::onUSBDeviceDetached (HostUSBDevice *aDevice)
153{
154 LogFlowMember (("HostUSB::onUSBDeviceDetached: aDevice=%p\n",
155 &aDevice));
156 HostUSB::AutoLock alock (this);
157
158 RTUUID id = aDevice->id();
159
160 HostUSBDevice *device = 0;
161 HostUSB::USBDeviceList::iterator it = mUSBDevices.begin();
162 while (it != mUSBDevices.end())
163 {
164 if (RTUuidCompare(&(*it)->id(), &id) == 0)
165 {
166 device = (*it);
167 break;
168 }
169 ++ it;
170 }
171
172 AssertReturn (!!device, (void) 0);
173
174 // remove from the collecion
175 mUSBDevices.erase (it);
176
177 if (device->isCaptured())
178 {
179 // the device is captured, release it
180 alock.unlock();
181 HRESULT rc = DetachUSBDevice (device);
182 AssertComRC (rc);
183 }
184}
185
186/**
187 * Called by USB proxy service when the state of the host-driven device
188 * has changed because of non proxy interaction.
189 *
190 * @param aDevice The device in question.
191 */
192void HostUSB::onUSBDeviceStateChanged (HostUSBDevice *aDevice)
193{
194 LogFlowMember (("HostUSB::onUSBDeviceStateChanged: \n"));
195 HostUSB::AutoLock alock (this);
196
197 /** @todo dmik, is there anything we should do here? For instance if the device now is available? */
198}
199
200STDMETHODIMP HostUSB::AttachUSBDevice (HostUSBDevice *hostDevice)
201{
202 AutoLock alock (this);
203 /* This originally checked that the console object was ready.
204 * Unfortunately, this method now belongs to HostUSB, and can get
205 * called during construction - so before we are "ready". */
206// CHECK_READY();
207
208 /*
209 * Don't proceed unless we've found the usb controller.
210 */
211 if (!mpVM)
212 return setError (E_FAIL, tr ("VM is not powered up"));
213 PPDMIBASE pBase;
214 int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
215 if (RT_FAILURE (vrc))
216 return setError (E_FAIL, tr ("VM doesn't have a USB controller"));
217 /*
218 * Make sure that the device is in a captureable state
219 */
220 USBDeviceState_T eState = hostDevice->state();
221 if (eState != USBDeviceState_Busy &&
222 eState != USBDeviceState_Available &&
223 eState != USBDeviceState_Held)
224 return setError (E_FAIL,
225 tr ("Device is not in a capturable state"));
226 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG)pBase->pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
227 AssertReturn (pRhConfig, E_FAIL);
228
229 /*
230 * Get the address and the Uuid, and call the pfnCreateProxyDevice roothub method in EMT.
231 */
232 std::string Address;
233 HRESULT hrc = hostDevice->COMGETTER (Address) (&Address);
234 AssertComRC (hrc);
235
236 RTUUID Uuid;
237 hrc = hostDevice->COMGETTER (Id) (Uuid);
238 AssertComRC (hrc);
239
240 /* No remote devices for now */
241 BOOL fRemote = FALSE;
242 void *pvRemote = NULL;
243
244 LogFlowMember (("Console::AttachUSBDevice: Proxying USB device '%s' %RTuuid...\n", Address.c_str(), &Uuid));
245 vrc = VMR3ReqCallWait (mpVM, VMCPUID_ANY,
246 (PFNRT)pRhConfig->pfnCreateProxyDevice,
247 5, pRhConfig, &Uuid, fRemote,
248 Address.c_str(), pvRemote);
249 if (RT_SUCCESS (vrc))
250 hostDevice->setCaptured();
251 else
252 {
253 Log (("Console::AttachUSBDevice: Failed to create proxy device for '%s' %RTuuid, vrc=%Rrc\n", Address.c_str(),
254 &Uuid, vrc));
255 AssertRC (vrc);
256 /* michael: I presume this is not needed. */
257/* hrc = mControl->ReleaseUSBDevice (Uuid);
258 AssertComRC (hrc); */
259 switch (vrc)
260 {
261 case VERR_VUSB_NO_PORTS:
262 hrc = setError (E_FAIL, tr ("No available ports on the USB controller"));
263 break;
264 case VERR_VUSB_USBFS_PERMISSION:
265 hrc = setError (E_FAIL, tr ("Not permitted to open the USB device, check usbfs options"));
266 break;
267 default:
268 hrc = setError (E_FAIL, tr ("Failed to create USB proxy device: %Rrc"), vrc);
269 break;
270 }
271 return hrc;
272 }
273
274 return S_OK;
275}
276
277STDMETHODIMP HostUSB::DetachUSBDevice (HostUSBDevice *aDevice)
278{
279 AutoLock alock (this);
280 /* This originally checked that the console object was ready.
281 * Unfortunately, this method now belongs to HostUSB, and can get
282 * called during construction - so before we are "ready". */
283// CHECK_READY();
284
285 /*
286 * Detach the device from the VM
287 */
288 int vrc = VERR_PDM_DEVICE_NOT_FOUND;
289 if (mpVM)
290 {
291 PPDMIBASE pBase;
292 vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
293 if (RT_SUCCESS (vrc))
294 {
295 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG)pBase->pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
296 Assert (pRhConfig);
297
298 RTUUID Uuid = aDevice->id();
299 LogFlowMember (("Console::DetachUSBDevice: Detaching USB proxy device %RTuuid...\n", &Uuid));
300 vrc = VMR3ReqCallWait (mpVM, VMCPUID_ANY, (PFNRT)pRhConfig->pfnDestroyProxyDevice,
301 2, pRhConfig, &Uuid);
302 }
303 }
304 if ( vrc == VERR_PDM_DEVICE_NOT_FOUND
305 || vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
306 {
307 Log (("Console::DetachUSBDevice: USB isn't enabled.\n"));
308 vrc = VINF_SUCCESS;
309 }
310 if (RT_SUCCESS (vrc))
311 return S_OK;
312 Log (("Console::AttachUSBDevice: Failed to detach the device from the USB controller, vrc=%Rrc.\n", vrc));
313 return(setError (E_UNEXPECTED, tr ("Failed to destroy the USB proxy device: %Rrc"), vrc));
314}
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