VirtualBox

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

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

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

  • 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 35346 2010-12-27 16:13:13Z 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 File;
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 if (pDevSol->File != NIL_RTFILE)
199 {
200 RTFileClose(pDevSol->File);
201 pDevSol->File = NIL_RTFILE;
202 }
203}
204
205
206/**
207 * The client driver IOCtl Wrapper function.
208 *
209 * @returns VBox status code.
210 * @param pDevSol The Solaris device instance.
211 * @param Function The Function.
212 * @param pvData Opaque pointer to the data.
213 * @param cbData Size of the data pointed to by pvData.
214 */
215static int usbProxySolarisIOCtl(PUSBPROXYDEVSOL pDevSol, unsigned Function, void *pvData, size_t cbData)
216{
217 if (RT_UNLIKELY(pDevSol->File == NIL_RTFILE))
218 {
219 LogFlow((USBPROXY ":usbProxySolarisIOCtl connection to driver gone!\n"));
220 return VERR_VUSB_DEVICE_NOT_ATTACHED;
221 }
222
223 VBOXUSBREQ Req;
224 Req.u32Magic = VBOXUSB_MAGIC;
225 Req.rc = -1;
226 Req.cbData = cbData;
227 Req.pvDataR3 = pvData;
228
229 int Ret = -1;
230 int rc = RTFileIoCtl(pDevSol->File, Function, &Req, sizeof(Req), &Ret);
231 if (RT_SUCCESS(rc))
232 {
233 if (RT_FAILURE(Req.rc))
234 {
235 if (Req.rc == VERR_VUSB_DEVICE_NOT_ATTACHED)
236 {
237 pDevSol->pProxyDev->fDetached = true;
238 usbProxySolarisCloseFile(pDevSol);
239 LogRel((USBPROXY ":Command %#x failed, USB Device '%s' disconnected!\n", Function, pDevSol->pProxyDev->pUsbIns->pszName));
240 }
241 else
242 LogRel((USBPROXY ":Command %#x failed. Req.rc=%Rrc\n", Function, Req.rc));
243 }
244
245 return Req.rc;
246 }
247
248 LogRel((USBPROXY ":Function %#x failed. rc=%Rrc\n", Function, rc));
249 return rc;
250}
251
252
253/**
254 * Get the active configuration from the device. The first time this is called
255 * our client driver would returned the cached configuration since the device is first plugged in.
256 * Subsequent get configuration requests are passed on to the device.
257 *
258 * @returns VBox status code.
259 * @param pDevSol The Solaris device instance.
260 *
261 */
262static inline int usbProxySolarisGetActiveConfig(PUSBPROXYDEVSOL pDevSol)
263{
264 VBOXUSBREQ_GET_CONFIG GetConfigReq;
265 bzero(&GetConfigReq, sizeof(GetConfigReq));
266 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_CONFIG, &GetConfigReq, sizeof(GetConfigReq));
267 if (RT_SUCCESS(rc))
268 {
269 pDevSol->pProxyDev->iActiveCfg = GetConfigReq.bConfigValue;
270 pDevSol->pProxyDev->cIgnoreSetConfigs = 0;
271 }
272 else
273 {
274 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
275 LogRel((USBPROXY ":Failed to get configuration. rc=%Rrc\n", rc));
276
277 pDevSol->pProxyDev->iActiveCfg = -1;
278 pDevSol->pProxyDev->cIgnoreSetConfigs = 0;
279 }
280 return rc;
281}
282
283
284/**
285 * Opens the USB device.
286 *
287 * @returns VBox status code.
288 * @param pProxyDev The device instance.
289 * @param pszAddress The unique device identifier.
290 * The format of this string is "VendorId:ProducIt:Release:StaticPath".
291 * @param pvBackend Backend specific pointer, unused for the solaris backend.
292 */
293static int usbProxySolarisOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
294{
295 LogFlowFunc((USBPROXY ":usbProxySolarisOpen pProxyDev=%p pszAddress=%s pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
296
297 /*
298 * Initialize our USB R3 lib.
299 */
300 int rc = USBLibInit();
301 if (RT_SUCCESS(rc))
302 {
303 /*
304 * Allocate and initialize the solaris backend data.
305 */
306 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)RTMemAllocZ(sizeof(*pDevSol));
307 if (RT_LIKELY(pDevSol))
308 {
309 AssertCompile(PATH_MAX >= MAXPATHLEN);
310 char szDeviceIdent[PATH_MAX+48];
311 rc = RTStrPrintf(szDeviceIdent, sizeof(szDeviceIdent), "%s", pszAddress);
312 if (RT_SUCCESS(rc))
313 {
314 rc = RTCritSectInit(&pDevSol->CritSect);
315 if (RT_SUCCESS(rc))
316 {
317 pProxyDev->Backend.pv = pDevSol;
318
319 int Instance;
320 char *pszDevicePath = NULL;
321 rc = USBLibGetClientInfo(szDeviceIdent, &pszDevicePath, &Instance);
322 if (RT_SUCCESS(rc))
323 {
324 pDevSol->pszDevicePath = pszDevicePath;
325
326 /*
327 * Open the client driver.
328 */
329 RTFILE File;
330 rc = RTFileOpen(&File, pDevSol->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
331 if (RT_SUCCESS(rc))
332 {
333 pDevSol->File = File;
334 pDevSol->pProxyDev = pProxyDev;
335
336 /*
337 * Verify client driver version.
338 */
339 VBOXUSBREQ_GET_VERSION GetVersionReq;
340 bzero(&GetVersionReq, sizeof(GetVersionReq));
341 rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_GET_VERSION, &GetVersionReq, sizeof(GetVersionReq));
342 if (RT_SUCCESS(rc))
343 {
344 if ( GetVersionReq.u32Major == VBOXUSB_VERSION_MAJOR
345 && GetVersionReq.u32Minor >= VBOXUSB_VERSION_MINOR)
346 {
347 /*
348 * Try & get the current cached config from Solaris.
349 */
350 usbProxySolarisGetActiveConfig(pDevSol);
351 return VINF_SUCCESS;
352 }
353 else
354 {
355 LogRel((USBPROXY ":version mismatch! driver v%d.%d expecting ~v%d.%d\n", GetVersionReq.u32Major,
356 GetVersionReq.u32Minor, VBOXUSB_VERSION_MAJOR, VBOXUSB_VERSION_MINOR));
357 rc = VERR_VERSION_MISMATCH;
358 }
359 }
360 else
361 {
362 LogRel((USBPROXY ":failed to query driver version. rc=%Rrc\n", rc));
363 }
364
365 RTFileClose(pDevSol->File);
366 pDevSol->File = NIL_RTFILE;
367 pDevSol->pProxyDev = NULL;
368 }
369 else
370 LogRel((USBPROXY ":failed to open device. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath));
371
372 RTStrFree(pDevSol->pszDevicePath);
373 pDevSol->pszDevicePath = NULL;
374 }
375 else
376 {
377 LogRel((USBPROXY ":failed to get client info. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath));
378 if (rc == VERR_NOT_FOUND)
379 rc = VERR_OPEN_FAILED;
380 }
381
382 RTCritSectDelete(&pDevSol->CritSect);
383 }
384 else
385 LogRel((USBPROXY ":RTCritSectInit failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress));
386 }
387 else
388 LogRel((USBPROXY ":RTStrAPrintf failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress));
389
390 RTMemFree(pDevSol);
391 pDevSol = NULL;
392 }
393 else
394 rc = VERR_NO_MEMORY;
395 }
396 else
397 LogRel((USBPROXY ":USBLibInit failed. rc=%Rrc\n", rc));
398
399 USBLibTerm();
400 pProxyDev->Backend.pv = NULL;
401 return rc;
402}
403
404
405/**
406 * Close the USB device.
407 *
408 * @param pProxyDev The device instance.
409 */
410static void usbProxySolarisClose(PUSBPROXYDEV pProxyDev)
411{
412 LogFlow((USBPROXY ":usbProxySolarisClose: pProxyDev=%p\n", pProxyDev));
413
414 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
415
416 /* Close the device (do not re-enumerate). */
417 VBOXUSBREQ_CLOSE_DEVICE CloseReq;
418 CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_NONE;
419 usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
420
421 pProxyDev->fDetached = true;
422 usbProxySolarisCloseFile(pDevSol);
423
424 /*
425 * Now we can close it and free all the resources.
426 */
427 RTCritSectDelete(&pDevSol->CritSect);
428
429 PUSBPROXYURBSOL pUrbSol = NULL;
430 while ((pUrbSol = pDevSol->pInFlightHead) != NULL)
431 {
432 pDevSol->pInFlightHead = pUrbSol->pNext;
433 RTMemFree(pUrbSol);
434 }
435
436 while ((pUrbSol = pDevSol->pFreeHead) != NULL)
437 {
438 pDevSol->pFreeHead = pUrbSol->pNext;
439 RTMemFree(pUrbSol);
440 }
441
442 RTStrFree(pDevSol->pszDevicePath);
443 pDevSol->pszDevicePath = NULL;
444
445 RTMemFree(pDevSol);
446 pProxyDev->Backend.pv = NULL;
447
448 USBLibTerm();
449}
450
451
452/**
453 * Reset the device.
454 *
455 * @returns VBox status code.
456 * @param pProxyDev The device to reset.
457 * @param fRootHubReset Is this a root hub reset or device specific reset request.
458 */
459static int usbProxySolarisReset(PUSBPROXYDEV pProxyDev, bool fRootHubReset)
460{
461 LogFlowFunc((USBPROXY ":usbProxySolarisReset pProxyDev=%s fRootHubReset=%d\n", pProxyDev->pUsbIns->pszName, fRootHubReset));
462
463 /** Pass all resets to the device. The Trekstor USB (1.1) stick requires this to work. */
464 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
465
466 /* Soft reset the device. */
467 VBOXUSBREQ_CLOSE_DEVICE CloseReq;
468 CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_SOFT;
469 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
470 if (RT_SUCCESS(rc))
471 {
472 /* Get the active config. Solaris USBA sets a default config. */
473 usbProxySolarisGetActiveConfig(pDevSol);
474 }
475 else if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
476 LogRel((USBPROXY ":usbProxySolarisReset failed. rc=%d\n", rc));
477
478 return rc;
479}
480
481
482/**
483 * Set the active configuration.
484 *
485 * The caller makes sure that it's not called first time after open or reset
486 * with the active interface.
487 *
488 * @returns success indicator.
489 * @param pProxyDev The device instance data.
490 * @param iCfg The configuration value to set.
491 */
492static int usbProxySolarisSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
493{
494 LogFlowFunc((USBPROXY ":usbProxySolarisSetConfig: pProxyDev=%p iCfg=%#x\n", pProxyDev, iCfg));
495
496 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
497 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
498
499 VBOXUSBREQ_SET_CONFIG SetConfigReq;
500 SetConfigReq.bConfigValue = iCfg;
501 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_CONFIG, &SetConfigReq, sizeof(SetConfigReq));
502 if (RT_SUCCESS(rc))
503 return true;
504
505 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
506 LogRel((USBPROXY ":usbProxySolarisSetConfig failed to switch configuration. rc=%Rrc\n", rc));
507
508 return false;
509}
510
511
512/**
513 * Claims an interface.
514 *
515 * This is a stub on Solaris since we release/claim all interfaces at
516 * as and when required with endpoint opens.
517 *
518 * @returns success indicator (always true).
519 */
520static int usbProxySolarisClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
521{
522 return true;
523}
524
525
526/**
527 * Releases an interface.
528 *
529 * This is a stub on Solaris since we release/claim all interfaces at
530 * as and when required with endpoint opens.
531 *
532 * @returns success indicator.
533 */
534static int usbProxySolarisReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
535{
536 return true;
537}
538
539
540/**
541 * Specify an alternate setting for the specified interface of the current configuration.
542 *
543 * @returns success indicator.
544 */
545static int usbProxySolarisSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
546{
547 LogFlowFunc((USBPROXY ":usbProxySolarisSetInterface: pProxyDev=%p iIf=%d iAlt=%d\n", pProxyDev, iIf, iAlt));
548
549 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
550 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
551
552 VBOXUSBREQ_SET_INTERFACE SetInterfaceReq;
553 SetInterfaceReq.bInterface = iIf;
554 SetInterfaceReq.bAlternate = iAlt;
555 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_INTERFACE, &SetInterfaceReq, sizeof(SetInterfaceReq));
556 if (RT_SUCCESS(rc))
557 return true;
558
559 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
560 LogRel((USBPROXY ":usbProxySolarisSetInterface failed to set interface. rc=%Rrc\n", rc));
561
562 return false;
563}
564
565
566/**
567 * Clears the halted endpoint 'EndPt'.
568 */
569static bool usbProxySolarisClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
570{
571 LogFlowFunc((USBPROXY ":usbProxySolarisClearHaltedEp pProxyDev=%p EndPt=%#x\n", pProxyDev, EndPt));
572
573 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
574 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
575
576 VBOXUSBREQ_CLEAR_EP ClearEpReq;
577 ClearEpReq.bEndpoint = EndPt;
578 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLEAR_EP, &ClearEpReq, sizeof(ClearEpReq));
579 if (RT_SUCCESS(rc))
580 return true;
581
582 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
583 LogRel((USBPROXY ":usbProxySolarisClearHaltedEp failed! rc=%Rrc\n", rc));
584
585 return false;
586}
587
588
589/**
590 * @copydoc USBPROXYBACK::pfnUrbQueue
591 */
592static int usbProxySolarisUrbQueue(PVUSBURB pUrb)
593{
594 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
595 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
596
597 LogFlowFunc((USBPROXY ": usbProxySolarisUrbQueue: pProxyDev=%s pUrb=%p EndPt=%#x enmDir=%d cbData=%d pvData=%p\n",
598 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->enmDir, pUrb->cbData, pUrb->abData));
599
600 // Enable Isoc. Xfers
601#if 0
602 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
603 {
604 /* Not yet complete (disabled for now) */
605 LogFlow((USBPROXY ":usbProxySolarisUrbQueue: Isoc. Xfers not supported\n"));
606 return false;
607 }
608#endif
609
610 PUSBPROXYURBSOL pUrbSol = usbProxySolarisUrbAlloc(pDevSol);
611 if (RT_UNLIKELY(!pUrbSol))
612 {
613 LogRel((USBPROXY ":usbProxySolarisUrbQueue: Failed to allocate URB.\n"));
614 return false;
615 }
616
617 pUrbSol->pVUsbUrb = pUrb;
618 pUrbSol->pDevSol = pDevSol;
619
620 uint8_t EndPt = pUrb->EndPt;
621 if (EndPt)
622 EndPt |= pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE;
623
624 VBOXUSBREQ_URB UrbReq;
625 UrbReq.pvUrbR3 = pUrbSol;
626 UrbReq.bEndpoint = EndPt;
627 UrbReq.enmType = pUrb->enmType;
628 UrbReq.enmDir = pUrb->enmDir;
629 UrbReq.enmStatus = pUrb->enmStatus;
630 UrbReq.cbData = pUrb->cbData;
631 UrbReq.pvData = pUrb->abData;
632 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
633 {
634 UrbReq.cIsocPkts = pUrb->cIsocPkts;
635 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
636 {
637 UrbReq.aIsocPkts[i].cbPkt = pUrb->aIsocPkts[i].cb;
638 UrbReq.aIsocPkts[i].cbActPkt = 0;
639 UrbReq.aIsocPkts[i].enmStatus = VUSBSTATUS_INVALID;
640 }
641 }
642
643 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SEND_URB, &UrbReq, sizeof(UrbReq));
644 if (RT_SUCCESS(rc))
645 {
646 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
647 LogFlow((USBPROXY ":usbProxySolarisUrbQueue success cbData=%d.\n", pUrb->cbData));
648 pUrb->Dev.pvPrivate = pUrbSol;
649 return true;
650 }
651
652 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
653 LogRel((USBPROXY ":usbProxySolarisUrbQueue Failed!! pProxyDev=%s pUrb=%p EndPt=%#x bEndpoint=%#x enmType=%d enmDir=%d cbData=%u rc=%Rrc\n",
654 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, UrbReq.bEndpoint, pUrb->enmType, pUrb->enmDir, pUrb->cbData, rc));
655
656 return false;
657}
658
659
660/**
661 * Cancels a URB.
662 *
663 * The URB requires reaping, so we don't change its state.
664 * @remark There isn't any way to cancel a specific asynchronous request
665 * on Solaris. So we just abort pending URBs on the pipe.
666 */
667static void usbProxySolarisUrbCancel(PVUSBURB pUrb)
668{
669 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)pUrb->Dev.pvPrivate;
670
671 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
672 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
673 AssertPtrReturnVoid(pDevSol);
674
675 LogFlowFunc((USBPROXY ":usbProxySolarisUrbCancel pUrb=%p pUrbSol=%p pDevSol=%p\n", pUrb, pUrbSol, pUrbSol->pDevSol));
676
677 /* Aborting the control pipe isn't supported, pretend success. */
678 if (!pUrb->EndPt)
679 return;
680
681 VBOXUSBREQ_ABORT_PIPE AbortPipeReq;
682 AbortPipeReq.bEndpoint = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE);
683 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_ABORT_PIPE, &AbortPipeReq, sizeof(AbortPipeReq));
684 if (RT_FAILURE(rc))
685 {
686 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
687 LogRel((USBPROXY ":usbProxySolarisUrbCancel failed to abort pipe. rc=%Rrc\n", rc));
688 return;
689 }
690
691 LogFlow((USBPROXY ":usbProxySolarisUrbCancel success.\n", rc));
692}
693
694
695/**
696 * Reap URBs in-flight on a device.
697 *
698 * @returns Pointer to a completed URB.
699 * @returns NULL if no URB was completed.
700 * @param pProxyDev The device.
701 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
702 */
703static PVUSBURB usbProxySolarisUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
704{
705 //LogFlowFunc((USBPROXY ":usbProxySolarisUrbReap pProxyDev=%p cMillies=%u\n", pProxyDev, cMillies));
706
707 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
708
709 /*
710 * Don't block if nothing is in the air.
711 */
712 if (!pDevSol->pInFlightHead)
713 return NULL;
714
715 /*
716 * Deque URBs inflight or those landed.
717 */
718 if (cMillies > 0)
719 {
720 for (;;)
721 {
722 struct pollfd pfd;
723 int rc;
724
725 pfd.fd = pDevSol->File;
726 pfd.events = POLLIN;
727 pfd.revents = 0;
728 rc = poll(&pfd, 1, cMillies);
729
730 if (rc > 0)
731 {
732 if (pfd.revents & POLLHUP)
733 {
734 LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName));
735 pProxyDev->fDetached = true;
736 usbProxySolarisCloseFile(pDevSol);
737 }
738 break;
739 }
740
741 if (rc == 0)
742 {
743 //LogFlow((USBPROXY ":usbProxySolarisUrbReap: Timed out\n"));
744 return NULL;
745 }
746 else if (rc != EAGAIN)
747 {
748 LogFlow((USBPROXY ":usbProxySolarisUrbReap Poll rc=%d errno=%d\n", rc, errno));
749 return NULL;
750 }
751 }
752 }
753
754 usbProxySolarisUrbComplete(pDevSol);
755
756 /*
757 * Any URBs pending delivery?
758 */
759 PVUSBURB pUrb = NULL;
760 while (pDevSol->pTaxingHead)
761 {
762 RTCritSectEnter(&pDevSol->CritSect);
763
764 PUSBPROXYURBSOL pUrbSol = pDevSol->pTaxingHead;
765 if (pUrbSol)
766 {
767 pUrb = pUrbSol->pVUsbUrb;
768 if (pUrb)
769 {
770 pUrb->Dev.pvPrivate = NULL;
771 usbProxySolarisUrbFree(pDevSol, pUrbSol);
772 }
773 }
774 RTCritSectLeave(&pDevSol->CritSect);
775 }
776
777 return pUrb;
778}
779
780
781/**
782 * Reads a completed/error'd URB from the client driver (no waiting).
783 *
784 * @param pDevSol The Solaris device instance.
785 */
786PVUSBURB usbProxySolarisUrbComplete(PUSBPROXYDEVSOL pDevSol)
787{
788 LogFlowFunc((USBPROXY ":usbProxySolarisUrbComplete pDevSol=%p\n", pDevSol));
789
790 VBOXUSBREQ_URB UrbReq;
791 bzero(&UrbReq, sizeof(UrbReq));
792
793 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_REAP_URB, &UrbReq, sizeof(UrbReq));
794 if (RT_SUCCESS(rc))
795 {
796 if (UrbReq.pvUrbR3)
797 {
798 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)UrbReq.pvUrbR3;
799 PVUSBURB pUrb = pUrbSol->pVUsbUrb;
800 if (RT_LIKELY(pUrb))
801 {
802 Assert(pUrb->u32Magic == VUSBURB_MAGIC);
803
804 /*
805 * Update the URB.
806 */
807 if ( pUrb->enmType == VUSBXFERTYPE_ISOC
808 && pUrb->enmDir == VUSBDIRECTION_IN)
809 {
810 size_t cbData = 0;
811 for (unsigned i = 0; i < UrbReq.cIsocPkts; i++)
812 {
813 pUrb->aIsocPkts[i].cb = UrbReq.aIsocPkts[i].cbActPkt;
814 cbData += UrbReq.aIsocPkts[i].cbActPkt;
815 pUrb->aIsocPkts[i].enmStatus = UrbReq.aIsocPkts[i].enmStatus;
816 }
817
818 LogFlow((USBPROXY ":usbProxySolarisUrbComplete ISOC cbData=%d cbActPktSum=%d\n", pUrb->cbData, cbData));
819 pUrb->cbData = cbData;
820 pUrb->enmStatus = UrbReq.enmStatus;
821 }
822 else
823 {
824 pUrb->cbData = UrbReq.cbData;
825 pUrb->enmStatus = UrbReq.enmStatus;
826 }
827
828 RTCritSectEnter(&pDevSol->CritSect);
829
830 /*
831 * Remove from the active list.
832 */
833 if (pUrbSol->pNext)
834 pUrbSol->pNext->pPrev = pUrbSol->pPrev;
835 if (pUrbSol->pPrev)
836 pUrbSol->pPrev->pNext = pUrbSol->pNext;
837 else
838 {
839 Assert(pDevSol->pInFlightHead == pUrbSol);
840 pDevSol->pInFlightHead = pUrbSol->pNext;
841 }
842
843 /*
844 * Link it into the taxing list.
845 */
846 pUrbSol->pNext = NULL;
847 pUrbSol->pPrev = pDevSol->pTaxingTail;
848 if (pDevSol->pTaxingTail)
849 pDevSol->pTaxingTail->pNext = pUrbSol;
850 else
851 pDevSol->pTaxingHead = pUrbSol;
852 pDevSol->pTaxingTail = pUrbSol;
853
854 RTCritSectLeave(&pDevSol->CritSect);
855
856 LogFlow((USBPROXY "usbProxySolarisUrbComplete: cb=%d EndPt=%#x enmDir=%d enmStatus=%s (%d) \n",
857 pUrb->cbData, pUrb->EndPt, pUrb->enmDir, pUrb->enmStatus == VUSBSTATUS_OK ? "OK" : "** Failed **", pUrb->enmStatus));
858// if (pUrb->cbData < 2049)
859// LogFlow((USBPROXY "%.*Rhxd\n", pUrb->cbData, pUrb->abData));
860 return pUrb;
861 }
862 }
863 }
864 else
865 {
866 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
867 LogRel((USBPROXY ":Reaping URB failed. rc=%Rrc\n", rc));
868 }
869
870 return NULL;
871}
872
873
874
875/**
876 * The Solaris USB Proxy Backend.
877 */
878extern const USBPROXYBACK g_USBProxyDeviceHost =
879{
880 "host",
881 usbProxySolarisOpen,
882 NULL,
883 usbProxySolarisClose,
884 usbProxySolarisReset,
885 usbProxySolarisSetConfig,
886 usbProxySolarisClaimInterface,
887 usbProxySolarisReleaseInterface,
888 usbProxySolarisSetInterface,
889 usbProxySolarisClearHaltedEp,
890 usbProxySolarisUrbQueue,
891 usbProxySolarisUrbCancel,
892 usbProxySolarisUrbReap,
893 NULL
894};
895
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