VirtualBox

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

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

*: scm cleanup run.

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