3
* VBox frontends: Basic Frontend (BFE):
4
* Implementation of HostUSB
8
* Copyright (C) 2006-2007 innotek GmbH
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.
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. */
26
#include <sys/types.h>
29
#include <sys/ioctl.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>
38
#endif /* RT_OS_LINUX */
40
#include "HostUSBImpl.h"
41
#include "HostUSBDeviceImpl.h"
42
#include "USBProxyService.h"
46
#include <VBox/vusb.h>
49
#include <iprt/string.h>
50
#include <iprt/system.h>
51
#include <iprt/time.h>
57
/////////////////////////////////////////////////////////////////////////////
65
// public initializer/uninitializer for internal purposes only
66
/////////////////////////////////////////////////////////////////////////////
69
* Initializes the host USB object.
71
* @returns COM result indicator
72
* @param parent handle of our parent object
74
HRESULT HostUSB::init(PVM pVM)
76
LogFlowMember(("HostUSB::init(): isReady=%d\n", isReady()));
78
ComAssertRet (!isReady(), E_UNEXPECTED);
80
/* Save pointer to the VM */
85
mUSBProxyService = new USBProxyServiceLinux (this);
86
#elif defined RT_OS_WINDOWS
87
mUSBProxyService = new USBProxyServiceWin32 (this);
90
mUSBProxyService = new USBProxyServiceLinux (this);
92
mUSBProxyService = new USBProxyService (this);
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... */
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.
106
void HostUSB::uninit()
108
LogFlowMember(("HostUSB::uninit(): isReady=%d\n", isReady()));
110
AssertReturn (isReady(), (void) 0);
112
delete mUSBProxyService;
113
mUSBProxyService = NULL;
121
////////////////////////////////////////////////////////////////////////////////
124
* Called by USB proxy service when a new device is physically attached
127
* @param aDevice Pointer to the device which has been attached.
129
void HostUSB::onUSBDeviceAttached (HostUSBDevice *aDevice)
131
LogFlowMember (("HostUSB::onUSBDeviceAttached: aDevice=%p\n",
133
HostUSB::AutoLock alock (this);
135
// add to the collecion
136
mUSBDevices.push_back (aDevice);
138
// apply all filters (no need to lock the device, nobody can access it yet)
139
HRESULT rc = AttachUSBDevice(aDevice);
144
* Called by USB proxy service (?) when the device is physically detached
147
* @param aDevice Pointer to the device which has been detached.
149
void HostUSB::onUSBDeviceDetached (HostUSBDevice *aDevice)
151
LogFlowMember (("HostUSB::onUSBDeviceDetached: aDevice=%p\n",
153
HostUSB::AutoLock alock (this);
155
RTUUID id = aDevice->id();
157
HostUSBDevice *device = 0;
158
HostUSB::USBDeviceList::iterator it = mUSBDevices.begin();
159
while (it != mUSBDevices.end())
161
if (RTUuidCompare(&(*it)->id(), &id) == 0)
169
AssertReturn (!!device, (void) 0);
171
// remove from the collecion
172
mUSBDevices.erase (it);
174
if (device->isCaptured())
176
// the device is captured, release it
178
HRESULT rc = DetachUSBDevice (device);
184
* Called by USB proxy service when the state of the host-driven device
185
* has changed because of non proxy interaction.
187
* @param aDevice The device in question.
189
void HostUSB::onUSBDeviceStateChanged (HostUSBDevice *aDevice)
191
LogFlowMember (("HostUSB::onUSBDeviceStateChanged: \n"));
192
HostUSB::AutoLock alock (this);
194
/** @todo dmik, is there anything we should do here? For instance if the device now is available? */
197
STDMETHODIMP HostUSB::AttachUSBDevice (HostUSBDevice *hostDevice)
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". */
206
* Don't proceed unless we've found the usb controller.
209
return setError (E_FAIL, tr ("VM is not powered up"));
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"));
215
* Make sure that the device is in a captureable state
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);
227
* Get the address and the Uuid, and call the pfnCreateProxyDevice roothub method in EMT.
230
STDMETHODIMP hrc = hostDevice->COMGETTER (Address) (&Address);
234
hrc = hostDevice->COMGETTER (Id) (Uuid);
237
/* No remote devices for now */
238
BOOL fRemote = FALSE;
239
void *pvRemote = NULL;
241
LogFlowMember (("Console::AttachUSBDevice: Proxying USB device '%s' %Vuuid...\n", Address.c_str(), &Uuid));
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))
250
if (VBOX_SUCCESS (vrc))
251
hostDevice->setCaptured();
254
Log (("Console::AttachUSBDevice: Failed to create proxy device for '%s' %Vuuid, vrc=%Vrc\n", Address.c_str(),
257
/* michael: I presume this is not needed. */
258
/* hrc = mControl->ReleaseUSBDevice (Uuid);
259
AssertComRC (hrc); */
262
case VERR_VUSB_NO_PORTS:
263
hrc = setError (E_FAIL, tr ("No available ports on the USB controller"));
265
case VERR_VUSB_USBFS_PERMISSION:
266
hrc = setError (E_FAIL, tr ("Not permitted to open the USB device, check usbfs options"));
269
hrc = setError (E_FAIL, tr ("Failed to create USB proxy device: %Vrc"), vrc);
278
STDMETHODIMP HostUSB::DetachUSBDevice (HostUSBDevice *aDevice)
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". */
287
* Detach the device from the VM
289
int vrc = VERR_PDM_DEVICE_NOT_FOUND;
293
vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
294
if (VBOX_SUCCESS (vrc))
296
PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG)pBase->pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
299
RTUUID Uuid = aDevice->id();
300
LogFlowMember (("Console::DetachUSBDevice: Detaching USB proxy device %Vuuid...\n", &Uuid));
302
vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT, (PFNRT)pRhConfig->pfnDestroyProxyDevice,
303
2, pRhConfig, &Uuid);
304
if (VBOX_SUCCESS (vrc))
309
if ( vrc == VERR_PDM_DEVICE_NOT_FOUND
310
|| vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
312
Log (("Console::DetachUSBDevice: USB isn't enabled.\n"));
315
if (VBOX_SUCCESS (vrc))
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));