VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/solaris/USBProxyDevice-solaris.cpp@ 55980

Last change on this file since 55980 was 55980, checked in by vboxsync, 10 years ago

iprt/log.h,++: Added extended logger instance getters that also checks whether the given logger and group-flags are enabled, making the LogRel* checks more efficient in avoid uncessary RTLogLoggerEx parameter building and calls. Ditto for debug logging. The LOG_INSTANCE and LOG_REL_INSTANCE tricks are gone for now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.7 KB
Line 
1/* $Id: USBProxyDevice-solaris.cpp 55980 2015-05-20 17:35:22Z vboxsync $ */
2/** @file
3 * USB device proxy - the Solaris backend.
4 */
5
6/*
7 * Copyright (C) 2009-2014 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#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23#include <sys/poll.h>
24#include <errno.h>
25#include <strings.h>
26#include <limits.h>
27
28#include <VBox/log.h>
29#include <VBox/err.h>
30#include <VBox/vmm/pdm.h>
31
32#include <iprt/string.h>
33#include <iprt/critsect.h>
34#include <iprt/time.h>
35#include <iprt/file.h>
36#include <iprt/mem.h>
37#include <iprt/pipe.h>
38#include "../USBProxyDevice.h"
39#include <VBox/usblib.h>
40
41/*******************************************************************************
42* Defined Constants And Macros *
43*******************************************************************************/
44/** Log Prefix. */
45#define USBPROXY "USBProxy"
46
47
48/*******************************************************************************
49* Structures and Typedefs *
50*******************************************************************************/
51/**
52 * Wrapper around the solaris urb request structure.
53 * This is required to track in-flight and landed URBs.
54 */
55typedef struct USBPROXYURBSOL
56{
57 /** Pointer to the Solaris device. */
58 struct USBPROXYDEVSOL *pDevSol;
59 /** Pointer to the VUSB URB (set to NULL if canceled). */
60 PVUSBURB pVUsbUrb;
61 /** Pointer to the next solaris URB. */
62 struct USBPROXYURBSOL *pNext;
63 /** Pointer to the previous solaris URB. */
64 struct USBPROXYURBSOL *pPrev;
65} USBPROXYURBSOL, *PUSBPROXYURBSOL;
66
67/**
68 * Data for the solaris usb proxy backend.
69 */
70typedef struct USBPROXYDEVSOL
71{
72 /** Path of the USB device in the devices tree (persistent). */
73 char *pszDevicePath;
74 /** The connection to the client driver. */
75 RTFILE hFile;
76 /** Pointer to the proxy device instance. */
77 PUSBPROXYDEV pProxyDev;
78 /** Critical section protecting the two lists. */
79 RTCRITSECT CritSect;
80 /** The list of free solaris URBs. Singly linked. */
81 PUSBPROXYURBSOL pFreeHead;
82 /** The list of active solaris URBs. Doubly linked.
83 * We must maintain this so we can properly reap URBs of a detached device.
84 * Only the split head will appear in this list. */
85 PUSBPROXYURBSOL pInFlightHead;
86 /** The list of landed solaris URBs. Doubly linked.
87 * Only the split head will appear in this list. */
88 PUSBPROXYURBSOL pTaxingHead;
89 /** The tail of the landed solaris URBs. */
90 PUSBPROXYURBSOL pTaxingTail;
91 /** Pipe handle for waking up - writing end. */
92 RTPIPE hPipeWakeupW;
93 /** Pipe handle for waking up - reading end. */
94 RTPIPE hPipeWakeupR;
95} USBPROXYDEVSOL, *PUSBPROXYDEVSOL;
96
97static PVUSBURB usbProxySolarisUrbComplete(PUSBPROXYDEVSOL pDevSol);
98
99
100/**
101 * Allocates a Solaris URB request structure.
102 *
103 * @returns Pointer to an active URB request.
104 * @returns NULL on failure.
105 *
106 * @param pDevSol The solaris USB device.
107 */
108static PUSBPROXYURBSOL usbProxySolarisUrbAlloc(PUSBPROXYDEVSOL pDevSol)
109{
110 PUSBPROXYURBSOL pUrbSol;
111
112 RTCritSectEnter(&pDevSol->CritSect);
113
114 /*
115 * Try remove a Solaris URB from the free list, if none there allocate a new one.
116 */
117 pUrbSol = pDevSol->pFreeHead;
118 if (pUrbSol)
119 pDevSol->pFreeHead = pUrbSol->pNext;
120 else
121 {
122 RTCritSectLeave(&pDevSol->CritSect);
123 pUrbSol = (PUSBPROXYURBSOL)RTMemAlloc(sizeof(*pUrbSol));
124 if (!pUrbSol)
125 return NULL;
126 RTCritSectEnter(&pDevSol->CritSect);
127 }
128 pUrbSol->pVUsbUrb = NULL;
129 pUrbSol->pDevSol = pDevSol;
130
131 /*
132 * Link it into the active list
133 */
134 pUrbSol->pPrev = NULL;
135 pUrbSol->pNext = pDevSol->pInFlightHead;
136 if (pUrbSol->pNext)
137 pUrbSol->pNext->pPrev = pUrbSol;
138 pDevSol->pInFlightHead = pUrbSol;
139
140 RTCritSectLeave(&pDevSol->CritSect);
141 return pUrbSol;
142}
143
144
145/**
146 * Frees a Solaris URB request structure.
147 *
148 * @param pDevSol The Solaris USB device.
149 * @param pUrbSol The Solaris URB to free.
150 */
151static void usbProxySolarisUrbFree(PUSBPROXYDEVSOL pDevSol, PUSBPROXYURBSOL pUrbSol)
152{
153 RTCritSectEnter(&pDevSol->CritSect);
154
155 /*
156 * Remove from the active or taxing list.
157 */
158 if (pUrbSol->pNext)
159 pUrbSol->pNext->pPrev = pUrbSol->pPrev;
160 else if (pDevSol->pTaxingTail == pUrbSol)
161 pDevSol->pTaxingTail = pUrbSol->pPrev;
162
163 if (pUrbSol->pPrev)
164 pUrbSol->pPrev->pNext = pUrbSol->pNext;
165 else if (pDevSol->pTaxingHead == pUrbSol)
166 pDevSol->pTaxingHead = pUrbSol->pNext;
167 else if (pDevSol->pInFlightHead == pUrbSol)
168 pDevSol->pInFlightHead = pUrbSol->pNext;
169 else
170 AssertFailed();
171
172 /*
173 * Link it into the free list.
174 */
175 pUrbSol->pPrev = NULL;
176 pUrbSol->pNext = pDevSol->pFreeHead;
177 pDevSol->pFreeHead = pUrbSol;
178
179 pUrbSol->pVUsbUrb = NULL;
180 pUrbSol->pDevSol = NULL;
181
182 RTCritSectLeave(&pDevSol->CritSect);
183}
184
185
186/*
187 * Close the connection to the USB client driver.
188 *
189 * This is required because our userland enumeration relies on drivers/device trees
190 * to recognize active devices, and hence if this device is unplugged we should no
191 * longer keep the client driver loaded.
192 */
193static void usbProxySolarisCloseFile(PUSBPROXYDEVSOL pDevSol)
194{
195 RTFileClose(pDevSol->hFile);
196 pDevSol->hFile = NIL_RTFILE;
197}
198
199
200/**
201 * The client driver IOCtl Wrapper function.
202 *
203 * @returns VBox status code.
204 * @param pDevSol The Solaris device instance.
205 * @param Function The Function.
206 * @param pvData Opaque pointer to the data.
207 * @param cbData Size of the data pointed to by pvData.
208 */
209static int usbProxySolarisIOCtl(PUSBPROXYDEVSOL pDevSol, unsigned Function, void *pvData, size_t cbData)
210{
211 if (RT_UNLIKELY(pDevSol->hFile == NIL_RTFILE))
212 {
213 LogFlow((USBPROXY ":usbProxySolarisIOCtl connection to driver gone!\n"));
214 return VERR_VUSB_DEVICE_NOT_ATTACHED;
215 }
216
217 VBOXUSBREQ Req;
218 Req.u32Magic = VBOXUSB_MAGIC;
219 Req.rc = -1;
220 Req.cbData = cbData;
221 Req.pvDataR3 = pvData;
222
223 int Ret = -1;
224 int rc = RTFileIoCtl(pDevSol->hFile, Function, &Req, sizeof(Req), &Ret);
225 if (RT_SUCCESS(rc))
226 {
227 if (RT_FAILURE(Req.rc))
228 {
229 if (Req.rc == VERR_VUSB_DEVICE_NOT_ATTACHED)
230 {
231 pDevSol->pProxyDev->fDetached = true;
232 usbProxySolarisCloseFile(pDevSol);
233 LogRel((USBPROXY ":Command %#x failed, USB Device '%s' disconnected!\n", Function, pDevSol->pProxyDev->pUsbIns->pszName));
234 }
235 else
236 LogRel((USBPROXY ":Command %#x failed. Req.rc=%Rrc\n", Function, Req.rc));
237 }
238
239 return Req.rc;
240 }
241
242 LogRel((USBPROXY ":Function %#x failed. rc=%Rrc\n", Function, rc));
243 return rc;
244}
245
246
247/**
248 * Get the active configuration from the device. The first time this is called
249 * our client driver would returned the cached configuration since the device is first plugged in.
250 * Subsequent get configuration requests are passed on to the device.
251 *
252 * @returns VBox status code.
253 * @param pDevSol The Solaris device instance.
254 *
255 */
256static inline int usbProxySolarisGetActiveConfig(PUSBPROXYDEVSOL pDevSol)
257{
258 VBOXUSBREQ_GET_CONFIG GetConfigReq;
259 bzero(&GetConfigReq, sizeof(GetConfigReq));
260 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_CONFIG, &GetConfigReq, sizeof(GetConfigReq));
261 if (RT_SUCCESS(rc))
262 {
263 pDevSol->pProxyDev->iActiveCfg = GetConfigReq.bConfigValue;
264 pDevSol->pProxyDev->cIgnoreSetConfigs = 0;
265 }
266 else
267 {
268 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
269 LogRel((USBPROXY ":Failed to get configuration. rc=%Rrc\n", rc));
270
271 pDevSol->pProxyDev->iActiveCfg = -1;
272 pDevSol->pProxyDev->cIgnoreSetConfigs = 0;
273 }
274 return rc;
275}
276
277
278/**
279 * Opens the USB device.
280 *
281 * @returns VBox status code.
282 * @param pProxyDev The device instance.
283 * @param pszAddress The unique device identifier.
284 * The format of this string is "VendorId:ProducIt:Release:StaticPath".
285 * @param pvBackend Backend specific pointer, unused for the solaris backend.
286 */
287static DECLCALLBACK(int) usbProxySolarisOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
288{
289 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
290
291 LogFlowFunc((USBPROXY ":usbProxySolarisOpen pProxyDev=%p pszAddress=%s pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
292
293 /*
294 * Initialize our USB R3 lib.
295 */
296 int rc = USBLibInit();
297 if (RT_SUCCESS(rc))
298 {
299 /*
300 * Allocate and initialize the solaris backend data.
301 */
302 AssertCompile(PATH_MAX >= MAXPATHLEN);
303 char szDeviceIdent[PATH_MAX+48];
304 rc = RTStrPrintf(szDeviceIdent, sizeof(szDeviceIdent), "%s", pszAddress);
305 if (RT_SUCCESS(rc))
306 {
307 rc = RTCritSectInit(&pDevSol->CritSect);
308 if (RT_SUCCESS(rc))
309 {
310 /*
311 * Create wakeup pipe.
312 */
313 rc = RTPipeCreate(&pDevSol->hPipeWakeupR, &pDevSol->hPipeWakeupW, 0);
314 if (RT_SUCCESS(rc))
315 {
316 int Instance;
317 char *pszDevicePath = NULL;
318 rc = USBLibGetClientInfo(szDeviceIdent, &pszDevicePath, &Instance);
319 if (RT_SUCCESS(rc))
320 {
321 pDevSol->pszDevicePath = pszDevicePath;
322
323 /*
324 * Open the client driver.
325 */
326 RTFILE hFile;
327 rc = RTFileOpen(&hFile, pDevSol->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
328 if (RT_SUCCESS(rc))
329 {
330 pDevSol->hFile = hFile;
331 pDevSol->pProxyDev = pProxyDev;
332
333 /*
334 * Verify client driver version.
335 */
336 VBOXUSBREQ_GET_VERSION GetVersionReq;
337 bzero(&GetVersionReq, sizeof(GetVersionReq));
338 rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_VERSION, &GetVersionReq, sizeof(GetVersionReq));
339 if (RT_SUCCESS(rc))
340 {
341 if ( GetVersionReq.u32Major == VBOXUSB_VERSION_MAJOR
342 && GetVersionReq.u32Minor >= VBOXUSB_VERSION_MINOR)
343 {
344 /*
345 * Try & get the current cached config from Solaris.
346 */
347 usbProxySolarisGetActiveConfig(pDevSol);
348 return VINF_SUCCESS;
349 }
350 else
351 {
352 LogRel((USBPROXY ":version mismatch! driver v%d.%d expecting ~v%d.%d\n", GetVersionReq.u32Major,
353 GetVersionReq.u32Minor, VBOXUSB_VERSION_MAJOR, VBOXUSB_VERSION_MINOR));
354 rc = VERR_VERSION_MISMATCH;
355 }
356 }
357 else
358 LogRel((USBPROXY ":failed to query driver version. rc=%Rrc\n", rc));
359
360 RTFileClose(pDevSol->hFile);
361 pDevSol->hFile = NIL_RTFILE;
362 pDevSol->pProxyDev = NULL;
363 }
364 else
365 LogRel((USBPROXY ":failed to open device. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath));
366
367 RTStrFree(pDevSol->pszDevicePath);
368 pDevSol->pszDevicePath = NULL;
369 }
370 else
371 {
372 LogRel((USBPROXY ":failed to get client info. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath));
373 if (rc == VERR_NOT_FOUND)
374 rc = VERR_OPEN_FAILED;
375 }
376 RTPipeClose(pDevSol->hPipeWakeupR);
377 RTPipeClose(pDevSol->hPipeWakeupW);
378 }
379
380 RTCritSectDelete(&pDevSol->CritSect);
381 }
382 else
383 LogRel((USBPROXY ":RTCritSectInit failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress));
384 }
385 else
386 LogRel((USBPROXY ":RTStrAPrintf failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress));
387 }
388 else
389 LogRel((USBPROXY ":USBLibInit failed. rc=%Rrc\n", rc));
390
391 USBLibTerm();
392 return rc;
393}
394
395
396/**
397 * Close the USB device.
398 *
399 * @param pProxyDev The device instance.
400 */
401static DECLCALLBACK(void) usbProxySolarisClose(PUSBPROXYDEV pProxyDev)
402{
403 LogFlow((USBPROXY ":usbProxySolarisClose: pProxyDev=%p\n", pProxyDev));
404
405 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
406
407 /* Close the device (do not re-enumerate). */
408 VBOXUSBREQ_CLOSE_DEVICE CloseReq;
409 CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_CLOSE;
410 usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
411
412 pProxyDev->fDetached = true;
413 usbProxySolarisCloseFile(pDevSol);
414
415 /*
416 * Now we can close it and free all the resources.
417 */
418 RTCritSectDelete(&pDevSol->CritSect);
419
420 PUSBPROXYURBSOL pUrbSol = NULL;
421 while ((pUrbSol = pDevSol->pInFlightHead) != NULL)
422 {
423 pDevSol->pInFlightHead = pUrbSol->pNext;
424 RTMemFree(pUrbSol);
425 }
426
427 while ((pUrbSol = pDevSol->pFreeHead) != NULL)
428 {
429 pDevSol->pFreeHead = pUrbSol->pNext;
430 RTMemFree(pUrbSol);
431 }
432
433 RTPipeClose(pDevSol->hPipeWakeupR);
434 RTPipeClose(pDevSol->hPipeWakeupW);
435
436 RTStrFree(pDevSol->pszDevicePath);
437 pDevSol->pszDevicePath = NULL;
438
439 USBLibTerm();
440}
441
442
443/**
444 * Reset the device.
445 *
446 * @returns VBox status code.
447 * @param pProxyDev The device to reset.
448 * @param fRootHubReset Is this a root hub reset or device specific reset request.
449 */
450static DECLCALLBACK(int) usbProxySolarisReset(PUSBPROXYDEV pProxyDev, bool fRootHubReset)
451{
452 LogFlowFunc((USBPROXY ":usbProxySolarisReset pProxyDev=%s fRootHubReset=%d\n", pProxyDev->pUsbIns->pszName, fRootHubReset));
453
454 /** Pass all resets to the device. The Trekstor USB (1.1) stick requires this to work. */
455 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
456
457 /* Soft reset the device. */
458 VBOXUSBREQ_CLOSE_DEVICE CloseReq;
459 CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_SOFT;
460 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
461 if (RT_SUCCESS(rc))
462 {
463 /* Get the active config. Solaris USBA sets a default config. */
464 usbProxySolarisGetActiveConfig(pDevSol);
465 }
466 else if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
467 LogRel((USBPROXY ":usbProxySolarisReset failed. rc=%d\n", rc));
468
469 return rc;
470}
471
472
473/**
474 * Set the active configuration.
475 *
476 * The caller makes sure that it's not called first time after open or reset
477 * with the active interface.
478 *
479 * @returns success indicator.
480 * @param pProxyDev The device instance data.
481 * @param iCfg The configuration value to set.
482 */
483static DECLCALLBACK(int) usbProxySolarisSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
484{
485 LogFlowFunc((USBPROXY ":usbProxySolarisSetConfig: pProxyDev=%p iCfg=%#x\n", pProxyDev, iCfg));
486
487 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
488 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
489
490 VBOXUSBREQ_SET_CONFIG SetConfigReq;
491 SetConfigReq.bConfigValue = iCfg;
492 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_CONFIG, &SetConfigReq, sizeof(SetConfigReq));
493 if ( RT_FAILURE(rc)
494 && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
495 LogRel((USBPROXY ":usbProxySolarisSetConfig failed to switch configuration. rc=%Rrc\n", rc));
496
497 return rc;
498}
499
500
501/**
502 * Claims an interface.
503 *
504 * This is a stub on Solaris since we release/claim all interfaces at
505 * as and when required with endpoint opens.
506 *
507 * @returns success indicator (always true).
508 */
509static DECLCALLBACK(int) usbProxySolarisClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
510{
511 return VINF_SUCCESS;
512}
513
514
515/**
516 * Releases an interface.
517 *
518 * This is a stub on Solaris since we release/claim all interfaces at
519 * as and when required with endpoint opens.
520 *
521 * @returns success indicator.
522 */
523static DECLCALLBACK(int) usbProxySolarisReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
524{
525 return VINF_SUCCESS;
526}
527
528
529/**
530 * Specify an alternate setting for the specified interface of the current configuration.
531 *
532 * @returns success indicator.
533 */
534static DECLCALLBACK(int) usbProxySolarisSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
535{
536 LogFlowFunc((USBPROXY ":usbProxySolarisSetInterface: pProxyDev=%p iIf=%d iAlt=%d\n", pProxyDev, iIf, iAlt));
537
538 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
539 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
540
541 VBOXUSBREQ_SET_INTERFACE SetInterfaceReq;
542 SetInterfaceReq.bInterface = iIf;
543 SetInterfaceReq.bAlternate = iAlt;
544 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_INTERFACE, &SetInterfaceReq, sizeof(SetInterfaceReq));
545 if ( RT_FAILURE(rc)
546 && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
547 LogRel((USBPROXY ":usbProxySolarisSetInterface failed to set interface. rc=%Rrc\n", rc));
548
549 return rc;
550}
551
552
553/**
554 * Clears the halted endpoint 'EndPt'.
555 */
556static DECLCALLBACK(int) usbProxySolarisClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
557{
558 LogFlowFunc((USBPROXY ":usbProxySolarisClearHaltedEp pProxyDev=%p EndPt=%#x\n", pProxyDev, EndPt));
559
560 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
561 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
562
563 VBOXUSBREQ_CLEAR_EP ClearEpReq;
564 ClearEpReq.bEndpoint = EndPt;
565 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLEAR_EP, &ClearEpReq, sizeof(ClearEpReq));
566 if ( RT_FAILURE(rc)
567 && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
568 LogRel((USBPROXY ":usbProxySolarisClearHaltedEp failed! rc=%Rrc\n", rc));
569
570 return rc;
571}
572
573
574/**
575 * @copydoc USBPROXYBACK::pfnUrbQueue
576 */
577static DECLCALLBACK(int) usbProxySolarisUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
578{
579 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
580
581 LogFlowFunc((USBPROXY ": usbProxySolarisUrbQueue: pProxyDev=%s pUrb=%p EndPt=%#x enmDir=%d cbData=%d pvData=%p\n",
582 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->enmDir, pUrb->cbData, pUrb->abData));
583
584 PUSBPROXYURBSOL pUrbSol = usbProxySolarisUrbAlloc(pDevSol);
585 if (RT_UNLIKELY(!pUrbSol))
586 {
587 LogRel((USBPROXY ":usbProxySolarisUrbQueue: Failed to allocate URB.\n"));
588 return VERR_NO_MEMORY;
589 }
590
591 pUrbSol->pVUsbUrb = pUrb;
592 pUrbSol->pDevSol = pDevSol;
593
594 uint8_t EndPt = pUrb->EndPt;
595 if (EndPt)
596 EndPt |= pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE;
597
598 VBOXUSBREQ_URB UrbReq;
599 UrbReq.pvUrbR3 = pUrbSol;
600 UrbReq.bEndpoint = EndPt;
601 UrbReq.enmType = pUrb->enmType;
602 UrbReq.enmDir = pUrb->enmDir;
603 UrbReq.enmStatus = pUrb->enmStatus;
604 UrbReq.fShortOk = !pUrb->fShortNotOk;
605 UrbReq.cbData = pUrb->cbData;
606 UrbReq.pvData = pUrb->abData;
607 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
608 {
609 UrbReq.cIsocPkts = pUrb->cIsocPkts;
610 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
611 {
612 UrbReq.aIsocPkts[i].cbPkt = pUrb->aIsocPkts[i].cb;
613 UrbReq.aIsocPkts[i].cbActPkt = 0;
614 UrbReq.aIsocPkts[i].enmStatus = VUSBSTATUS_INVALID;
615 }
616 }
617
618 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SEND_URB, &UrbReq, sizeof(UrbReq));
619 if (RT_SUCCESS(rc))
620 {
621 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
622 LogFlow((USBPROXY ":usbProxySolarisUrbQueue success cbData=%d.\n", pUrb->cbData));
623 pUrb->Dev.pvPrivate = pUrbSol;
624 return VINF_SUCCESS;
625 }
626
627 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
628 LogRel((USBPROXY ":usbProxySolarisUrbQueue Failed!! pProxyDev=%s pUrb=%p EndPt=%#x bEndpoint=%#x enmType=%d enmDir=%d cbData=%u rc=%Rrc\n",
629 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, UrbReq.bEndpoint, pUrb->enmType, pUrb->enmDir, pUrb->cbData, rc));
630
631 return rc;
632}
633
634
635/**
636 * Cancels a URB.
637 *
638 * The URB requires reaping, so we don't change its state.
639 * @remark There isn't any way to cancel a specific asynchronous request
640 * on Solaris. So we just abort pending URBs on the pipe.
641 */
642static DECLCALLBACK(int) usbProxySolarisUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
643{
644 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)pUrb->Dev.pvPrivate;
645 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
646 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
647
648 LogFlowFunc((USBPROXY ":usbProxySolarisUrbCancel pUrb=%p pUrbSol=%p pDevSol=%p\n", pUrb, pUrbSol, pUrbSol->pDevSol));
649
650 /* Aborting the control pipe isn't supported, pretend success. */
651 if (!pUrb->EndPt)
652 return VINF_SUCCESS;
653
654 VBOXUSBREQ_ABORT_PIPE AbortPipeReq;
655 AbortPipeReq.bEndpoint = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE);
656 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_ABORT_PIPE, &AbortPipeReq, sizeof(AbortPipeReq));
657 if ( RT_FAILURE(rc)
658 && rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
659 LogRel((USBPROXY ":usbProxySolarisUrbCancel failed to abort pipe. rc=%Rrc\n", rc));
660
661 LogFlow((USBPROXY ":usbProxySolarisUrbCancel: rc=%Rrc.\n", rc));
662 return rc;
663}
664
665
666/**
667 * Reap URBs in-flight on a device.
668 *
669 * @returns Pointer to a completed URB.
670 * @returns NULL if no URB was completed.
671 * @param pProxyDev The device.
672 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
673 */
674static DECLCALLBACK(PVUSBURB) usbProxySolarisUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
675{
676 //LogFlowFunc((USBPROXY ":usbProxySolarisUrbReap pProxyDev=%p cMillies=%u\n", pProxyDev, cMillies));
677
678 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
679
680 /*
681 * Don't block if nothing is in the air.
682 */
683 if (!pDevSol->pInFlightHead)
684 return NULL;
685
686 /*
687 * Deque URBs inflight or those landed.
688 */
689 if (cMillies > 0)
690 {
691 for (;;)
692 {
693 int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies;
694 struct pollfd pfd[2];
695
696 pfd[0].fd = RTFileToNative(pDevSol->hFile);
697 pfd[0].events = POLLIN;
698 pfd[0].revents = 0;
699
700 pfd[1].fd = RTPipeToNative(pDevSol->hPipeWakeupR);
701 pfd[1].events = POLLIN;
702 pfd[1].revents = 0;
703
704 int rc = poll(&pfd[0], 2, cMilliesWait);
705 if (rc > 0)
706 {
707 if (pfd[0].revents & POLLHUP)
708 {
709 LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName));
710 pProxyDev->fDetached = true;
711 usbProxySolarisCloseFile(pDevSol);
712 }
713
714 if (pfd[1].revents & POLLIN)
715 {
716 /* Got woken up, drain pipe. */
717 uint8_t bRead;
718 size_t cbIgnored = 0;
719 RTPipeRead(pDevSol->hPipeWakeupR, &bRead, 1, &cbIgnored);
720
721 /*
722 * It is possible that we got woken up and have an URB pending
723 * for completion. Do it on the way out. Otherwise return
724 * immediately to the caller.
725 */
726 if (!(pfd[0].revents & POLLIN))
727 return NULL;
728 }
729
730 break;
731 }
732
733 if (rc == 0)
734 {
735 //LogFlow((USBPROXY ":usbProxySolarisUrbReap: Timed out\n"));
736 return NULL;
737 }
738 else if (rc != EAGAIN)
739 {
740 LogFlow((USBPROXY ":usbProxySolarisUrbReap Poll rc=%d errno=%d\n", rc, errno));
741 return NULL;
742 }
743 }
744 }
745
746 usbProxySolarisUrbComplete(pDevSol);
747
748 /*
749 * Any URBs pending delivery?
750 */
751 PVUSBURB pUrb = NULL;
752 while (pDevSol->pTaxingHead)
753 {
754 RTCritSectEnter(&pDevSol->CritSect);
755
756 PUSBPROXYURBSOL pUrbSol = pDevSol->pTaxingHead;
757 if (pUrbSol)
758 {
759 pUrb = pUrbSol->pVUsbUrb;
760 if (pUrb)
761 {
762 pUrb->Dev.pvPrivate = NULL;
763 usbProxySolarisUrbFree(pDevSol, pUrbSol);
764 }
765 }
766 RTCritSectLeave(&pDevSol->CritSect);
767 }
768
769 return pUrb;
770}
771
772
773/**
774 * Reads a completed/error'd URB from the client driver (no waiting).
775 *
776 * @param pDevSol The Solaris device instance.
777 */
778static PVUSBURB usbProxySolarisUrbComplete(PUSBPROXYDEVSOL pDevSol)
779{
780 LogFlowFunc((USBPROXY ":usbProxySolarisUrbComplete pDevSol=%p\n", pDevSol));
781
782 VBOXUSBREQ_URB UrbReq;
783 bzero(&UrbReq, sizeof(UrbReq));
784
785 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_REAP_URB, &UrbReq, sizeof(UrbReq));
786 if (RT_SUCCESS(rc))
787 {
788 if (UrbReq.pvUrbR3)
789 {
790 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)UrbReq.pvUrbR3;
791 PVUSBURB pUrb = pUrbSol->pVUsbUrb;
792 if (RT_LIKELY(pUrb))
793 {
794 Assert(pUrb->u32Magic == VUSBURB_MAGIC);
795
796 /*
797 * Update the URB.
798 */
799 if ( pUrb->enmType == VUSBXFERTYPE_ISOC
800 && pUrb->enmDir == VUSBDIRECTION_IN)
801 {
802 size_t cbData = 0;
803 for (unsigned i = 0; i < UrbReq.cIsocPkts; i++)
804 {
805 pUrb->aIsocPkts[i].cb = UrbReq.aIsocPkts[i].cbActPkt;
806 cbData += UrbReq.aIsocPkts[i].cbActPkt;
807 pUrb->aIsocPkts[i].enmStatus = UrbReq.aIsocPkts[i].enmStatus;
808 }
809
810 LogFlow((USBPROXY ":usbProxySolarisUrbComplete ISOC cbData=%d cbActPktSum=%d\n", pUrb->cbData, cbData));
811 pUrb->cbData = cbData;
812 pUrb->enmStatus = UrbReq.enmStatus;
813 }
814 else
815 {
816 pUrb->cbData = UrbReq.cbData;
817 pUrb->enmStatus = UrbReq.enmStatus;
818 }
819
820 RTCritSectEnter(&pDevSol->CritSect);
821
822 /*
823 * Remove from the active list.
824 */
825 if (pUrbSol->pNext)
826 pUrbSol->pNext->pPrev = pUrbSol->pPrev;
827 if (pUrbSol->pPrev)
828 pUrbSol->pPrev->pNext = pUrbSol->pNext;
829 else
830 {
831 Assert(pDevSol->pInFlightHead == pUrbSol);
832 pDevSol->pInFlightHead = pUrbSol->pNext;
833 }
834
835 /*
836 * Link it into the taxing list.
837 */
838 pUrbSol->pNext = NULL;
839 pUrbSol->pPrev = pDevSol->pTaxingTail;
840 if (pDevSol->pTaxingTail)
841 pDevSol->pTaxingTail->pNext = pUrbSol;
842 else
843 pDevSol->pTaxingHead = pUrbSol;
844 pDevSol->pTaxingTail = pUrbSol;
845
846 RTCritSectLeave(&pDevSol->CritSect);
847
848 LogFlow((USBPROXY "usbProxySolarisUrbComplete: cb=%d EndPt=%#x enmDir=%d enmStatus=%s (%d) \n",
849 pUrb->cbData, pUrb->EndPt, pUrb->enmDir, pUrb->enmStatus == VUSBSTATUS_OK ? "OK" : "** Failed **", pUrb->enmStatus));
850// if (pUrb->cbData < 2049)
851// LogFlow((USBPROXY "%.*Rhxd\n", pUrb->cbData, pUrb->abData));
852 return pUrb;
853 }
854 }
855 }
856 else
857 {
858 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
859 LogRel((USBPROXY ":Reaping URB failed. rc=%Rrc\n", rc));
860 }
861
862 return NULL;
863}
864
865
866static DECLCALLBACK(int) usbProxySolarisWakeup(PUSBPROXYDEV pProxyDev)
867{
868 PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
869 size_t cbIgnored;
870
871 LogFlowFunc(("pProxyDev=%p\n", pProxyDev));
872
873 return RTPipeWrite(pDevSol->hPipeWakeupW, "", 1, &cbIgnored);
874}
875
876
877/**
878 * The Solaris USB Proxy Backend.
879 */
880extern const USBPROXYBACK g_USBProxyDeviceHost =
881{
882 /* pszName */
883 "host",
884 /* cbBackend */
885 sizeof(USBPROXYDEVSOL),
886 usbProxySolarisOpen,
887 NULL,
888 usbProxySolarisClose,
889 usbProxySolarisReset,
890 usbProxySolarisSetConfig,
891 usbProxySolarisClaimInterface,
892 usbProxySolarisReleaseInterface,
893 usbProxySolarisSetInterface,
894 usbProxySolarisClearHaltedEp,
895 usbProxySolarisUrbQueue,
896 usbProxySolarisUrbCancel,
897 usbProxySolarisUrbReap,
898 usbProxySolarisWakeup,
899 0
900};
901
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