VirtualBox

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

Last change on this file since 45733 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

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