VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp@ 59122

Last change on this file since 59122 was 59122, checked in by vboxsync, 9 years ago

Main/USB: More fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.4 KB
Line 
1/* $Id: USBProxyBackendSolaris.cpp 59122 2015-12-14 14:50:28Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service, Solaris Specialization.
4 */
5
6/*
7 * Copyright (C) 2005-2014 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#include "USBProxyBackend.h"
23#include "Logging.h"
24
25#include <VBox/usb.h>
26#include <VBox/usblib.h>
27#include <VBox/err.h>
28#include <iprt/semaphore.h>
29#include <iprt/path.h>
30
31#include <sys/usb/usba.h>
32#include <syslog.h>
33
34
35/*********************************************************************************************************************************
36* Internal Functions *
37*********************************************************************************************************************************/
38static int solarisWalkDeviceNode(di_node_t Node, void *pvArg);
39static void solarisFreeUSBDevice(PUSBDEVICE pDevice);
40static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node_t Node);
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46typedef struct USBDEVICELIST
47{
48 PUSBDEVICE pHead;
49 PUSBDEVICE pTail;
50} USBDEVICELIST;
51typedef USBDEVICELIST *PUSBDEVICELIST;
52
53
54/**
55 * Initialize data members.
56 */
57USBProxyBackendSolaris::USBProxyBackendSolaris(USBProxyService *aUsbProxyService)
58 : USBProxyBackend(aUsbProxyService), mUSBLibInitialized(false)
59{
60 LogFlowThisFunc(("aUsbProxyService=%p\n", aUsbProxyService));
61}
62
63
64/**
65 * Initializes the object (called right after construction).
66 *
67 * @returns VBox status code.
68 */
69int USBProxyBackendSolaris::init(void)
70{
71 /*
72 * Create semaphore.
73 */
74 int rc = RTSemEventCreate(&mNotifyEventSem);
75 if (RT_FAILURE(rc))
76 return rc;
77
78 /*
79 * Initialize the USB library.
80 */
81 rc = USBLibInit();
82 if (RT_FAILURE(rc))
83 {
84 RTSemEventDestroy(&mNotifyEventSem);
85 return rc;
86 }
87
88 mUSBLibInitialized = true;
89
90 /*
91 * Start the poller thread.
92 */
93 start();
94 return VINF_SUCCESS;
95}
96
97
98/**
99 * Stop all service threads and free the device chain.
100 */
101USBProxyBackendSolaris::~USBProxyBackendSolaris()
102{
103 LogFlowThisFunc(("destruct\n"));
104
105 /*
106 * Stop the service.
107 */
108 if (isActive())
109 stop();
110
111 /*
112 * Terminate the USB library
113 */
114 if (mUSBLibInitialized)
115 {
116 USBLibTerm();
117 mUSBLibInitialized = false;
118 }
119
120 RTSemEventDestroy(mNotifyEventSem);
121 mNotifyEventSem = NULL;
122}
123
124
125void *USBProxyBackendSolaris::insertFilter(PCUSBFILTER aFilter)
126{
127 return USBLibAddFilter(aFilter);
128}
129
130
131voidUSBProxyBackendSolaris::removeFilter(void *pvID)
132{
133 USBLibRemoveFilter(pvID);
134}
135
136
137int USBProxyBackendSolaris::wait(RTMSINTERVAL aMillies)
138{
139 return RTSemEventWait(mNotifyEventSem, aMillies < 1000 ? 1000 : RT_MIN(aMillies, 5000));
140}
141
142
143int USBProxyBackendSolaris::interruptWait(void)
144{
145 return RTSemEventSignal(mNotifyEventSem);
146}
147
148
149PUSBDEVICE USBProxyBackendSolaris::getDevices(void)
150{
151 USBDEVICELIST DevList;
152 DevList.pHead = NULL;
153 DevList.pTail = NULL;
154 di_node_t RootNode = di_init("/", DINFOCPYALL);
155 if (RootNode != DI_NODE_NIL)
156 di_walk_node(RootNode, DI_WALK_CLDFIRST, &DevList, solarisWalkDeviceNode);
157
158 di_fini(RootNode);
159 return DevList.pHead;
160}
161
162
163static int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
164{
165 PUSBDEVICELIST pList = (PUSBDEVICELIST)pvArg;
166 AssertPtrReturn(pList, DI_WALK_TERMINATE);
167
168 /*
169 * Check if it's a USB device in the first place.
170 */
171 bool fUSBDevice = false;
172 char *pszCompatNames = NULL;
173 int cCompatNames = di_compatible_names(Node, &pszCompatNames);
174 for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1)
175 if (!strncmp(pszCompatNames, RT_STR_TUPLE("usb")))
176 {
177 fUSBDevice = true;
178 break;
179 }
180
181 if (!fUSBDevice)
182 return DI_WALK_CONTINUE;
183
184 /*
185 * Check if it's a device node or interface.
186 */
187 int *pInt = NULL;
188 char *pStr = NULL;
189 int rc = DI_WALK_CONTINUE;
190 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "interface", &pInt) < 0)
191 {
192 /* It's a device node. */
193 char *pszDevicePath = di_devfs_path(Node);
194 PUSBDEVICE pCur = (PUSBDEVICE)RTMemAllocZ(sizeof(*pCur));
195 if (!pCur)
196 {
197 LogRel(("USBService: failed to allocate %d bytes for PUSBDEVICE.\n", sizeof(*pCur)));
198 return DI_WALK_TERMINATE;
199 }
200
201 bool fValidDevice = false;
202 do
203 {
204 AssertBreak(pszDevicePath);
205
206 char *pszDriverName = di_driver_name(Node);
207
208 /*
209 * Skip hubs
210 */
211 if ( pszDriverName
212 && !strcmp(pszDriverName, "hubd"))
213 {
214 break;
215 }
216
217 /*
218 * Mandatory.
219 * snv_85 and above have usb-dev-descriptor node properties, but older one's do not.
220 * So if we cannot obtain the entire device descriptor, we try falling back to the
221 * individual properties (those must not fail, if it does we drop the device).
222 */
223 uchar_t *pDevData = NULL;
224 int cbProp = di_prop_lookup_bytes(DDI_DEV_T_ANY, Node, "usb-dev-descriptor", &pDevData);
225 if ( cbProp > 0
226 && pDevData)
227 {
228 usb_dev_descr_t *pDeviceDescriptor = (usb_dev_descr_t *)pDevData;
229 pCur->bDeviceClass = pDeviceDescriptor->bDeviceClass;
230 pCur->bDeviceSubClass = pDeviceDescriptor->bDeviceSubClass;
231 pCur->bDeviceProtocol = pDeviceDescriptor->bDeviceProtocol;
232 pCur->idVendor = pDeviceDescriptor->idVendor;
233 pCur->idProduct = pDeviceDescriptor->idProduct;
234 pCur->bcdDevice = pDeviceDescriptor->bcdDevice;
235 pCur->bcdUSB = pDeviceDescriptor->bcdUSB;
236 pCur->bNumConfigurations = pDeviceDescriptor->bNumConfigurations;
237 pCur->fPartialDescriptor = false;
238 }
239 else
240 {
241 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-vendor-id", &pInt) > 0);
242 pCur->idVendor = (uint16_t)*pInt;
243
244 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-product-id", &pInt) > 0);
245 pCur->idProduct = (uint16_t)*pInt;
246
247 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-revision-id", &pInt) > 0);
248 pCur->bcdDevice = (uint16_t)*pInt;
249
250 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-release", &pInt) > 0);
251 pCur->bcdUSB = (uint16_t)*pInt;
252
253 pCur->fPartialDescriptor = true;
254 }
255
256 char *pszPortAddr = di_bus_addr(Node);
257 if (pszPortAddr)
258 pCur->bPort = RTStrToUInt8(pszPortAddr); /* Bus & Port are mixed up (kernel driver/userland) */
259 else
260 pCur->bPort = 0;
261
262 char szBuf[PATH_MAX + 48];
263 RTStrPrintf(szBuf, sizeof(szBuf), "%#x:%#x:%d:%s", pCur->idVendor, pCur->idProduct, pCur->bcdDevice, pszDevicePath);
264 pCur->pszAddress = RTStrDup(szBuf);
265 AssertBreak(pCur->pszAddress);
266
267 pCur->pszDevicePath = RTStrDup(pszDevicePath);
268 AssertBreak(pCur->pszDevicePath);
269
270 pCur->pszBackend = RTStrDup("host");
271 AssertBreak(pCur->pszBackend);
272
273 /*
274 * Optional (some devices don't have all these)
275 */
276 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-product-name", &pStr) > 0)
277 pCur->pszProduct = RTStrDup(pStr);
278
279 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-vendor-name", &pStr) > 0)
280 pCur->pszManufacturer = RTStrDup(pStr);
281
282 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-serialno", &pStr) > 0)
283 pCur->pszSerialNumber = RTStrDup(pStr);
284
285 if (pCur->bcdUSB == 0x300)
286 pCur->enmSpeed = USBDEVICESPEED_SUPER;
287 else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "low-speed", &pInt) >= 0)
288 pCur->enmSpeed = USBDEVICESPEED_LOW;
289 else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "high-speed", &pInt) >= 0)
290 pCur->enmSpeed = USBDEVICESPEED_HIGH;
291 else
292 pCur->enmSpeed = USBDEVICESPEED_FULL;
293
294 /* Determine state of the USB device. */
295 pCur->enmState = solarisDetermineUSBDeviceState(pCur, Node);
296
297 /*
298 * Valid device, add it to the list.
299 */
300 fValidDevice = true;
301 pCur->pPrev = pList->pTail;
302 if (pList->pTail)
303 pList->pTail = pList->pTail->pNext = pCur;
304 else
305 pList->pTail = pList->pHead = pCur;
306
307 rc = DI_WALK_CONTINUE;
308 } while (0);
309
310 di_devfs_path_free(pszDevicePath);
311 if (!fValidDevice)
312 solarisFreeUSBDevice(pCur);
313 }
314 return rc;
315}
316
317
318static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node_t Node)
319{
320 char *pszDriverName = di_driver_name(Node);
321
322 /* Not possible unless a user explicitly unbinds the default driver. */
323 if (!pszDriverName)
324 return USBDEVICESTATE_UNUSED;
325
326 if (!strncmp(pszDriverName, RT_STR_TUPLE(VBOXUSB_DRIVER_NAME)))
327 return USBDEVICESTATE_HELD_BY_PROXY;
328
329 NOREF(pDevice);
330 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
331}
332
333
334int USBProxyBackendSolaris::captureDevice(HostUSBDevice *aDevice)
335{
336 /*
337 * Check preconditions.
338 */
339 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
340 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
341
342 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
343 LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str()));
344
345 Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_Capturing);
346 AssertReturn(aDevice->i_getUsbData(), VERR_INVALID_POINTER);
347
348 /*
349 * Create a one-shot capture filter for the device and reset the device.
350 */
351 USBFILTER Filter;
352 USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_CAPTURE);
353 initFilterFromDevice(&Filter, aDevice);
354
355 void *pvId = USBLibAddFilter(&Filter);
356 if (!pvId)
357 {
358 LogRel(("USBService: failed to add filter\n"));
359 return VERR_GENERAL_FAILURE;
360 }
361
362 PUSBDEVICE pDev = aDevice->i_getUsbData();
363 int rc = USBLibResetDevice(pDev->pszDevicePath, true);
364 if (RT_SUCCESS(rc))
365 aDevice->i_setBackendUserData(pvId);
366 else
367 {
368 USBLibRemoveFilter(pvId);
369 pvId = NULL;
370 }
371 LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
372 return rc;
373}
374
375
376void USBProxyBackendSolaris::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
377{
378 AssertReturnVoid(aDevice->isWriteLockOnCurrentThread());
379 /*
380 * Remove the one-shot filter if necessary.
381 */
382 LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->i_getBackendUserData()));
383 if (!aSuccess && aDevice->i_getBackendUserData())
384 USBLibRemoveFilter(aDevice->mOneShotId);
385 aDevice->i_setBackendUserData(NULL);
386}
387
388
389int USBProxyBackendSolaris::releaseDevice(HostUSBDevice *aDevice)
390{
391 /*
392 * Check preconditions.
393 */
394 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
395 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
396
397 AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
398 LogFlowThisFunc(("aDevice=%s\n", aDevice->i_getName().c_str()));
399
400 Assert(aDevice->i_getUnistate() == kHostUSBDeviceState_ReleasingToHost);
401 AssertReturn(aDevice->i_getUsbData(), VERR_INVALID_POINTER);
402
403 /*
404 * Create a one-shot ignore filter for the device and reset it.
405 */
406 USBFILTER Filter;
407 USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_IGNORE);
408 initFilterFromDevice(&Filter, aDevice);
409
410 void *pvId = USBLibAddFilter(&Filter);
411 if (!pvId)
412 {
413 LogRel(("USBService: Adding ignore filter failed!\n"));
414 return VERR_GENERAL_FAILURE;
415 }
416
417 PUSBDEVICE pDev = aDevice->i_getUsbData();
418 int rc = USBLibResetDevice(pDev->pszDevicePath, true /* Re-attach */);
419 if (RT_SUCCESS(rc))
420 aDevice->i_setBackendUserData(pvId);
421 else
422 {
423 USBLibRemoveFilter(pvId);
424 pvId = NULL;
425 }
426 LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
427 return rc;
428}
429
430
431void USBProxyBackendSolaris::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
432{
433 AssertReturnVoid(aDevice->isWriteLockOnCurrentThread());
434 /*
435 * Remove the one-shot filter if necessary.
436 */
437 LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->i_getName().c_str(), aSuccess, aDevice->i_getBackendUserData()));
438 if (!aSuccess && aDevice->i_getBackendUserData())
439 USBLibRemoveFilter(aDevice->i_getBackendUser());
440 aDevice->i_setBackendUserData(NULL);
441}
442
443
444bool USBProxyBackendSolaris::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
445 SessionMachine **aIgnoreMachine)
446{
447 AssertReturn(aDevice, false);
448 AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
449 return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
450}
451
452/**
453 * Wrapper called by walkDeviceNode.
454 *
455 * @param pDevice The USB device to free.
456 */
457void solarisFreeUSBDevice(PUSBDEVICE pDevice)
458{
459 USBProxyBackend::freeDevice(pDevice);
460}
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