VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp@ 86714

Last change on this file since 86714 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1/* $Id: USBProxyBackendFreeBSD.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service, FreeBSD Specialization.
4 */
5
6/*
7 * Copyright (C) 2005-2020 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_USBPROXYBACKEND
23#include "USBProxyBackend.h"
24#include "LoggingNew.h"
25
26#include <VBox/usb.h>
27#include <VBox/usblib.h>
28#include <iprt/errcore.h>
29
30#include <iprt/string.h>
31#include <iprt/alloc.h>
32#include <iprt/assert.h>
33#include <iprt/file.h>
34#include <iprt/errcore.h>
35#include <iprt/mem.h>
36#include <iprt/param.h>
37#include <iprt/path.h>
38#include <iprt/semaphore.h>
39
40#include <stdlib.h>
41#include <string.h>
42#include <stdio.h>
43#include <errno.h>
44#include <unistd.h>
45#include <fcntl.h>
46#include <sys/poll.h>
47#include <dev/usb/usb.h>
48#include <dev/usb/usb_ioctl.h>
49
50
51/**
52 * Initialize data members.
53 */
54USBProxyBackendFreeBSD::USBProxyBackendFreeBSD()
55 : USBProxyBackend(), mNotifyEventSem(NIL_RTSEMEVENT)
56{
57 LogFlowThisFunc(("\n"));
58}
59
60USBProxyBackendFreeBSD::~USBProxyBackendFreeBSD()
61{
62 LogFlowThisFunc(("\n"));
63}
64
65/**
66 * Initializes the object (called right after construction).
67 *
68 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
69 */
70int USBProxyBackendFreeBSD::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
71 const com::Utf8Str &strAddress, bool fLoadingSettings)
72{
73 USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings);
74
75 unconst(m_strBackend) = Utf8Str("host");
76
77 /*
78 * Create semaphore.
79 */
80 int rc = RTSemEventCreate(&mNotifyEventSem);
81 if (RT_FAILURE(rc))
82 return rc;
83
84 /*
85 * Start the poller thread.
86 */
87 start();
88 return VINF_SUCCESS;
89}
90
91
92/**
93 * Stop all service threads and free the device chain.
94 */
95void USBProxyBackendFreeBSD::uninit()
96{
97 LogFlowThisFunc(("\n"));
98
99 /*
100 * Stop the service.
101 */
102 if (isActive())
103 stop();
104
105 RTSemEventDestroy(mNotifyEventSem);
106 mNotifyEventSem = NULL;
107 USBProxyBackend::uninit();
108}
109
110
111int USBProxyBackendFreeBSD::captureDevice(HostUSBDevice *aDevice)
112{
113 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
114 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
115
116 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
117 LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str()));
118
119 /*
120 * Don't think we need to do anything when the device is held... fake it.
121 */
122 Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_Capturing);
123 devLock.release();
124 interruptWait();
125
126 return VINF_SUCCESS;
127}
128
129
130int USBProxyBackendFreeBSD::releaseDevice(HostUSBDevice *aDevice)
131{
132 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
133 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
134
135 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
136 LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str()));
137
138 /*
139 * We're not really holding it atm., just fake it.
140 */
141 Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_ReleasingToHost);
142 devLock.release();
143 interruptWait();
144
145 return VINF_SUCCESS;
146}
147
148
149bool USBProxyBackendFreeBSD::isFakeUpdateRequired()
150{
151 return true;
152}
153
154
155int USBProxyBackendFreeBSD::wait(RTMSINTERVAL aMillies)
156{
157 return RTSemEventWait(mNotifyEventSem, aMillies < 1000 ? 1000 : 5000);
158}
159
160
161int USBProxyBackendFreeBSD::interruptWait(void)
162{
163 return RTSemEventSignal(mNotifyEventSem);
164}
165
166
167/**
168 * Dumps a USBDEVICE structure to the log using LogLevel 3.
169 * @param pDev The structure to log.
170 * @todo This is really common code.
171 */
172DECLINLINE(void) usbLogDevice(PUSBDEVICE pDev)
173{
174 NOREF(pDev);
175
176 Log3(("USB device:\n"));
177 Log3(("Product: %s (%x)\n", pDev->pszProduct, pDev->idProduct));
178 Log3(("Manufacturer: %s (Vendor ID %x)\n", pDev->pszManufacturer, pDev->idVendor));
179 Log3(("Serial number: %s (%llx)\n", pDev->pszSerialNumber, pDev->u64SerialHash));
180 Log3(("Device revision: %d\n", pDev->bcdDevice));
181 Log3(("Device class: %x\n", pDev->bDeviceClass));
182 Log3(("Device subclass: %x\n", pDev->bDeviceSubClass));
183 Log3(("Device protocol: %x\n", pDev->bDeviceProtocol));
184 Log3(("USB version number: %d\n", pDev->bcdUSB));
185 Log3(("Device speed: %s\n",
186 pDev->enmSpeed == USBDEVICESPEED_UNKNOWN ? "unknown"
187 : pDev->enmSpeed == USBDEVICESPEED_LOW ? "1.5 MBit/s"
188 : pDev->enmSpeed == USBDEVICESPEED_FULL ? "12 MBit/s"
189 : pDev->enmSpeed == USBDEVICESPEED_HIGH ? "480 MBit/s"
190 : pDev->enmSpeed == USBDEVICESPEED_VARIABLE ? "variable"
191 : "invalid"));
192 Log3(("Number of configurations: %d\n", pDev->bNumConfigurations));
193 Log3(("Bus number: %d\n", pDev->bBus));
194 Log3(("Port number: %d\n", pDev->bPort));
195 Log3(("Device number: %d\n", pDev->bDevNum));
196 Log3(("Device state: %s\n",
197 pDev->enmState == USBDEVICESTATE_UNSUPPORTED ? "unsupported"
198 : pDev->enmState == USBDEVICESTATE_USED_BY_HOST ? "in use by host"
199 : pDev->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE ? "in use by host, possibly capturable"
200 : pDev->enmState == USBDEVICESTATE_UNUSED ? "not in use"
201 : pDev->enmState == USBDEVICESTATE_HELD_BY_PROXY ? "held by proxy"
202 : pDev->enmState == USBDEVICESTATE_USED_BY_GUEST ? "used by guest"
203 : "invalid"));
204 Log3(("OS device address: %s\n", pDev->pszAddress));
205}
206
207
208PUSBDEVICE USBProxyBackendFreeBSD::getDevices(void)
209{
210 PUSBDEVICE pDevices = NULL;
211 int FileUsb = 0;
212 int iBus = 0;
213 int iAddr = 1;
214 int rc = VINF_SUCCESS;
215 char *pszDevicePath = NULL;
216 uint32_t PlugTime = 0;
217
218 for (;;)
219 {
220 rc = RTStrAPrintf(&pszDevicePath, "/dev/%s%d.%d", USB_GENERIC_NAME, iBus, iAddr);
221 if (RT_FAILURE(rc))
222 break;
223
224 LogFlowFunc((": Opening %s\n", pszDevicePath));
225
226 FileUsb = open(pszDevicePath, O_RDONLY);
227 if (FileUsb < 0)
228 {
229 RTStrFree(pszDevicePath);
230
231 if ((errno == ENOENT) && (iAddr > 1))
232 {
233 iAddr = 1;
234 iBus++;
235 continue;
236 }
237 else if (errno == EACCES)
238 {
239 /* Skip devices without the right permission. */
240 iAddr++;
241 continue;
242 }
243 else
244 break;
245 }
246
247 LogFlowFunc((": %s opened successfully\n", pszDevicePath));
248
249 struct usb_device_info UsbDevInfo;
250 RT_ZERO(UsbDevInfo);
251
252 rc = ioctl(FileUsb, USB_GET_DEVICEINFO, &UsbDevInfo);
253 if (rc < 0)
254 {
255 LogFlowFunc((": Error querying device info rc=%Rrc\n", RTErrConvertFromErrno(errno)));
256 close(FileUsb);
257 RTStrFree(pszDevicePath);
258 break;
259 }
260
261 /* Filter out hubs */
262 if (UsbDevInfo.udi_class != 0x09)
263 {
264 PUSBDEVICE pDevice = (PUSBDEVICE)RTMemAllocZ(sizeof(USBDEVICE));
265 if (!pDevice)
266 {
267 close(FileUsb);
268 RTStrFree(pszDevicePath);
269 break;
270 }
271
272 pDevice->enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
273 pDevice->bBus = UsbDevInfo.udi_bus;
274 pDevice->bPort = UsbDevInfo.udi_hubport;
275 pDevice->bDeviceClass = UsbDevInfo.udi_class;
276 pDevice->bDeviceSubClass = UsbDevInfo.udi_subclass;
277 pDevice->bDeviceProtocol = UsbDevInfo.udi_protocol;
278 pDevice->bNumConfigurations = UsbDevInfo.udi_config_no;
279 pDevice->idVendor = UsbDevInfo.udi_vendorNo;
280 pDevice->idProduct = UsbDevInfo.udi_productNo;
281 pDevice->bDevNum = UsbDevInfo.udi_index;
282
283 switch (UsbDevInfo.udi_speed)
284 {
285 case USB_SPEED_LOW:
286 pDevice->enmSpeed = USBDEVICESPEED_LOW;
287 break;
288 case USB_SPEED_FULL:
289 pDevice->enmSpeed = USBDEVICESPEED_FULL;
290 break;
291 case USB_SPEED_HIGH:
292 pDevice->enmSpeed = USBDEVICESPEED_HIGH;
293 break;
294 case USB_SPEED_SUPER:
295 pDevice->enmSpeed = USBDEVICESPEED_SUPER;
296 break;
297 case USB_SPEED_VARIABLE:
298 pDevice->enmSpeed = USBDEVICESPEED_VARIABLE;
299 break;
300 default:
301 pDevice->enmSpeed = USBDEVICESPEED_UNKNOWN;
302 break;
303 }
304
305 if (UsbDevInfo.udi_vendor[0] != '\0')
306 {
307 USBLibPurgeEncoding(UsbDevInfo.udi_vendor);
308 pDevice->pszManufacturer = RTStrDupN(UsbDevInfo.udi_vendor, sizeof(UsbDevInfo.udi_vendor));
309 }
310
311 if (UsbDevInfo.udi_product[0] != '\0')
312 {
313 USBLibPurgeEncoding(UsbDevInfo.udi_product);
314 pDevice->pszProduct = RTStrDupN(UsbDevInfo.udi_product, sizeof(UsbDevInfo.udi_product));
315 }
316
317 if (UsbDevInfo.udi_serial[0] != '\0')
318 {
319 USBLibPurgeEncoding(UsbDevInfo.udi_serial);
320 pDevice->pszSerialNumber = RTStrDupN(UsbDevInfo.udi_serial, sizeof(UsbDevInfo.udi_serial));
321 pDevice->u64SerialHash = USBLibHashSerial(UsbDevInfo.udi_serial);
322 }
323 rc = ioctl(FileUsb, USB_GET_PLUGTIME, &PlugTime);
324 if (rc == 0)
325 pDevice->u64SerialHash += PlugTime;
326
327 pDevice->pszAddress = RTStrDup(pszDevicePath);
328 pDevice->pszBackend = RTStrDup("host");
329
330 usbLogDevice(pDevice);
331
332 pDevice->pNext = pDevices;
333 if (pDevices)
334 pDevices->pPrev = pDevice;
335 pDevices = pDevice;
336 }
337 close(FileUsb);
338 RTStrFree(pszDevicePath);
339 iAddr++;
340 }
341
342 return pDevices;
343}
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