VirtualBox

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

Last change on this file since 50228 was 50228, checked in by vboxsync, 11 years ago

USB/Proxy: Start a source code cleanup, remove unused struct members and make the generic proxy code do the backend specific memory allocation (fixes a small memory leak in the VRDP backend when closing a proxy device)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.9 KB
Line 
1/* $Id: USBProxyDevice-solaris.cpp 50228 2014-01-24 21:16:37Z vboxsync $ */
2/** @file
3 * USB device proxy - the Solaris backend.
4 */
5
6/*
7 * Copyright (C) 2009-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.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 <iprt/pipe.h>
41#include "../USBProxyDevice.h"
42#include <VBox/usblib.h>
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** Log Prefix. */
48#define USBPROXY "USBProxy"
49
50
51/*******************************************************************************
52* Structures and Typedefs *
53*******************************************************************************/
54/**
55 * Wrapper around the solaris urb request structure.
56 * This is required to track in-flight and landed URBs.
57 */
58typedef struct USBPROXYURBSOL
59{
60 /** Pointer to the Solaris device. */
61 struct USBPROXYDEVSOL *pDevSol;
62 /** Pointer to the VUSB URB (set to NULL if canceled). */
63 PVUSBURB pVUsbUrb;
64 /** Pointer to the next solaris URB. */
65 struct USBPROXYURBSOL *pNext;
66 /** Pointer to the previous solaris URB. */
67 struct USBPROXYURBSOL *pPrev;
68} USBPROXYURBSOL, *PUSBPROXYURBSOL;
69
70/**
71 * Data for the solaris usb proxy backend.
72 */
73typedef struct USBPROXYDEVSOL
74{
75 /** Path of the USB device in the devices tree (persistent). */
76 char *pszDevicePath;
77 /** The connection to the client driver. */
78 RTFILE hFile;
79 /** Pointer to the proxy device instance. */
80 PUSBPROXYDEV pProxyDev;
81 /** Critical section protecting the two lists. */
82 RTCRITSECT CritSect;
83 /** The list of free solaris URBs. Singly linked. */
84 PUSBPROXYURBSOL pFreeHead;
85 /** The list of active solaris URBs. Doubly linked.
86 * We must maintain this so we can properly reap URBs of a detached device.
87 * Only the split head will appear in this list. */
88 PUSBPROXYURBSOL pInFlightHead;
89 /** The list of landed solaris URBs. Doubly linked.
90 * Only the split head will appear in this list. */
91 PUSBPROXYURBSOL pTaxingHead;
92 /** The tail of the landed solaris URBs. */
93 PUSBPROXYURBSOL pTaxingTail;
94 /** Pipe handle for waking up - writing end. */
95 RTPIPE hPipeWakeupW;
96 /** Pipe handle for waking up - reading end. */
97 RTPIPE hPipeWakeupR;
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 DECLCALLBACK(int) usbProxySolarisOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
291{
292 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
293
294 LogFlowFunc((USBPROXY ":usbProxySolarisOpen pProxyDev=%p pszAddress=%s pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
295
296 /*
297 * Initialize our USB R3 lib.
298 */
299 int rc = USBLibInit();
300 if (RT_SUCCESS(rc))
301 {
302 /*
303 * Allocate and initialize the solaris backend data.
304 */
305 AssertCompile(PATH_MAX >= MAXPATHLEN);
306 char szDeviceIdent[PATH_MAX+48];
307 rc = RTStrPrintf(szDeviceIdent, sizeof(szDeviceIdent), "%s", pszAddress);
308 if (RT_SUCCESS(rc))
309 {
310 rc = RTCritSectInit(&pDevSol->CritSect);
311 if (RT_SUCCESS(rc))
312 {
313 /*
314 * Create wakeup pipe.
315 */
316 rc = RTPipeCreate(&pDevSol->hPipeWakeupR, &pDevSol->hPipeWakeupW, 0);
317 if (RT_SUCCESS(rc))
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 hFile;
330 rc = RTFileOpen(&hFile, pDevSol->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
331 if (RT_SUCCESS(rc))
332 {
333 pDevSol->hFile = hFile;
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 LogRel((USBPROXY ":failed to query driver version. rc=%Rrc\n", rc));
362
363 RTFileClose(pDevSol->hFile);
364 pDevSol->hFile = NIL_RTFILE;
365 pDevSol->pProxyDev = NULL;
366 }
367 else
368 LogRel((USBPROXY ":failed to open device. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath));
369
370 RTStrFree(pDevSol->pszDevicePath);
371 pDevSol->pszDevicePath = NULL;
372 }
373 else
374 {
375 LogRel((USBPROXY ":failed to get client info. rc=%Rrc pszDevicePath=%s\n", rc, pDevSol->pszDevicePath));
376 if (rc == VERR_NOT_FOUND)
377 rc = VERR_OPEN_FAILED;
378 }
379 RTPipeClose(pDevSol->hPipeWakeupR);
380 RTPipeClose(pDevSol->hPipeWakeupW);
381 }
382
383 RTCritSectDelete(&pDevSol->CritSect);
384 }
385 else
386 LogRel((USBPROXY ":RTCritSectInit failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress));
387 }
388 else
389 LogRel((USBPROXY ":RTStrAPrintf failed. rc=%Rrc pszAddress=%s\n", rc, pszAddress));
390 }
391 else
392 LogRel((USBPROXY ":USBLibInit failed. rc=%Rrc\n", rc));
393
394 USBLibTerm();
395 return rc;
396}
397
398
399/**
400 * Close the USB device.
401 *
402 * @param pProxyDev The device instance.
403 */
404static DECLCALLBACK(void) usbProxySolarisClose(PUSBPROXYDEV pProxyDev)
405{
406 LogFlow((USBPROXY ":usbProxySolarisClose: pProxyDev=%p\n", pProxyDev));
407
408 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
409
410 /* Close the device (do not re-enumerate). */
411 VBOXUSBREQ_CLOSE_DEVICE CloseReq;
412 CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_CLOSE;
413 usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
414
415 pProxyDev->fDetached = true;
416 usbProxySolarisCloseFile(pDevSol);
417
418 /*
419 * Now we can close it and free all the resources.
420 */
421 RTCritSectDelete(&pDevSol->CritSect);
422
423 PUSBPROXYURBSOL pUrbSol = NULL;
424 while ((pUrbSol = pDevSol->pInFlightHead) != NULL)
425 {
426 pDevSol->pInFlightHead = pUrbSol->pNext;
427 RTMemFree(pUrbSol);
428 }
429
430 while ((pUrbSol = pDevSol->pFreeHead) != NULL)
431 {
432 pDevSol->pFreeHead = pUrbSol->pNext;
433 RTMemFree(pUrbSol);
434 }
435
436 RTPipeClose(pDevSol->hPipeWakeupR);
437 RTPipeClose(pDevSol->hPipeWakeupW);
438
439 RTStrFree(pDevSol->pszDevicePath);
440 pDevSol->pszDevicePath = NULL;
441
442 USBLibTerm();
443}
444
445
446/**
447 * Reset the device.
448 *
449 * @returns VBox status code.
450 * @param pProxyDev The device to reset.
451 * @param fRootHubReset Is this a root hub reset or device specific reset request.
452 */
453static DECLCALLBACK(int) usbProxySolarisReset(PUSBPROXYDEV pProxyDev, bool fRootHubReset)
454{
455 LogFlowFunc((USBPROXY ":usbProxySolarisReset pProxyDev=%s fRootHubReset=%d\n", pProxyDev->pUsbIns->pszName, fRootHubReset));
456
457 /** Pass all resets to the device. The Trekstor USB (1.1) stick requires this to work. */
458 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
459
460 /* Soft reset the device. */
461 VBOXUSBREQ_CLOSE_DEVICE CloseReq;
462 CloseReq.ResetLevel = VBOXUSB_RESET_LEVEL_SOFT;
463 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLOSE_DEVICE, &CloseReq, sizeof(CloseReq));
464 if (RT_SUCCESS(rc))
465 {
466 /* Get the active config. Solaris USBA sets a default config. */
467 usbProxySolarisGetActiveConfig(pDevSol);
468 }
469 else if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
470 LogRel((USBPROXY ":usbProxySolarisReset failed. rc=%d\n", rc));
471
472 return rc;
473}
474
475
476/**
477 * Set the active configuration.
478 *
479 * The caller makes sure that it's not called first time after open or reset
480 * with the active interface.
481 *
482 * @returns success indicator.
483 * @param pProxyDev The device instance data.
484 * @param iCfg The configuration value to set.
485 */
486static DECLCALLBACK(int) usbProxySolarisSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
487{
488 LogFlowFunc((USBPROXY ":usbProxySolarisSetConfig: pProxyDev=%p iCfg=%#x\n", pProxyDev, iCfg));
489
490 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
491 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
492
493 VBOXUSBREQ_SET_CONFIG SetConfigReq;
494 SetConfigReq.bConfigValue = iCfg;
495 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_CONFIG, &SetConfigReq, sizeof(SetConfigReq));
496 if (RT_SUCCESS(rc))
497 return true;
498
499 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
500 LogRel((USBPROXY ":usbProxySolarisSetConfig failed to switch configuration. rc=%Rrc\n", rc));
501
502 return false;
503}
504
505
506/**
507 * Claims an interface.
508 *
509 * This is a stub on Solaris since we release/claim all interfaces at
510 * as and when required with endpoint opens.
511 *
512 * @returns success indicator (always true).
513 */
514static DECLCALLBACK(int) usbProxySolarisClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
515{
516 return true;
517}
518
519
520/**
521 * Releases an interface.
522 *
523 * This is a stub on Solaris since we release/claim all interfaces at
524 * as and when required with endpoint opens.
525 *
526 * @returns success indicator.
527 */
528static DECLCALLBACK(int) usbProxySolarisReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
529{
530 return true;
531}
532
533
534/**
535 * Specify an alternate setting for the specified interface of the current configuration.
536 *
537 * @returns success indicator.
538 */
539static DECLCALLBACK(int) usbProxySolarisSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
540{
541 LogFlowFunc((USBPROXY ":usbProxySolarisSetInterface: pProxyDev=%p iIf=%d iAlt=%d\n", pProxyDev, iIf, iAlt));
542
543 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
544 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
545
546 VBOXUSBREQ_SET_INTERFACE SetInterfaceReq;
547 SetInterfaceReq.bInterface = iIf;
548 SetInterfaceReq.bAlternate = iAlt;
549 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SET_INTERFACE, &SetInterfaceReq, sizeof(SetInterfaceReq));
550 if (RT_SUCCESS(rc))
551 return true;
552
553 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
554 LogRel((USBPROXY ":usbProxySolarisSetInterface failed to set interface. rc=%Rrc\n", rc));
555
556 return false;
557}
558
559
560/**
561 * Clears the halted endpoint 'EndPt'.
562 */
563static DECLCALLBACK(bool) usbProxySolarisClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
564{
565 LogFlowFunc((USBPROXY ":usbProxySolarisClearHaltedEp pProxyDev=%p EndPt=%#x\n", pProxyDev, EndPt));
566
567 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
568 AssertPtrReturn(pDevSol, VERR_INVALID_POINTER);
569
570 VBOXUSBREQ_CLEAR_EP ClearEpReq;
571 ClearEpReq.bEndpoint = EndPt;
572 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_CLEAR_EP, &ClearEpReq, sizeof(ClearEpReq));
573 if (RT_SUCCESS(rc))
574 return true;
575
576 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
577 LogRel((USBPROXY ":usbProxySolarisClearHaltedEp failed! rc=%Rrc\n", rc));
578
579 return false;
580}
581
582
583/**
584 * @copydoc USBPROXYBACK::pfnUrbQueue
585 */
586static DECLCALLBACK(int) usbProxySolarisUrbQueue(PVUSBURB pUrb)
587{
588 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
589 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
590
591 LogFlowFunc((USBPROXY ": usbProxySolarisUrbQueue: pProxyDev=%s pUrb=%p EndPt=%#x enmDir=%d cbData=%d pvData=%p\n",
592 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->enmDir, pUrb->cbData, pUrb->abData));
593
594 PUSBPROXYURBSOL pUrbSol = usbProxySolarisUrbAlloc(pDevSol);
595 if (RT_UNLIKELY(!pUrbSol))
596 {
597 LogRel((USBPROXY ":usbProxySolarisUrbQueue: Failed to allocate URB.\n"));
598 return false;
599 }
600
601 pUrbSol->pVUsbUrb = pUrb;
602 pUrbSol->pDevSol = pDevSol;
603
604 uint8_t EndPt = pUrb->EndPt;
605 if (EndPt)
606 EndPt |= pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE;
607
608 VBOXUSBREQ_URB UrbReq;
609 UrbReq.pvUrbR3 = pUrbSol;
610 UrbReq.bEndpoint = EndPt;
611 UrbReq.enmType = pUrb->enmType;
612 UrbReq.enmDir = pUrb->enmDir;
613 UrbReq.enmStatus = pUrb->enmStatus;
614 UrbReq.fShortOk = !pUrb->fShortNotOk;
615 UrbReq.cbData = pUrb->cbData;
616 UrbReq.pvData = pUrb->abData;
617 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
618 {
619 UrbReq.cIsocPkts = pUrb->cIsocPkts;
620 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
621 {
622 UrbReq.aIsocPkts[i].cbPkt = pUrb->aIsocPkts[i].cb;
623 UrbReq.aIsocPkts[i].cbActPkt = 0;
624 UrbReq.aIsocPkts[i].enmStatus = VUSBSTATUS_INVALID;
625 }
626 }
627
628 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_SEND_URB, &UrbReq, sizeof(UrbReq));
629 if (RT_SUCCESS(rc))
630 {
631 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
632 LogFlow((USBPROXY ":usbProxySolarisUrbQueue success cbData=%d.\n", pUrb->cbData));
633 pUrb->Dev.pvPrivate = pUrbSol;
634 return true;
635 }
636
637 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
638 LogRel((USBPROXY ":usbProxySolarisUrbQueue Failed!! pProxyDev=%s pUrb=%p EndPt=%#x bEndpoint=%#x enmType=%d enmDir=%d cbData=%u rc=%Rrc\n",
639 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, UrbReq.bEndpoint, pUrb->enmType, pUrb->enmDir, pUrb->cbData, rc));
640
641 return false;
642}
643
644
645/**
646 * Cancels a URB.
647 *
648 * The URB requires reaping, so we don't change its state.
649 * @remark There isn't any way to cancel a specific asynchronous request
650 * on Solaris. So we just abort pending URBs on the pipe.
651 */
652static DECLCALLBACK(void) usbProxySolarisUrbCancel(PVUSBURB pUrb)
653{
654 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)pUrb->Dev.pvPrivate;
655
656 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
657 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
658 AssertPtrReturnVoid(pDevSol);
659
660 LogFlowFunc((USBPROXY ":usbProxySolarisUrbCancel pUrb=%p pUrbSol=%p pDevSol=%p\n", pUrb, pUrbSol, pUrbSol->pDevSol));
661
662 /* Aborting the control pipe isn't supported, pretend success. */
663 if (!pUrb->EndPt)
664 return;
665
666 VBOXUSBREQ_ABORT_PIPE AbortPipeReq;
667 AbortPipeReq.bEndpoint = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? VUSB_DIR_TO_HOST : VUSB_DIR_TO_DEVICE);
668 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_ABORT_PIPE, &AbortPipeReq, sizeof(AbortPipeReq));
669 if (RT_FAILURE(rc))
670 {
671 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
672 LogRel((USBPROXY ":usbProxySolarisUrbCancel failed to abort pipe. rc=%Rrc\n", rc));
673 return;
674 }
675
676 LogFlow((USBPROXY ":usbProxySolarisUrbCancel success.\n", rc));
677}
678
679
680/**
681 * Reap URBs in-flight on a device.
682 *
683 * @returns Pointer to a completed URB.
684 * @returns NULL if no URB was completed.
685 * @param pProxyDev The device.
686 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
687 */
688static DECLCALLBACK(PVUSBURB) usbProxySolarisUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
689{
690 //LogFlowFunc((USBPROXY ":usbProxySolarisUrbReap pProxyDev=%p cMillies=%u\n", pProxyDev, cMillies));
691
692 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
693
694 /*
695 * Don't block if nothing is in the air.
696 */
697 if (!pDevSol->pInFlightHead)
698 return NULL;
699
700 /*
701 * Deque URBs inflight or those landed.
702 */
703 if (cMillies > 0)
704 {
705 for (;;)
706 {
707 int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies;
708 struct pollfd pfd[2];
709
710 pfd[0].fd = RTFileToNative(pDevSol->hFile);
711 pfd[0].events = POLLIN;
712 pfd[0].revents = 0;
713
714 pfd[1].fd = RTPipeToNative(pDevSol->hPipeWakeupR);
715 pfd[1].events = POLLIN;
716 pfd[1].revents = 0;
717
718 int rc = poll(&pfd[0], 2, cMilliesWait);
719 if (rc > 0)
720 {
721 if (pfd[0].revents & POLLHUP)
722 {
723 LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName));
724 pProxyDev->fDetached = true;
725 usbProxySolarisCloseFile(pDevSol);
726 }
727
728 if (pfd[1].revents & POLLIN)
729 {
730 /* Got woken up, drain pipe. */
731 uint8_t bRead;
732 size_t cbIgnored = 0;
733 RTPipeRead(pDevSol->hPipeWakeupR, &bRead, 1, &cbIgnored);
734
735 /*
736 * It is possible that we got woken up and have an URB pending
737 * for completion. Do it on the way out. Otherwise return
738 * immediately to the caller.
739 */
740 if (!(pfd[0].revents & POLLIN))
741 return NULL;
742 }
743
744 break;
745 }
746
747 if (rc == 0)
748 {
749 //LogFlow((USBPROXY ":usbProxySolarisUrbReap: Timed out\n"));
750 return NULL;
751 }
752 else if (rc != EAGAIN)
753 {
754 LogFlow((USBPROXY ":usbProxySolarisUrbReap Poll rc=%d errno=%d\n", rc, errno));
755 return NULL;
756 }
757 }
758 }
759
760 usbProxySolarisUrbComplete(pDevSol);
761
762 /*
763 * Any URBs pending delivery?
764 */
765 PVUSBURB pUrb = NULL;
766 while (pDevSol->pTaxingHead)
767 {
768 RTCritSectEnter(&pDevSol->CritSect);
769
770 PUSBPROXYURBSOL pUrbSol = pDevSol->pTaxingHead;
771 if (pUrbSol)
772 {
773 pUrb = pUrbSol->pVUsbUrb;
774 if (pUrb)
775 {
776 pUrb->Dev.pvPrivate = NULL;
777 usbProxySolarisUrbFree(pDevSol, pUrbSol);
778 }
779 }
780 RTCritSectLeave(&pDevSol->CritSect);
781 }
782
783 return pUrb;
784}
785
786
787/**
788 * Reads a completed/error'd URB from the client driver (no waiting).
789 *
790 * @param pDevSol The Solaris device instance.
791 */
792static PVUSBURB usbProxySolarisUrbComplete(PUSBPROXYDEVSOL pDevSol)
793{
794 LogFlowFunc((USBPROXY ":usbProxySolarisUrbComplete pDevSol=%p\n", pDevSol));
795
796 VBOXUSBREQ_URB UrbReq;
797 bzero(&UrbReq, sizeof(UrbReq));
798
799 int rc = usbProxySolarisIOCtl(pDevSol, VBOXUSB_IOCTL_REAP_URB, &UrbReq, sizeof(UrbReq));
800 if (RT_SUCCESS(rc))
801 {
802 if (UrbReq.pvUrbR3)
803 {
804 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)UrbReq.pvUrbR3;
805 PVUSBURB pUrb = pUrbSol->pVUsbUrb;
806 if (RT_LIKELY(pUrb))
807 {
808 Assert(pUrb->u32Magic == VUSBURB_MAGIC);
809
810 /*
811 * Update the URB.
812 */
813 if ( pUrb->enmType == VUSBXFERTYPE_ISOC
814 && pUrb->enmDir == VUSBDIRECTION_IN)
815 {
816 size_t cbData = 0;
817 for (unsigned i = 0; i < UrbReq.cIsocPkts; i++)
818 {
819 pUrb->aIsocPkts[i].cb = UrbReq.aIsocPkts[i].cbActPkt;
820 cbData += UrbReq.aIsocPkts[i].cbActPkt;
821 pUrb->aIsocPkts[i].enmStatus = UrbReq.aIsocPkts[i].enmStatus;
822 }
823
824 LogFlow((USBPROXY ":usbProxySolarisUrbComplete ISOC cbData=%d cbActPktSum=%d\n", pUrb->cbData, cbData));
825 pUrb->cbData = cbData;
826 pUrb->enmStatus = UrbReq.enmStatus;
827 }
828 else
829 {
830 pUrb->cbData = UrbReq.cbData;
831 pUrb->enmStatus = UrbReq.enmStatus;
832 }
833
834 RTCritSectEnter(&pDevSol->CritSect);
835
836 /*
837 * Remove from the active list.
838 */
839 if (pUrbSol->pNext)
840 pUrbSol->pNext->pPrev = pUrbSol->pPrev;
841 if (pUrbSol->pPrev)
842 pUrbSol->pPrev->pNext = pUrbSol->pNext;
843 else
844 {
845 Assert(pDevSol->pInFlightHead == pUrbSol);
846 pDevSol->pInFlightHead = pUrbSol->pNext;
847 }
848
849 /*
850 * Link it into the taxing list.
851 */
852 pUrbSol->pNext = NULL;
853 pUrbSol->pPrev = pDevSol->pTaxingTail;
854 if (pDevSol->pTaxingTail)
855 pDevSol->pTaxingTail->pNext = pUrbSol;
856 else
857 pDevSol->pTaxingHead = pUrbSol;
858 pDevSol->pTaxingTail = pUrbSol;
859
860 RTCritSectLeave(&pDevSol->CritSect);
861
862 LogFlow((USBPROXY "usbProxySolarisUrbComplete: cb=%d EndPt=%#x enmDir=%d enmStatus=%s (%d) \n",
863 pUrb->cbData, pUrb->EndPt, pUrb->enmDir, pUrb->enmStatus == VUSBSTATUS_OK ? "OK" : "** Failed **", pUrb->enmStatus));
864// if (pUrb->cbData < 2049)
865// LogFlow((USBPROXY "%.*Rhxd\n", pUrb->cbData, pUrb->abData));
866 return pUrb;
867 }
868 }
869 }
870 else
871 {
872 if (rc != VERR_VUSB_DEVICE_NOT_ATTACHED)
873 LogRel((USBPROXY ":Reaping URB failed. rc=%Rrc\n", rc));
874 }
875
876 return NULL;
877}
878
879
880static DECLCALLBACK(int) usbProxySolarisWakeup(PUSBPROXYDEV pProxyDev)
881{
882 PUSBPROXYDEVFBSD pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL);
883 size_t cbIgnored;
884
885 LogFlowFunc(("pProxyDev=%p\n", pProxyDev));
886
887 return RTPipeWrite(pDevSol->hPipeWakeupW, "", 1, &cbIgnored);
888}
889
890
891/**
892 * The Solaris USB Proxy Backend.
893 */
894extern const USBPROXYBACK g_USBProxyDeviceHost =
895{
896 /* pszName */
897 "host",
898 /* cbBackend */
899 sizeof(USBPROXYDEVSOL),
900 usbProxySolarisOpen,
901 NULL,
902 usbProxySolarisClose,
903 usbProxySolarisReset,
904 usbProxySolarisSetConfig,
905 usbProxySolarisClaimInterface,
906 usbProxySolarisReleaseInterface,
907 usbProxySolarisSetInterface,
908 usbProxySolarisClearHaltedEp,
909 usbProxySolarisUrbQueue,
910 usbProxySolarisUrbCancel,
911 usbProxySolarisUrbReap,
912 usbProxySolarisWakeup,
913 0
914};
915
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