VirtualBox

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

Last change on this file since 5965 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • 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 * Implementation of HostUSB
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * 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/system.h>
51#include <iprt/time.h>
52#include <stdio.h>
53
54#include <algorithm>
55
56// destructor
57/////////////////////////////////////////////////////////////////////////////
58
59HostUSB::~HostUSB()
60{
61 if (isReady())
62 uninit();
63}
64
65// public initializer/uninitializer for internal purposes only
66/////////////////////////////////////////////////////////////////////////////
67
68/**
69 * Initializes the host USB object.
70 *
71 * @returns COM result indicator
72 * @param parent handle of our parent object
73 */
74HRESULT HostUSB::init(PVM pVM)
75{
76 LogFlowMember(("HostUSB::init(): isReady=%d\n", isReady()));
77
78 ComAssertRet (!isReady(), E_UNEXPECTED);
79
80 /* Save pointer to the VM */
81 mpVM = pVM;
82
83/*
84#ifdef RT_OS_LINUX
85 mUSBProxyService = new USBProxyServiceLinux (this);
86#elif defined RT_OS_WINDOWS
87 mUSBProxyService = new USBProxyServiceWin32 (this);
88*/
89#ifdef RT_OS_L4
90 mUSBProxyService = new USBProxyServiceLinux (this);
91#else
92 mUSBProxyService = new USBProxyService (this);
93#endif
94 /** @todo handle !mUSBProxySerivce->isActive() and mUSBProxyService->getLastError()
95 * and somehow report or whatever that the proxy failed to startup.
96 * Also, there might be init order issues... */
97
98 setReady(true);
99 return S_OK;
100}
101
102/**
103 * Uninitializes the host object and sets the ready flag to FALSE.
104 * Called either from FinalRelease() or by the parent when it gets destroyed.
105 */
106void HostUSB::uninit()
107{
108 LogFlowMember(("HostUSB::uninit(): isReady=%d\n", isReady()));
109
110 AssertReturn (isReady(), (void) 0);
111
112 delete mUSBProxyService;
113 mUSBProxyService = NULL;
114
115 mUSBDevices.clear();
116
117 setReady (FALSE);
118}
119
120// private methods
121////////////////////////////////////////////////////////////////////////////////
122
123/**
124 * Called by USB proxy service when a new device is physically attached
125 * to the host.
126 *
127 * @param aDevice Pointer to the device which has been attached.
128 */
129void HostUSB::onUSBDeviceAttached (HostUSBDevice *aDevice)
130{
131 LogFlowMember (("HostUSB::onUSBDeviceAttached: aDevice=%p\n",
132 aDevice));
133 HostUSB::AutoLock alock (this);
134
135 // add to the collecion
136 mUSBDevices.push_back (aDevice);
137
138 // apply all filters (no need to lock the device, nobody can access it yet)
139 HRESULT rc = AttachUSBDevice(aDevice);
140 AssertComRC (rc);
141}
142
143/**
144 * Called by USB proxy service (?) when the device is physically detached
145 * from the host.
146 *
147 * @param aDevice Pointer to the device which has been detached.
148 */
149void HostUSB::onUSBDeviceDetached (HostUSBDevice *aDevice)
150{
151 LogFlowMember (("HostUSB::onUSBDeviceDetached: aDevice=%p\n",
152 &aDevice));
153 HostUSB::AutoLock alock (this);
154
155 RTUUID id = aDevice->id();
156
157 HostUSBDevice *device = 0;
158 HostUSB::USBDeviceList::iterator it = mUSBDevices.begin();
159 while (it != mUSBDevices.end())
160 {
161 if (RTUuidCompare(&(*it)->id(), &id) == 0)
162 {
163 device = (*it);
164 break;
165 }
166 ++ it;
167 }
168
169 AssertReturn (!!device, (void) 0);
170
171 // remove from the collecion
172 mUSBDevices.erase (it);
173
174 if (device->isCaptured())
175 {
176 // the device is captured, release it
177 alock.unlock();
178 HRESULT rc = DetachUSBDevice (device);
179 AssertComRC (rc);
180 }
181}
182
183/**
184 * Called by USB proxy service when the state of the host-driven device
185 * has changed because of non proxy interaction.
186 *
187 * @param aDevice The device in question.
188 */
189void HostUSB::onUSBDeviceStateChanged (HostUSBDevice *aDevice)
190{
191 LogFlowMember (("HostUSB::onUSBDeviceStateChanged: \n"));
192 HostUSB::AutoLock alock (this);
193
194 /** @todo dmik, is there anything we should do here? For instance if the device now is available? */
195}
196
197STDMETHODIMP HostUSB::AttachUSBDevice (HostUSBDevice *hostDevice)
198{
199 AutoLock alock (this);
200 /* This originally checked that the console object was ready.
201 * Unfortunately, this method now belongs to HostUSB, and can get
202 * called during construction - so before we are "ready". */
203// CHECK_READY();
204
205 /*
206 * Don't proceed unless we've found the usb controller.
207 */
208 if (!mpVM)
209 return setError (E_FAIL, tr ("VM is not powered up"));
210 PPDMIBASE pBase;
211 int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
212 if (VBOX_FAILURE (vrc))
213 return setError (E_FAIL, tr ("VM doesn't have a USB controller"));
214 /*
215 * Make sure that the device is in a captureable state
216 */
217 USBDeviceState_T eState = hostDevice->state();
218 if (eState != USBDeviceState_USBDeviceBusy &&
219 eState != USBDeviceState_USBDeviceAvailable &&
220 eState != USBDeviceState_USBDeviceHeld)
221 return setError (E_FAIL,
222 tr ("Device is not in a capturable state"));
223 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG)pBase->pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
224 AssertReturn (pRhConfig, E_FAIL);
225
226 /*
227 * Get the address and the Uuid, and call the pfnCreateProxyDevice roothub method in EMT.
228 */
229 std::string Address;
230 STDMETHODIMP hrc = hostDevice->COMGETTER (Address) (&Address);
231 AssertComRC (hrc);
232
233 RTUUID Uuid;
234 hrc = hostDevice->COMGETTER (Id) (Uuid);
235 AssertComRC (hrc);
236
237 /* No remote devices for now */
238 BOOL fRemote = FALSE;
239 void *pvRemote = NULL;
240
241 LogFlowMember (("Console::AttachUSBDevice: Proxying USB device '%s' %Vuuid...\n", Address.c_str(), &Uuid));
242 PVMREQ pReq;
243 vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT,
244 (PFNRT)pRhConfig->pfnCreateProxyDevice,
245 5, pRhConfig, &Uuid, fRemote,
246 Address.c_str(), pvRemote);
247 if (VBOX_SUCCESS (vrc))
248 vrc = pReq->iStatus;
249 VMR3ReqFree (pReq);
250 if (VBOX_SUCCESS (vrc))
251 hostDevice->setCaptured();
252 else
253 {
254 Log (("Console::AttachUSBDevice: Failed to create proxy device for '%s' %Vuuid, vrc=%Vrc\n", Address.c_str(),
255 &Uuid, vrc));
256 AssertRC (vrc);
257 /* michael: I presume this is not needed. */
258/* hrc = mControl->ReleaseUSBDevice (Uuid);
259 AssertComRC (hrc); */
260 switch (vrc)
261 {
262 case VERR_VUSB_NO_PORTS:
263 hrc = setError (E_FAIL, tr ("No available ports on the USB controller"));
264 break;
265 case VERR_VUSB_USBFS_PERMISSION:
266 hrc = setError (E_FAIL, tr ("Not permitted to open the USB device, check usbfs options"));
267 break;
268 default:
269 hrc = setError (E_FAIL, tr ("Failed to create USB proxy device: %Vrc"), vrc);
270 break;
271 }
272 return hrc;
273 }
274
275 return S_OK;
276}
277
278STDMETHODIMP HostUSB::DetachUSBDevice (HostUSBDevice *aDevice)
279{
280 AutoLock alock (this);
281 /* This originally checked that the console object was ready.
282 * Unfortunately, this method now belongs to HostUSB, and can get
283 * called during construction - so before we are "ready". */
284// CHECK_READY();
285
286 /*
287 * Detach the device from the VM
288 */
289 int vrc = VERR_PDM_DEVICE_NOT_FOUND;
290 if (mpVM)
291 {
292 PPDMIBASE pBase;
293 vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
294 if (VBOX_SUCCESS (vrc))
295 {
296 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG)pBase->pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
297 Assert (pRhConfig);
298
299 RTUUID Uuid = aDevice->id();
300 LogFlowMember (("Console::DetachUSBDevice: Detaching USB proxy device %Vuuid...\n", &Uuid));
301 PVMREQ pReq;
302 vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)pRhConfig->pfnDestroyProxyDevice,
303 2, pRhConfig, &Uuid);
304 if (VBOX_SUCCESS (vrc))
305 vrc = pReq->iStatus;
306 VMR3ReqFree (pReq);
307 }
308 }
309 if ( vrc == VERR_PDM_DEVICE_NOT_FOUND
310 || vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
311 {
312 Log (("Console::DetachUSBDevice: USB isn't enabled.\n"));
313 vrc = VINF_SUCCESS;
314 }
315 if (VBOX_SUCCESS (vrc))
316 return S_OK;
317 Log (("Console::AttachUSBDevice: Failed to detach the device from the USB controller, vrc=%Vrc.\n", vrc));
318 return(setError (E_UNEXPECTED, tr ("Failed to destroy the USB proxy device: %Vrc"), vrc));
319}
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