VirtualBox

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

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