VirtualBox

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

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

*: RTFILE becomes a pointer, RTFileOpen++ expands it's flags paramter from uint32_t to uint64_t.

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