VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/solaris/USBProxyServiceSolaris.cpp@ 37599

Last change on this file since 37599 was 37599, checked in by vboxsync, 14 years ago

Main/USBProxyService: implementation inheritance is not so great that we have to pretend to do it when we are not

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/* $Id: USBProxyServiceSolaris.cpp 37599 2011-06-22 21:06:38Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service, Solaris Specialization.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 "USBProxyService.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* Internal Functions *
36*******************************************************************************/
37static int solarisWalkDeviceNode(di_node_t Node, void *pvArg);
38static void solarisFreeUSBDevice(PUSBDEVICE pDevice);
39static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node_t Node);
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef struct USBDEVICELIST
46{
47 PUSBDEVICE pHead;
48 PUSBDEVICE pTail;
49} USBDEVICELIST;
50typedef USBDEVICELIST *PUSBDEVICELIST;
51
52
53/**
54 * Initialize data members.
55 */
56USBProxyServiceSolaris::USBProxyServiceSolaris (Host *aHost)
57 : USBProxyService (aHost), mUSBLibInitialized(false)
58{
59 LogFlowThisFunc(("aHost=%p\n", aHost));
60}
61
62
63/**
64 * Initializes the object (called right after construction).
65 *
66 * @returns S_OK on success and non-fatal failures, some COM error otherwise.
67 */
68HRESULT USBProxyServiceSolaris::init(void)
69{
70 /*
71 * Create semaphore.
72 */
73 int rc = RTSemEventCreate(&mNotifyEventSem);
74 if (RT_FAILURE(rc))
75 {
76 mLastError = rc;
77 return E_FAIL;
78 }
79
80 /*
81 * Initialize the USB library.
82 */
83 rc = USBLibInit();
84 if (RT_FAILURE(rc))
85 {
86 mLastError = rc;
87 return S_OK;
88 }
89 mUSBLibInitialized = true;
90
91 /*
92 * Start the poller thread.
93 */
94 start();
95 return S_OK;
96}
97
98
99/**
100 * Stop all service threads and free the device chain.
101 */
102USBProxyServiceSolaris::~USBProxyServiceSolaris()
103{
104 LogFlowThisFunc(("destruct\n"));
105
106 /*
107 * Stop the service.
108 */
109 if (isActive())
110 stop();
111
112 /*
113 * Terminate the USB library
114 */
115 if (mUSBLibInitialized)
116 {
117 USBLibTerm();
118 mUSBLibInitialized = false;
119 }
120
121 RTSemEventDestroy(mNotifyEventSem);
122 mNotifyEventSem = NULL;
123}
124
125
126void *USBProxyServiceSolaris::insertFilter(PCUSBFILTER aFilter)
127{
128 return USBLibAddFilter(aFilter);
129}
130
131
132void USBProxyServiceSolaris::removeFilter(void *pvID)
133{
134 USBLibRemoveFilter(pvID);
135}
136
137
138int USBProxyServiceSolaris::wait(RTMSINTERVAL aMillies)
139{
140 return RTSemEventWait(mNotifyEventSem, aMillies < 1000 ? 1000 : RT_MIN(aMillies, 5000));
141}
142
143
144int USBProxyServiceSolaris::interruptWait(void)
145{
146 return RTSemEventSignal(mNotifyEventSem);
147}
148
149
150PUSBDEVICE USBProxyServiceSolaris::getDevices(void)
151{
152 USBDEVICELIST DevList;
153 DevList.pHead = NULL;
154 DevList.pTail = NULL;
155 di_node_t RootNode = di_init("/", DINFOCPYALL);
156 if (RootNode != DI_NODE_NIL)
157 di_walk_node(RootNode, DI_WALK_CLDFIRST, &DevList, solarisWalkDeviceNode);
158
159 di_fini(RootNode);
160 return DevList.pHead;
161}
162
163#if 0
164static int solarisWalkMinor(di_node_t Node, di_minor_t Minor, void *pvArg)
165{
166 char *pszDevFsPath = di_devfs_path(Node);
167 char *pszMinorName = di_minor_name(Minor);
168 PUSBDEVICE pDev = (PUSBDEVICE)pvArg;
169
170 AssertRelease(pDev);
171
172 if (!pszDevFsPath || !pszMinorName)
173 return DI_WALK_CONTINUE;
174
175 RTStrAPrintf(&pDev->pszApId, "/devices%s:%s", pszDevFsPath, pszMinorName);
176 di_devfs_path_free(pszDevFsPath);
177
178 syslog(LOG_ERR, "VBoxUsbApId:%s\n", pDev->pszApId);
179 return DI_WALK_TERMINATE;
180}
181
182static bool solarisGetApId(PUSBDEVICE pDev, char *pszDevicePath, di_node_t RootNode)
183{
184 pDev->pszApId = NULL;
185
186 /* Skip "/devices" prefix if any */
187 char achDevicesDir[] = "/devices/";
188 if (strncmp(pszDevicePath, achDevicesDir, sizeof(achDevicesDir)) == 0)
189 pszDevicePath += sizeof(achDevicesDir);
190
191 char *pszPhysical = RTStrDup(pszDevicePath);
192 char *pszTmp = NULL;
193
194 /* Remove dynamic component "::" if any */
195 if ((pszTmp = strstr(pszPhysical, "::")) != NULL)
196 *pszTmp = '\0';
197
198 /* Remove minor name if any */
199 if ((pszTmp = strrchr(pszPhysical, ':')) != NULL)
200 *pszTmp = '\0';
201
202 /* Walk device tree */
203// di_node_t RootNode = di_init("/", DINFOCPYALL);
204// if (RootNode != DI_NODE_NIL)
205// {
206// di_node_t MinorNode = di_lookup_node(RootNode, pszPhysical);
207// if (MinorNode != DI_NODE_NIL)
208 {
209 di_walk_minor(RootNode, NULL, DI_CHECK_ALIAS | DI_CHECK_INTERNAL_PATH, pDev, solarisWalkMinor);
210 return true;
211 }
212// di_fini(RootNode);
213// }
214
215 return false;
216}
217#endif
218
219static int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
220{
221 PUSBDEVICELIST pList = (PUSBDEVICELIST)pvArg;
222 AssertPtrReturn(pList, DI_WALK_TERMINATE);
223
224 /*
225 * Check if it's a USB device in the first place.
226 */
227 bool fUSBDevice = false;
228 char *pszCompatNames = NULL;
229 int cCompatNames = di_compatible_names(Node, &pszCompatNames);
230 for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1)
231 if (!strncmp(pszCompatNames, "usb", 3))
232 {
233 fUSBDevice = true;
234 break;
235 }
236
237 if (!fUSBDevice)
238 return DI_WALK_CONTINUE;
239
240 /*
241 * Check if it's a device node or interface.
242 */
243 int *pInt = NULL;
244 char *pStr = NULL;
245 int rc = DI_WALK_CONTINUE;
246 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "interface", &pInt) < 0)
247 {
248 /* It's a device node. */
249 char *pszDevicePath = di_devfs_path(Node);
250 PUSBDEVICE pCur = (PUSBDEVICE)RTMemAllocZ(sizeof(*pCur));
251 if (!pCur)
252 {
253 LogRel(("USBService: failed to allocate %d bytes for PUSBDEVICE.\n", sizeof(*pCur)));
254 return DI_WALK_TERMINATE;
255 }
256
257 bool fValidDevice = false;
258 do
259 {
260 AssertBreak(pszDevicePath);
261
262 char *pszDriverName = di_driver_name(Node);
263
264 /*
265 * Skip hubs
266 */
267 if ( pszDriverName
268 && !strcmp(pszDriverName, "hubd"))
269 {
270 break;
271 }
272
273 /*
274 * Mandatory.
275 * snv_85 and above have usb-dev-descriptor node properties, but older one's do not.
276 * So if we cannot obtain the entire device descriptor, we try falling back to the
277 * individual properties (those must not fail, if it does we drop the device).
278 */
279 uchar_t *pDevData = NULL;
280 int cbProp = di_prop_lookup_bytes(DDI_DEV_T_ANY, Node, "usb-dev-descriptor", &pDevData);
281 if ( cbProp > 0
282 && pDevData)
283 {
284 usb_dev_descr_t *pDeviceDescriptor = (usb_dev_descr_t *)pDevData;
285 pCur->bDeviceClass = pDeviceDescriptor->bDeviceClass;
286 pCur->bDeviceSubClass = pDeviceDescriptor->bDeviceSubClass;
287 pCur->bDeviceProtocol = pDeviceDescriptor->bDeviceProtocol;
288 pCur->idVendor = pDeviceDescriptor->idVendor;
289 pCur->idProduct = pDeviceDescriptor->idProduct;
290 pCur->bcdDevice = pDeviceDescriptor->bcdDevice;
291 pCur->bcdUSB = pDeviceDescriptor->bcdUSB;
292 pCur->bNumConfigurations = pDeviceDescriptor->bNumConfigurations;
293 pCur->fPartialDescriptor = false;
294 }
295 else
296 {
297 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-vendor-id", &pInt) > 0);
298 pCur->idVendor = (uint16_t)*pInt;
299
300 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-product-id", &pInt) > 0);
301 pCur->idProduct = (uint16_t)*pInt;
302
303 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-revision-id", &pInt) > 0);
304 pCur->bcdDevice = (uint16_t)*pInt;
305
306 AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-release", &pInt) > 0);
307 pCur->bcdUSB = (uint16_t)*pInt;
308
309 pCur->fPartialDescriptor = true;
310 }
311
312 char *pszPortAddr = di_bus_addr(Node);
313 if (pszPortAddr)
314 pCur->bPort = RTStrToUInt8(pszPortAddr); /* Bus & Port are mixed up (kernel driver/userland) */
315 else
316 pCur->bPort = 0;
317
318#if 0
319 /*
320 * Obtain the dev_t of the device.
321 */
322 di_minor_t Minor = di_minor_next(Node, DI_MINOR_NIL);
323 AssertBreak(Minor != DI_MINOR_NIL);
324 dev_t DeviceNum = di_minor_devt(Minor);
325
326 int DevInstance = 0;
327 rc = solarisUSBGetInstance(pszDevicePath, &DevInstance);
328
329 char szAddress[PATH_MAX + 128];
330 RTStrPrintf(szAddress, sizeof(szAddress), "/dev/usb/%x.%x|%s", pCur->idVendor, pCur->idProduct, pszDevicePath);
331 /* @todo after binding ugen we need to append the instance number to the address. Not yet sure how we can update PUSBDEVICE at that time. */
332
333 pCur->pszAddress = RTStrDup(szAddress);
334 AssertBreak(pCur->pszAddress);
335#endif
336
337 char pathBuf[PATH_MAX];
338 RTStrPrintf(pathBuf, sizeof(pathBuf), "%s", pszDevicePath);
339 RTPathStripFilename(pathBuf);
340
341 char szBuf[PATH_MAX + 48];
342 RTStrPrintf(szBuf, sizeof(szBuf), "%#x:%#x:%d:%s", pCur->idVendor, pCur->idProduct, pCur->bcdDevice, pathBuf);
343 pCur->pszAddress = RTStrDup(szBuf);
344
345 pCur->pszDevicePath = RTStrDup(pszDevicePath);
346 AssertBreak(pCur->pszDevicePath);
347
348 /*
349 * Optional (some devices don't have all these)
350 */
351 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-product-name", &pStr) > 0)
352 pCur->pszProduct = RTStrDup(pStr);
353
354 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-vendor-name", &pStr) > 0)
355 pCur->pszManufacturer = RTStrDup(pStr);
356
357 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-serialno", &pStr) > 0)
358 pCur->pszSerialNumber = RTStrDup(pStr);
359
360 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "low-speed", &pInt) >= 0)
361 pCur->enmSpeed = USBDEVICESPEED_LOW;
362 else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "high-speed", &pInt) >= 0)
363 pCur->enmSpeed = USBDEVICESPEED_HIGH;
364 else
365 pCur->enmSpeed = USBDEVICESPEED_FULL;
366
367 /* Determine state of the USB device. */
368 pCur->enmState = solarisDetermineUSBDeviceState(pCur, Node);
369
370// fValidDevice = solarisGetApId(pCur, pszDevicePath, Node);
371 fValidDevice = true;
372
373 /*
374 * Valid device, add it to the list.
375 */
376 if (fValidDevice)
377 {
378 pCur->pPrev = pList->pTail;
379 if (pList->pTail)
380 pList->pTail = pList->pTail->pNext = pCur;
381 else
382 pList->pTail = pList->pHead = pCur;
383 }
384 rc = DI_WALK_CONTINUE;
385 } while(0);
386
387 di_devfs_path_free(pszDevicePath);
388 if (!fValidDevice)
389 solarisFreeUSBDevice(pCur);
390 }
391 return rc;
392}
393
394
395static USBDEVICESTATE solarisDetermineUSBDeviceState(PUSBDEVICE pDevice, di_node_t Node)
396{
397 char *pszDriverName = di_driver_name(Node);
398
399 /* Not possible unless a user explicitly unbinds the default driver. */
400 if (!pszDriverName)
401 return USBDEVICESTATE_UNUSED;
402
403 if (!strncmp(pszDriverName, VBOXUSB_DRIVER_NAME, sizeof(VBOXUSB_DRIVER_NAME) - 1))
404 return USBDEVICESTATE_HELD_BY_PROXY;
405
406 NOREF(pDevice);
407 return USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
408}
409
410
411int USBProxyServiceSolaris::captureDevice(HostUSBDevice *aDevice)
412{
413 /*
414 * Check preconditions.
415 */
416 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
417 LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str()));
418 AssertReturn(aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
419 Assert(aDevice->getUnistate() == kHostUSBDeviceState_Capturing);
420 AssertReturn(aDevice->mUsb, VERR_INVALID_POINTER);
421
422 /*
423 * Create a one-shot capture filter for the device and reset the device.
424 */
425 USBFILTER Filter;
426 USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_CAPTURE);
427 initFilterFromDevice(&Filter, aDevice);
428
429 void *pvId = USBLibAddFilter(&Filter);
430 if (!pvId)
431 {
432 LogRel(("USBService: failed to add filter\n"));
433 return VERR_GENERAL_FAILURE;
434 }
435
436 PUSBDEVICE pDev = aDevice->mUsb;
437 int rc = USBLibResetDevice(pDev->pszDevicePath, true);
438 if (RT_SUCCESS(rc))
439 aDevice->mOneShotId = pvId;
440 else
441 {
442 USBLibRemoveFilter(pvId);
443 pvId = NULL;
444 }
445 LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
446 return rc;
447}
448
449
450void USBProxyServiceSolaris::captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
451{
452 /*
453 * Remove the one-shot filter if necessary.
454 */
455 LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->getName().c_str(), aSuccess, aDevice->mOneShotId));
456 if (!aSuccess && aDevice->mOneShotId)
457 USBLibRemoveFilter(aDevice->mOneShotId);
458 aDevice->mOneShotId = NULL;
459}
460
461
462int USBProxyServiceSolaris::releaseDevice(HostUSBDevice *aDevice)
463{
464 /*
465 * Check preconditions.
466 */
467 AssertReturn(aDevice, VERR_GENERAL_FAILURE);
468 LogFlowThisFunc(("aDevice=%s\n", aDevice->getName().c_str()));
469 AssertReturn(aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
470 Assert(aDevice->getUnistate() == kHostUSBDeviceState_ReleasingToHost);
471 AssertReturn(aDevice->mUsb, VERR_INVALID_POINTER);
472
473 /*
474 * Create a one-shot ignore filter for the device and reset it.
475 */
476 USBFILTER Filter;
477 USBFilterInit(&Filter, USBFILTERTYPE_ONESHOT_IGNORE);
478 initFilterFromDevice(&Filter, aDevice);
479
480 void *pvId = USBLibAddFilter(&Filter);
481 if (!pvId)
482 {
483 LogRel(("USBService: Adding ignore filter failed!\n"));
484 return VERR_GENERAL_FAILURE;
485 }
486
487 PUSBDEVICE pDev = aDevice->mUsb;
488 int rc = USBLibResetDevice(pDev->pszDevicePath, true /* Re-attach */);
489 if (RT_SUCCESS(rc))
490 aDevice->mOneShotId = pvId;
491 else
492 {
493 USBLibRemoveFilter(pvId);
494 pvId = NULL;
495 }
496 LogFlowThisFunc(("returns %Rrc pvId=%p\n", rc, pvId));
497 return rc;
498}
499
500
501void USBProxyServiceSolaris::releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess)
502{
503 /*
504 * Remove the one-shot filter if necessary.
505 */
506 LogFlowThisFunc(("aDevice=%s aSuccess=%RTbool mOneShotId=%p\n", aDevice->getName().c_str(), aSuccess, aDevice->mOneShotId));
507 if (!aSuccess && aDevice->mOneShotId)
508 USBLibRemoveFilter(aDevice->mOneShotId);
509 aDevice->mOneShotId = NULL;
510}
511
512
513bool USBProxyServiceSolaris::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
514{
515 return USBProxyService::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
516}
517
518/**
519 * Wrapper called by walkDeviceNode.
520 *
521 * @param pDevice The USB device to free.
522 */
523void solarisFreeUSBDevice(PUSBDEVICE pDevice)
524{
525 USBProxyService::freeDevice(pDevice);
526}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette