VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp@ 89153

Last change on this file since 89153 was 87419, checked in by vboxsync, 4 years ago

USB/Darwin: Capture USB devices directly through IOUSBLib, no longer use VBoxUSB.kext (see bugref:9808). [build fix/hack]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.3 KB
Line 
1/* $Id: USBProxyDevice-darwin.cpp 87419 2021-01-25 14:18:14Z vboxsync $ */
2/** @file
3 * USB device proxy - the Darwin backend.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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#define __STDC_LIMIT_MACROS
24#define __STDC_CONSTANT_MACROS
25
26#include <mach/mach.h>
27#include <Carbon/Carbon.h>
28#include <IOKit/IOKitLib.h>
29#include <mach/mach_error.h>
30#include <IOKit/usb/IOUSBLib.h>
31#include <IOKit/IOCFPlugIn.h>
32#ifndef __MAC_10_10 /* Quick hack: The following two masks appeared in 10.10. */
33# define kUSBReEnumerateReleaseDeviceMask RT_BIT_32(29)
34# define kUSBReEnumerateCaptureDeviceMask RT_BIT_32(30)
35#endif
36
37#include <VBox/log.h>
38#include <VBox/err.h>
39#include <VBox/vmm/pdm.h>
40
41#include <iprt/assert.h>
42#include <iprt/critsect.h>
43#include <iprt/list.h>
44#include <iprt/mem.h>
45#include <iprt/once.h>
46#include <iprt/string.h>
47#include <iprt/time.h>
48
49#include "../USBProxyDevice.h"
50#include <VBox/usblib.h>
51
52
53/*********************************************************************************************************************************
54* Defined Constants And Macros *
55*********************************************************************************************************************************/
56/** An experiment... */
57//#define USE_LOW_LATENCY_API 1
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63/** Forward declaration of the Darwin interface structure. */
64typedef struct USBPROXYIFOSX *PUSBPROXYIFOSX;
65
66
67/**
68 * A low latency isochronous buffer.
69 *
70 * These are allocated in chunks on an interface level, see USBPROXYISOCBUFCOL.
71 */
72typedef struct USBPROXYISOCBUF
73{
74 /** Whether this buffer is in use or not. */
75 bool volatile fUsed;
76 /** Pointer to the buffer. */
77 void *pvBuf;
78 /** Pointer to an array of 8 frames. */
79 IOUSBLowLatencyIsocFrame *paFrames;
80} USBPROXYISOCBUF, *PUSBPROXYISOCBUF;
81
82
83/**
84 * Isochronous buffer collection (associated with an interface).
85 *
86 * These are allocated in decent sized chunks and there isn't supposed
87 * to be too many of these per interface.
88 */
89typedef struct USBPROXYISOCBUFCOL
90{
91 /** Write or Read buffers? */
92 USBLowLatencyBufferType enmType;
93 /** The next buffer collection on this interface. */
94 struct USBPROXYISOCBUFCOL *pNext;
95 /** The buffer. */
96 void *pvBuffer;
97 /** The frame. */
98 void *pvFrames;
99 /** The buffers.
100 * The number of buffers here is decided by pvFrame begin allocated in
101 * PAGE_SIZE chunks. The size of IOUSBLowLatencyIsocFrame is 16 bytes
102 * and we require 8 of those per buffer. PAGE_SIZE / (16 * 8) = 32.
103 * @remarks Don't allocate too many as it may temporarily halt the system if
104 * some pool is low / exhausted. (Contiguous memory woes on mach.)
105 */
106 USBPROXYISOCBUF aBuffers[/*32*/ 4];
107} USBPROXYISOCBUFCOL, *PUSBPROXYISOCBUFCOL;
108
109AssertCompileSize(IOUSBLowLatencyIsocFrame, 16);
110
111/**
112 * Per-urb data for the Darwin usb proxy backend.
113 *
114 * This is required to track in-flight and landed URBs
115 * since we take down the URBs in a different thread (perhaps).
116 */
117typedef struct USBPROXYURBOSX
118{
119 /** Pointer to the next Darwin URB. */
120 struct USBPROXYURBOSX *pNext;
121 /** Pointer to the previous Darwin URB. */
122 struct USBPROXYURBOSX *pPrev;
123 /** The millisecond timestamp when this URB was submitted. */
124 uint64_t u64SubmitTS;
125 /** Pointer to the VUSB URB.
126 * This is set to NULL if canceled. */
127 PVUSBURB pVUsbUrb;
128 /** Pointer to the Darwin device. */
129 struct USBPROXYDEVOSX *pDevOsX;
130 /** The transfer type. */
131 VUSBXFERTYPE enmType;
132 /** Union with data depending on transfer type. */
133 union
134 {
135 /** The control message. */
136 IOUSBDevRequest ControlMsg;
137 /** The Isochronous Data. */
138 struct
139 {
140#ifdef USE_LOW_LATENCY_API
141 /** The low latency isochronous buffer. */
142 PUSBPROXYISOCBUF pBuf;
143 /** Array of frames parallel to the one in VUSBURB. (Same as pBuf->paFrames.) */
144 IOUSBLowLatencyIsocFrame *aFrames;
145#else
146 /** Array of frames parallel to the one in VUSBURB. */
147 IOUSBIsocFrame aFrames[8];
148#endif
149 } Isoc;
150 } u;
151} USBPROXYURBOSX, *PUSBPROXYURBOSX;
152
153/**
154 * Per-pipe data for the Darwin usb proxy backend.
155 */
156typedef struct USBPROXYPIPEOSX
157{
158 /** The endpoint number. */
159 uint8_t u8Endpoint;
160 /** The IOKit pipe reference. */
161 uint8_t u8PipeRef;
162 /** The pipe Transfer type type. */
163 uint8_t u8TransferType;
164 /** The pipe direction. */
165 uint8_t u8Direction;
166 /** The endpoint interval. (interrupt) */
167 uint8_t u8Interval;
168 /** Full-speed device indicator (isochronous pipes only). */
169 bool fIsFullSpeed;
170 /** The max packet size. */
171 uint16_t u16MaxPacketSize;
172 /** The next frame number (isochronous pipes only). */
173 uint64_t u64NextFrameNo;
174} USBPROXYPIPEOSX, *PUSBPROXYPIPEOSX, **PPUSBPROXYPIPEOSX;
175
176typedef struct RUNLOOPREFLIST
177{
178 RTLISTNODE List;
179 CFRunLoopRef RunLoopRef;
180} RUNLOOPREFLIST, *PRUNLOOPREFLIST;
181typedef RUNLOOPREFLIST **PPRUNLOOPREFLIST;
182
183/**
184 * Per-interface data for the Darwin usb proxy backend.
185 */
186typedef struct USBPROXYIFOSX
187{
188 /** Pointer to the next interface. */
189 struct USBPROXYIFOSX *pNext;
190 /** The interface number. */
191 uint8_t u8Interface;
192 /** The current alternative interface setting.
193 * This is used to skip unnecessary SetAltInterface calls. */
194 uint8_t u8AltSetting;
195 /** The interface class. (not really used) */
196 uint8_t u8Class;
197 /** The interface protocol. (not really used) */
198 uint8_t u8Protocol;
199 /** The number of pipes. */
200 uint8_t cPipes;
201 /** Array containing all the pipes. (Currently unsorted.) */
202 USBPROXYPIPEOSX aPipes[kUSBMaxPipes];
203 /** The IOUSBDeviceInterface. */
204 IOUSBInterfaceInterface245 **ppIfI;
205 /** The run loop source for the async operations on the interface level. */
206 CFRunLoopSourceRef RunLoopSrcRef;
207 /** List of isochronous buffer collections.
208 * These are allocated on demand by the URB queuing routine and then recycled until the interface is destroyed. */
209 RTLISTANCHOR HeadOfRunLoopLst;
210 PUSBPROXYISOCBUFCOL pIsocBufCols;
211} USBPROXYIFOSX, *PUSBPROXYIFOSX, **PPUSBPROXYIFOSX;
212/** Pointer to a pointer to an darwin interface. */
213typedef USBPROXYIFOSX **PPUSBPROXYIFOSX;
214
215/**
216 * Per-device Data for the Darwin usb proxy backend.
217 */
218typedef struct USBPROXYDEVOSX
219{
220 /** The USB Device IOService object. */
221 io_object_t USBDevice;
222 /** The IOUSBDeviceInterface. */
223 IOUSBDeviceInterface245 **ppDevI;
224 /** The run loop source for the async operations on the device level
225 * (i.e. the default control pipe stuff). */
226 CFRunLoopSourceRef RunLoopSrcRef;
227 /** we want to add and remove RunLoopSourceRefs to run loop's of
228 * every EMT thread participated in USB processing. */
229 RTLISTANCHOR HeadOfRunLoopLst;
230 /** Pointer to the proxy device instance. */
231 PUSBPROXYDEV pProxyDev;
232
233 /** Pointer to the first interface. */
234 PUSBPROXYIFOSX pIfHead;
235 /** Pointer to the last interface. */
236 PUSBPROXYIFOSX pIfTail;
237
238 /** Critical section protecting the lists. */
239 RTCRITSECT CritSect;
240 /** The list of free Darwin URBs. Singly linked. */
241 PUSBPROXYURBOSX pFreeHead;
242 /** The list of landed Darwin URBs. Doubly linked.
243 * Only the split head will appear in this list. */
244 PUSBPROXYURBOSX pTaxingHead;
245 /** The tail of the landed Darwin URBs. */
246 PUSBPROXYURBOSX pTaxingTail;
247 /** Last reaper runloop reference, there can be only one runloop at a time. */
248 CFRunLoopRef hRunLoopReapingLast;
249 /** Runloop source for waking up the reaper thread. */
250 CFRunLoopSourceRef hRunLoopSrcWakeRef;
251 /** List of threads used for reaping which can be woken up. */
252 RTLISTANCHOR HeadOfRunLoopWakeLst;
253 /** Runloop reference of the thread reaping. */
254 volatile CFRunLoopRef hRunLoopReaping;
255 /** Flag whether the reaping thread is about the be waked. */
256 volatile bool fReapingThreadWake;
257} USBPROXYDEVOSX, *PUSBPROXYDEVOSX;
258
259
260/*********************************************************************************************************************************
261* Global Variables *
262*********************************************************************************************************************************/
263static RTONCE g_usbProxyDarwinOnce = RTONCE_INITIALIZER;
264/** The runloop mode we use.
265 * Since it's difficult to remove this, we leak it to prevent crashes.
266 * @bugref{4407} */
267static CFStringRef g_pRunLoopMode = NULL;
268/** The IO Master Port.
269 * Not worth cleaning up. */
270static mach_port_t g_MasterPort = MACH_PORT_NULL;
271
272
273/**
274 * Init once callback that sets up g_MasterPort and g_pRunLoopMode.
275 *
276 * @returns IPRT status code.
277 *
278 * @param pvUser1 NULL, ignored.
279 */
280static DECLCALLBACK(int32_t) usbProxyDarwinInitOnce(void *pvUser1)
281{
282 RT_NOREF(pvUser1);
283
284 int rc;
285 kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &g_MasterPort);
286 if (krc == KERN_SUCCESS)
287 {
288 g_pRunLoopMode = CFStringCreateWithCString(kCFAllocatorDefault, "VBoxUsbProxyMode", kCFStringEncodingUTF8);
289 if (g_pRunLoopMode)
290 return VINF_SUCCESS;
291 rc = VERR_INTERNAL_ERROR_5;
292 }
293 else
294 rc = RTErrConvertFromDarwin(krc);
295 return rc;
296}
297
298/**
299 * Kicks the reaper thread if it sleeps currently to respond to state changes
300 * or to pick up completed URBs.
301 *
302 * @returns nothing.
303 * @param pDevOsX The darwin device instance data.
304 */
305static void usbProxyDarwinReaperKick(PUSBPROXYDEVOSX pDevOsX)
306{
307 CFRunLoopRef hRunLoopWake = (CFRunLoopRef)ASMAtomicReadPtr((void * volatile *)&pDevOsX->hRunLoopReaping);
308 if (hRunLoopWake)
309 {
310 LogFlowFunc(("Waking runloop %p\n", hRunLoopWake));
311 CFRunLoopSourceSignal(pDevOsX->hRunLoopSrcWakeRef);
312 CFRunLoopWakeUp(hRunLoopWake);
313 }
314}
315
316/**
317 * Adds Source ref to current run loop and adds it the list of runloops.
318 */
319static int usbProxyDarwinAddRunLoopRef(PRTLISTANCHOR pListHead,
320 CFRunLoopSourceRef SourceRef)
321{
322 AssertPtrReturn(pListHead, VERR_INVALID_PARAMETER);
323 AssertReturn(CFRunLoopSourceIsValid(SourceRef), VERR_INVALID_PARAMETER);
324
325 if (CFRunLoopContainsSource(CFRunLoopGetCurrent(), SourceRef, g_pRunLoopMode))
326 return VINF_SUCCESS;
327
328 /* Add to the list */
329 PRUNLOOPREFLIST pListNode = (PRUNLOOPREFLIST)RTMemAllocZ(sizeof(RUNLOOPREFLIST));
330 if (!pListNode)
331 return VERR_NO_MEMORY;
332
333 pListNode->RunLoopRef = CFRunLoopGetCurrent();
334
335 CFRetain(pListNode->RunLoopRef);
336 CFRetain(SourceRef); /* We want to be aware of releasing */
337
338 CFRunLoopAddSource(pListNode->RunLoopRef, SourceRef, g_pRunLoopMode);
339
340 RTListInit(&pListNode->List);
341
342 RTListAppend((PRTLISTNODE)pListHead, &pListNode->List);
343
344 return VINF_SUCCESS;
345}
346
347
348/*
349 * Removes all source reference from mode of run loop's we've registered them.
350 *
351 */
352static int usbProxyDarwinRemoveSourceRefFromAllRunLoops(PRTLISTANCHOR pHead,
353 CFRunLoopSourceRef SourceRef)
354{
355 AssertPtrReturn(pHead, VERR_INVALID_PARAMETER);
356
357 while (!RTListIsEmpty(pHead))
358 {
359 PRUNLOOPREFLIST pNode = RTListGetFirst(pHead, RUNLOOPREFLIST, List);
360 /* XXX: Should Release Reference? */
361 Assert(CFGetRetainCount(pNode->RunLoopRef));
362
363 CFRunLoopRemoveSource(pNode->RunLoopRef, SourceRef, g_pRunLoopMode);
364 CFRelease(SourceRef);
365 CFRelease(pNode->RunLoopRef);
366
367 RTListNodeRemove(&pNode->List);
368
369 RTMemFree(pNode);
370 }
371
372 return VINF_SUCCESS;
373}
374
375
376/**
377 * Allocates a Darwin URB request structure.
378 *
379 * @returns Pointer to an active URB request.
380 * @returns NULL on failure.
381 *
382 * @param pDevOsX The darwin proxy device.
383 */
384static PUSBPROXYURBOSX usbProxyDarwinUrbAlloc(PUSBPROXYDEVOSX pDevOsX)
385{
386 PUSBPROXYURBOSX pUrbOsX;
387
388 RTCritSectEnter(&pDevOsX->CritSect);
389
390 /*
391 * Try remove a Darwin URB from the free list, if none there allocate a new one.
392 */
393 pUrbOsX = pDevOsX->pFreeHead;
394 if (pUrbOsX)
395 {
396 pDevOsX->pFreeHead = pUrbOsX->pNext;
397 RTCritSectLeave(&pDevOsX->CritSect);
398 }
399 else
400 {
401 RTCritSectLeave(&pDevOsX->CritSect);
402 pUrbOsX = (PUSBPROXYURBOSX)RTMemAlloc(sizeof(*pUrbOsX));
403 if (!pUrbOsX)
404 return NULL;
405 }
406 pUrbOsX->pVUsbUrb = NULL;
407 pUrbOsX->pDevOsX = pDevOsX;
408 pUrbOsX->enmType = VUSBXFERTYPE_INVALID;
409
410 return pUrbOsX;
411}
412
413
414#ifdef USE_LOW_LATENCY_API
415/**
416 * Allocates an low latency isochronous buffer.
417 *
418 * @returns VBox status code.
419 * @param pUrbOsX The OsX URB to allocate it for.
420 * @param pIf The interface to allocated it from.
421 */
422static int usbProxyDarwinUrbAllocIsocBuf(PUSBPROXYURBOSX pUrbOsX, PUSBPROXYIFOSX pIf)
423{
424 USBLowLatencyBufferType enmLLType = pUrbOsX->pVUsbUrb->enmDir == VUSBDIRECTION_IN
425 ? kUSBLowLatencyWriteBuffer : kUSBLowLatencyReadBuffer;
426
427 /*
428 * Walk the buffer collection list and look for an unused one.
429 */
430 pUrbOsX->u.Isoc.pBuf = NULL;
431 for (PUSBPROXYISOCBUFCOL pCur = pIf->pIsocBufCols; pCur; pCur = pCur->pNext)
432 if (pCur->enmType == enmLLType)
433 for (unsigned i = 0; i < RT_ELEMENTS(pCur->aBuffers); i++)
434 if (!pCur->aBuffers[i].fUsed)
435 {
436 pCur->aBuffers[i].fUsed = true;
437 pUrbOsX->u.Isoc.pBuf = &pCur->aBuffers[i];
438 AssertPtr(pUrbOsX->u.Isoc.pBuf);
439 AssertPtr(pUrbOsX->u.Isoc.pBuf->pvBuf);
440 pUrbOsX->u.Isoc.aFrames = pCur->aBuffers[i].paFrames;
441 AssertPtr(pUrbOsX->u.Isoc.aFrames);
442 return VINF_SUCCESS;
443 }
444
445 /*
446 * Didn't find an empty one, create a new buffer collection and take the first buffer.
447 */
448 PUSBPROXYISOCBUFCOL pNew = (PUSBPROXYISOCBUFCOL)RTMemAllocZ(sizeof(*pNew));
449 AssertReturn(pNew, VERR_NO_MEMORY);
450
451 IOReturn irc = (*pIf->ppIfI)->LowLatencyCreateBuffer(pIf->ppIfI, &pNew->pvBuffer, 8192 * RT_ELEMENTS(pNew->aBuffers), enmLLType);
452 if (irc == kIOReturnSuccess != VALID_PTR(pNew->pvBuffer))
453 {
454 AssertPtr(pNew->pvBuffer);
455 irc = kIOReturnNoMemory;
456 }
457 if (irc == kIOReturnSuccess)
458 {
459 irc = (*pIf->ppIfI)->LowLatencyCreateBuffer(pIf->ppIfI, &pNew->pvFrames, PAGE_SIZE, kUSBLowLatencyFrameListBuffer);
460 if (irc == kIOReturnSuccess != VALID_PTR(pNew->pvFrames))
461 {
462 AssertPtr(pNew->pvFrames);
463 irc = kIOReturnNoMemory;
464 }
465 if (irc == kIOReturnSuccess)
466 {
467 for (unsigned i = 0; i < RT_ELEMENTS(pNew->aBuffers); i++)
468 {
469 //pNew->aBuffers[i].fUsed = false;
470 pNew->aBuffers[i].paFrames = &((IOUSBLowLatencyIsocFrame *)pNew->pvFrames)[i * 8];
471 pNew->aBuffers[i].pvBuf = (uint8_t *)pNew->pvBuffer + i * 8192;
472 }
473
474 pNew->aBuffers[0].fUsed = true;
475 pUrbOsX->u.Isoc.aFrames = pNew->aBuffers[0].paFrames;
476 pUrbOsX->u.Isoc.pBuf = &pNew->aBuffers[0];
477
478 pNew->enmType = enmLLType;
479 pNew->pNext = pIf->pIsocBufCols;
480 pIf->pIsocBufCols = pNew;
481
482#if 0 /* doesn't help :-/ */
483 /*
484 * If this is the first time we're here, try mess with the policy?
485 */
486 if (!pNew->pNext)
487 for (unsigned iPipe = 0; iPipe < pIf->cPipes; iPipe++)
488 if (pIf->aPipes[iPipe].u8TransferType == kUSBIsoc)
489 {
490 irc = (*pIf->ppIfI)->SetPipePolicy(pIf->ppIfI, pIf->aPipes[iPipe].u8PipeRef,
491 pIf->aPipes[iPipe].u16MaxPacketSize, pIf->aPipes[iPipe].u8Interval);
492 AssertMsg(irc == kIOReturnSuccess, ("%#x\n", irc));
493 }
494#endif
495
496 return VINF_SUCCESS;
497 }
498
499 /* bail out */
500 (*pIf->ppIfI)->LowLatencyDestroyBuffer(pIf->ppIfI, pNew->pvBuffer);
501 }
502 AssertMsgFailed(("%#x\n", irc));
503 RTMemFree(pNew);
504
505 return RTErrConvertFromDarwin(irc);
506}
507#endif /* USE_LOW_LATENCY_API */
508
509
510/**
511 * Frees a Darwin URB request structure.
512 *
513 * @param pDevOsX The darwin proxy device.
514 * @param pUrbOsX The Darwin URB to free.
515 */
516static void usbProxyDarwinUrbFree(PUSBPROXYDEVOSX pDevOsX, PUSBPROXYURBOSX pUrbOsX)
517{
518 RTCritSectEnter(&pDevOsX->CritSect);
519
520#ifdef USE_LOW_LATENCY_API
521 /*
522 * Free low latency stuff.
523 */
524 if ( pUrbOsX->enmType == VUSBXFERTYPE_ISOC
525 && pUrbOsX->u.Isoc.pBuf)
526 {
527 pUrbOsX->u.Isoc.pBuf->fUsed = false;
528 pUrbOsX->u.Isoc.pBuf = NULL;
529 }
530#endif
531
532 /*
533 * Link it into the free list.
534 */
535 pUrbOsX->pPrev = NULL;
536 pUrbOsX->pNext = pDevOsX->pFreeHead;
537 pDevOsX->pFreeHead = pUrbOsX;
538
539 pUrbOsX->pVUsbUrb = NULL;
540 pUrbOsX->pDevOsX = NULL;
541 pUrbOsX->enmType = VUSBXFERTYPE_INVALID;
542
543 RTCritSectLeave(&pDevOsX->CritSect);
544}
545
546/**
547 * Translate the IOKit status code to a VUSB status.
548 *
549 * @returns VUSB URB status code.
550 * @param irc IOKit status code.
551 */
552static VUSBSTATUS vusbProxyDarwinStatusToVUsbStatus(IOReturn irc)
553{
554 switch (irc)
555 {
556 /* IOKit OHCI VUSB */
557 case kIOReturnSuccess: /* 0 */ return VUSBSTATUS_OK;
558 case kIOUSBCRCErr: /* 1 */ return VUSBSTATUS_CRC;
559 //case kIOUSBBitstufErr: /* 2 */ return VUSBSTATUS_;
560 //case kIOUSBDataToggleErr: /* 3 */ return VUSBSTATUS_;
561 case kIOUSBPipeStalled: /* 4 */ return VUSBSTATUS_STALL;
562 case kIOReturnNotResponding: /* 5 */ return VUSBSTATUS_DNR;
563 //case kIOUSBPIDCheckErr: /* 6 */ return VUSBSTATUS_;
564 //case kIOUSBWrongPIDErr: /* 7 */ return VUSBSTATUS_;
565 case kIOReturnOverrun: /* 8 */ return VUSBSTATUS_DATA_OVERRUN;
566 case kIOReturnUnderrun: /* 9 */ return VUSBSTATUS_DATA_UNDERRUN;
567 //case kIOUSBReserved1Err: /* 10 */ return VUSBSTATUS_;
568 //case kIOUSBReserved2Err: /* 11 */ return VUSBSTATUS_;
569 //case kIOUSBBufferOverrunErr: /* 12 */ return VUSBSTATUS_;
570 //case kIOUSBBufferUnderrunErr: /* 13 */ return VUSBSTATUS_;
571 case kIOUSBNotSent1Err: /* 14 */ return VUSBSTATUS_NOT_ACCESSED/*VUSBSTATUS_OK*/;
572 case kIOUSBNotSent2Err: /* 15 */ return VUSBSTATUS_NOT_ACCESSED/*VUSBSTATUS_OK*/;
573
574 /* Other errors */
575 case kIOUSBTransactionTimeout: return VUSBSTATUS_DNR;
576 //case kIOReturnAborted: return VUSBSTATUS_CRC; - see on SET_INTERFACE...
577
578 default:
579 Log(("vusbProxyDarwinStatusToVUsbStatus: irc=%#x!!\n", irc));
580 return VUSBSTATUS_STALL;
581 }
582}
583
584
585/**
586 * Completion callback for an async URB transfer.
587 *
588 * @param pvUrbOsX The Darwin URB.
589 * @param irc The status of the operation.
590 * @param Size Possible the transfer size.
591 */
592static void usbProxyDarwinUrbAsyncComplete(void *pvUrbOsX, IOReturn irc, void *Size)
593{
594 PUSBPROXYURBOSX pUrbOsX = (PUSBPROXYURBOSX)pvUrbOsX;
595 PUSBPROXYDEVOSX pDevOsX = pUrbOsX->pDevOsX;
596 const uint32_t cb = (uintptr_t)Size;
597
598 /*
599 * Do status updates.
600 */
601 PVUSBURB pUrb = pUrbOsX->pVUsbUrb;
602 if (pUrb)
603 {
604 Assert(pUrb->u32Magic == VUSBURB_MAGIC);
605 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
606 {
607#ifdef USE_LOW_LATENCY_API
608 /* copy the data. */
609 //if (pUrb->enmDir == VUSBDIRECTION_IN)
610 memcpy(pUrb->abData, pUrbOsX->u.Isoc.pBuf->pvBuf, pUrb->cbData);
611#endif
612 Log3(("AsyncComplete isoc - raw data (%d bytes):\n"
613 "%16.*Rhxd\n", pUrb->cbData, pUrb->cbData, pUrb->abData));
614 uint32_t off = 0;
615 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
616 {
617#ifdef USE_LOW_LATENCY_API
618 Log2((" %d{%d/%d-%x-%RX64}", i, pUrbOsX->u.Isoc.aFrames[i].frActCount, pUrb->aIsocPkts[i].cb, pUrbOsX->u.Isoc.aFrames[i].frStatus,
619 RT_MAKE_U64(pUrbOsX->u.Isoc.aFrames[i].frTimeStamp.lo, pUrbOsX->u.Isoc.aFrames[i].frTimeStamp.hi) ));
620#else
621 Log2((" %d{%d/%d-%x}", i, pUrbOsX->u.Isoc.aFrames[i].frActCount, pUrb->aIsocPkts[i].cb, pUrbOsX->u.Isoc.aFrames[i].frStatus));
622#endif
623 pUrb->aIsocPkts[i].enmStatus = vusbProxyDarwinStatusToVUsbStatus(pUrbOsX->u.Isoc.aFrames[i].frStatus);
624 pUrb->aIsocPkts[i].cb = pUrbOsX->u.Isoc.aFrames[i].frActCount;
625 off += pUrbOsX->u.Isoc.aFrames[i].frActCount;
626 }
627 Log2(("\n"));
628#if 0 /** @todo revisit this, wasn't working previously. */
629 for (int i = (int)pUrb->cIsocPkts - 1; i >= 0; i--)
630 Assert( !pUrbOsX->u.Isoc.aFrames[i].frActCount
631 && !pUrbOsX->u.Isoc.aFrames[i].frReqCount
632 && !pUrbOsX->u.Isoc.aFrames[i].frStatus);
633#endif
634 pUrb->cbData = off; /* 'Size' seems to be pointing at an error code or something... */
635 pUrb->enmStatus = VUSBSTATUS_OK; /* Don't use 'irc'. OHCI expects OK unless it's a really bad error. */
636 }
637 else
638 {
639 pUrb->cbData = cb;
640 pUrb->enmStatus = vusbProxyDarwinStatusToVUsbStatus(irc);
641 if (pUrb->enmType == VUSBXFERTYPE_MSG)
642 pUrb->cbData += sizeof(VUSBSETUP);
643 }
644 }
645
646 RTCritSectEnter(&pDevOsX->CritSect);
647
648 /*
649 * Link it into the taxing list.
650 */
651 pUrbOsX->pNext = NULL;
652 pUrbOsX->pPrev = pDevOsX->pTaxingTail;
653 if (pDevOsX->pTaxingTail)
654 pDevOsX->pTaxingTail->pNext = pUrbOsX;
655 else
656 pDevOsX->pTaxingHead = pUrbOsX;
657 pDevOsX->pTaxingTail = pUrbOsX;
658
659 RTCritSectLeave(&pDevOsX->CritSect);
660
661 LogFlow(("%s: usbProxyDarwinUrbAsyncComplete: cb=%d EndPt=%#x irc=%#x (%d)\n",
662 pUrb->pszDesc, cb, pUrb ? pUrb->EndPt : 0xff, irc, pUrb ? pUrb->enmStatus : 0xff));
663}
664
665/**
666 * Release all interfaces (current config).
667 *
668 * @param pDevOsX The darwin proxy device.
669 */
670static void usbProxyDarwinReleaseAllInterfaces(PUSBPROXYDEVOSX pDevOsX)
671{
672 RTCritSectEnter(&pDevOsX->CritSect);
673
674 /* Kick the reaper thread out of sleep. */
675 usbProxyDarwinReaperKick(pDevOsX);
676
677 PUSBPROXYIFOSX pIf = pDevOsX->pIfHead;
678 pDevOsX->pIfHead = pDevOsX->pIfTail = NULL;
679
680 while (pIf)
681 {
682 PUSBPROXYIFOSX pNext = pIf->pNext;
683 IOReturn irc;
684
685 if (pIf->RunLoopSrcRef)
686 {
687 int rc = usbProxyDarwinRemoveSourceRefFromAllRunLoops((PRTLISTANCHOR)&pIf->HeadOfRunLoopLst, pIf->RunLoopSrcRef);
688 AssertRC(rc);
689
690 CFRelease(pIf->RunLoopSrcRef);
691 pIf->RunLoopSrcRef = NULL;
692 RTListInit((PRTLISTNODE)&pIf->HeadOfRunLoopLst);
693 }
694
695 while (pIf->pIsocBufCols)
696 {
697 PUSBPROXYISOCBUFCOL pCur = pIf->pIsocBufCols;
698 pIf->pIsocBufCols = pCur->pNext;
699 pCur->pNext = NULL;
700
701 irc = (*pIf->ppIfI)->LowLatencyDestroyBuffer(pIf->ppIfI, pCur->pvBuffer);
702 AssertMsg(irc == kIOReturnSuccess || irc == MACH_SEND_INVALID_DEST, ("%#x\n", irc));
703 pCur->pvBuffer = NULL;
704
705 irc = (*pIf->ppIfI)->LowLatencyDestroyBuffer(pIf->ppIfI, pCur->pvFrames);
706 AssertMsg(irc == kIOReturnSuccess || irc == MACH_SEND_INVALID_DEST, ("%#x\n", irc));
707 pCur->pvFrames = NULL;
708
709 RTMemFree(pCur);
710 }
711
712 irc = (*pIf->ppIfI)->USBInterfaceClose(pIf->ppIfI);
713 AssertMsg(irc == kIOReturnSuccess || irc == kIOReturnNoDevice, ("%#x\n", irc));
714
715 (*pIf->ppIfI)->Release(pIf->ppIfI);
716 pIf->ppIfI = NULL;
717
718 RTMemFree(pIf);
719
720 pIf = pNext;
721 }
722 RTCritSectLeave(&pDevOsX->CritSect);
723}
724
725
726/**
727 * Get the properties all the pipes associated with an interface.
728 *
729 * This is used when we seize all the interface and after SET_INTERFACE.
730 *
731 * @returns VBox status code.
732 * @param pDevOsX The darwin proxy device.
733 * @param pIf The interface to get pipe props for.
734 */
735static int usbProxyDarwinGetPipeProperties(PUSBPROXYDEVOSX pDevOsX, PUSBPROXYIFOSX pIf)
736{
737 /*
738 * Get the pipe (endpoint) count (it might have changed - even on open).
739 */
740 int rc = VINF_SUCCESS;
741 bool fFullSpeed;
742 UInt32 u32UsecInFrame;
743 UInt8 cPipes;
744 IOReturn irc = (*pIf->ppIfI)->GetNumEndpoints(pIf->ppIfI, &cPipes);
745 if (irc != kIOReturnSuccess)
746 {
747 pIf->cPipes = 0;
748 if (irc == kIOReturnNoDevice)
749 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
750 else
751 rc = RTErrConvertFromDarwin(irc);
752 return rc;
753 }
754 AssertRelease(cPipes < RT_ELEMENTS(pIf->aPipes));
755 pIf->cPipes = cPipes + 1;
756
757 /* Find out if this is a full-speed interface (needed for isochronous support). */
758 irc = (*pIf->ppIfI)->GetFrameListTime(pIf->ppIfI, &u32UsecInFrame);
759 if (irc != kIOReturnSuccess)
760 {
761 pIf->cPipes = 0;
762 if (irc == kIOReturnNoDevice)
763 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
764 else
765 rc = RTErrConvertFromDarwin(irc);
766 return rc;
767 }
768 fFullSpeed = u32UsecInFrame == kUSBFullSpeedMicrosecondsInFrame;
769
770 /*
771 * Get the properties of each pipe.
772 */
773 for (unsigned i = 0; i < pIf->cPipes; i++)
774 {
775 pIf->aPipes[i].u8PipeRef = i;
776 pIf->aPipes[i].fIsFullSpeed = fFullSpeed;
777 pIf->aPipes[i].u64NextFrameNo = 0;
778 irc = (*pIf->ppIfI)->GetPipeProperties(pIf->ppIfI, i,
779 &pIf->aPipes[i].u8Direction,
780 &pIf->aPipes[i].u8Endpoint,
781 &pIf->aPipes[i].u8TransferType,
782 &pIf->aPipes[i].u16MaxPacketSize,
783 &pIf->aPipes[i].u8Interval);
784 if (irc != kIOReturnSuccess)
785 {
786 LogRel(("USB: Failed to query properties for pipe %#d / interface %#x on device '%s'. (prot=%#x class=%#x)\n",
787 i, pIf->u8Interface, pDevOsX->pProxyDev->pUsbIns->pszName, pIf->u8Protocol, pIf->u8Class));
788 if (irc == kIOReturnNoDevice)
789 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
790 else
791 rc = RTErrConvertFromDarwin(irc);
792 pIf->cPipes = i;
793 break;
794 }
795 /* reconstruct bEndpoint */
796 if (pIf->aPipes[i].u8Direction == kUSBIn)
797 pIf->aPipes[i].u8Endpoint |= 0x80;
798 Log2(("usbProxyDarwinGetPipeProperties: #If=%d EndPt=%#x Dir=%d Type=%d PipeRef=%#x MaxPktSize=%#x Interval=%#x\n",
799 pIf->u8Interface, pIf->aPipes[i].u8Endpoint, pIf->aPipes[i].u8Direction, pIf->aPipes[i].u8TransferType,
800 pIf->aPipes[i].u8PipeRef, pIf->aPipes[i].u16MaxPacketSize, pIf->aPipes[i].u8Interval));
801 }
802
803 /** @todo sort or hash these for speedy lookup... */
804 return VINF_SUCCESS;
805}
806
807
808/**
809 * Seize all interfaces (current config).
810 *
811 * @returns VBox status code.
812 * @param pDevOsX The darwin proxy device.
813 * @param fMakeTheBestOfIt If set we will not give up on error. This is for
814 * use during SET_CONFIGURATION and similar.
815 */
816static int usbProxyDarwinSeizeAllInterfaces(PUSBPROXYDEVOSX pDevOsX, bool fMakeTheBestOfIt)
817{
818 PUSBPROXYDEV pProxyDev = pDevOsX->pProxyDev;
819
820 RTCritSectEnter(&pDevOsX->CritSect);
821
822 /*
823 * Create a interface enumerator for all the interface (current config).
824 */
825 io_iterator_t Interfaces = IO_OBJECT_NULL;
826 IOUSBFindInterfaceRequest Req;
827 Req.bInterfaceClass = kIOUSBFindInterfaceDontCare;
828 Req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
829 Req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
830 Req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
831 IOReturn irc = (*pDevOsX->ppDevI)->CreateInterfaceIterator(pDevOsX->ppDevI, &Req, &Interfaces);
832 int rc;
833 if (irc == kIOReturnSuccess)
834 {
835 /*
836 * Iterate the interfaces.
837 */
838 io_object_t Interface;
839 rc = VINF_SUCCESS;
840 while ((Interface = IOIteratorNext(Interfaces)))
841 {
842 /*
843 * Create a plug-in and query the IOUSBInterfaceInterface (cute name).
844 */
845 IOCFPlugInInterface **ppPlugInInterface = NULL;
846 kern_return_t krc;
847 SInt32 Score = 0;
848 krc = IOCreatePlugInInterfaceForService(Interface, kIOUSBInterfaceUserClientTypeID,
849 kIOCFPlugInInterfaceID, &ppPlugInInterface, &Score);
850 IOObjectRelease(Interface);
851 Interface = IO_OBJECT_NULL;
852 if (krc == KERN_SUCCESS)
853 {
854 IOUSBInterfaceInterface245 **ppIfI;
855 HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
856 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID245),
857 (LPVOID *)&ppIfI);
858 krc = IODestroyPlugInInterface(ppPlugInInterface); Assert(krc == KERN_SUCCESS);
859 ppPlugInInterface = NULL;
860 if (hrc == S_OK)
861 {
862 /*
863 * Query some basic properties first.
864 * (This means we can print more informative messages on failure
865 * to seize the interface.)
866 */
867 UInt8 u8Interface = 0xff;
868 irc = (*ppIfI)->GetInterfaceNumber(ppIfI, &u8Interface);
869 UInt8 u8AltSetting = 0xff;
870 if (irc == kIOReturnSuccess)
871 irc = (*ppIfI)->GetAlternateSetting(ppIfI, &u8AltSetting);
872 UInt8 u8Class = 0xff;
873 if (irc == kIOReturnSuccess)
874 irc = (*ppIfI)->GetInterfaceClass(ppIfI, &u8Class);
875 UInt8 u8Protocol = 0xff;
876 if (irc == kIOReturnSuccess)
877 irc = (*ppIfI)->GetInterfaceProtocol(ppIfI, &u8Protocol);
878 UInt8 cEndpoints = 0;
879 if (irc == kIOReturnSuccess)
880 irc = (*ppIfI)->GetNumEndpoints(ppIfI, &cEndpoints);
881 if (irc == kIOReturnSuccess)
882 {
883 /*
884 * Try seize the interface.
885 */
886 irc = (*ppIfI)->USBInterfaceOpenSeize(ppIfI);
887 if (irc == kIOReturnSuccess)
888 {
889 PUSBPROXYIFOSX pIf = (PUSBPROXYIFOSX)RTMemAllocZ(sizeof(*pIf));
890 if (pIf)
891 {
892 /*
893 * Create the per-interface entry and query the
894 * endpoint data.
895 */
896 /* initialize the entry */
897 pIf->u8Interface = u8Interface;
898 pIf->u8AltSetting = u8AltSetting;
899 pIf->u8Class = u8Class;
900 pIf->u8Protocol = u8Protocol;
901 pIf->cPipes = cEndpoints;
902 pIf->ppIfI = ppIfI;
903
904 /* query pipe/endpoint properties. */
905 rc = usbProxyDarwinGetPipeProperties(pDevOsX, pIf);
906 if (RT_SUCCESS(rc))
907 {
908 /*
909 * Create the async event source and add it to the
910 * default current run loop.
911 * (Later: Add to the worker thread run loop instead.)
912 */
913 irc = (*ppIfI)->CreateInterfaceAsyncEventSource(ppIfI, &pIf->RunLoopSrcRef);
914 if (irc == kIOReturnSuccess)
915 {
916 RTListInit((PRTLISTNODE)&pIf->HeadOfRunLoopLst);
917 usbProxyDarwinAddRunLoopRef(&pIf->HeadOfRunLoopLst,
918 pIf->RunLoopSrcRef);
919
920 /*
921 * Just link the interface into the list and we're good.
922 */
923 pIf->pNext = NULL;
924 Log(("USB: Seized interface %#x (alt=%d prot=%#x class=%#x)\n",
925 u8Interface, u8AltSetting, u8Protocol, u8Class));
926 if (pDevOsX->pIfTail)
927 pDevOsX->pIfTail = pDevOsX->pIfTail->pNext = pIf;
928 else
929 pDevOsX->pIfTail = pDevOsX->pIfHead = pIf;
930 continue;
931 }
932 rc = RTErrConvertFromDarwin(irc);
933 }
934
935 /* failure cleanup. */
936 RTMemFree(pIf);
937 }
938 }
939 else if (irc == kIOReturnExclusiveAccess)
940 {
941 LogRel(("USB: Interface %#x on device '%s' is being used by another process. (prot=%#x class=%#x)\n",
942 u8Interface, pProxyDev->pUsbIns->pszName, u8Protocol, u8Class));
943 rc = VERR_SHARING_VIOLATION;
944 }
945 else
946 {
947 LogRel(("USB: Failed to open interface %#x on device '%s'. (prot=%#x class=%#x) krc=%#x\n",
948 u8Interface, pProxyDev->pUsbIns->pszName, u8Protocol, u8Class, irc));
949 rc = VERR_OPEN_FAILED;
950 }
951 }
952 else
953 {
954 rc = RTErrConvertFromDarwin(irc);
955 LogRel(("USB: Failed to query interface properties on device '%s', irc=%#x.\n",
956 pProxyDev->pUsbIns->pszName, irc));
957 }
958 (*ppIfI)->Release(ppIfI);
959 ppIfI = NULL;
960 }
961 else if (RT_SUCCESS(rc))
962 rc = RTErrConvertFromDarwinCOM(hrc);
963 }
964 else if (RT_SUCCESS(rc))
965 rc = RTErrConvertFromDarwin(krc);
966 if (!fMakeTheBestOfIt)
967 {
968 usbProxyDarwinReleaseAllInterfaces(pDevOsX);
969 break;
970 }
971 } /* iterate */
972 IOObjectRelease(Interfaces);
973 }
974 else if (irc == kIOReturnNoDevice)
975 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
976 else
977 {
978 AssertMsgFailed(("%#x\n", irc));
979 rc = VERR_GENERAL_FAILURE;
980 }
981
982 RTCritSectLeave(&pDevOsX->CritSect);
983 return rc;
984}
985
986
987/**
988 * Find a particular interface.
989 *
990 * @returns The requested interface or NULL if not found.
991 * @param pDevOsX The darwin proxy device.
992 * @param u8Interface The interface number.
993 */
994static PUSBPROXYIFOSX usbProxyDarwinGetInterface(PUSBPROXYDEVOSX pDevOsX, uint8_t u8Interface)
995{
996 if (!pDevOsX->pIfHead)
997 usbProxyDarwinSeizeAllInterfaces(pDevOsX, true /* make the best out of it */);
998
999 PUSBPROXYIFOSX pIf;
1000 for (pIf = pDevOsX->pIfHead; pIf; pIf = pIf->pNext)
1001 if (pIf->u8Interface == u8Interface)
1002 return pIf;
1003
1004/* AssertMsgFailed(("Cannot find If#=%d\n", u8Interface)); - the 3rd quickcam interface is capture by the ****ing audio crap. */
1005 return NULL;
1006}
1007
1008
1009/**
1010 * Find a particular endpoint.
1011 *
1012 * @returns The requested interface or NULL if not found.
1013 * @param pDevOsX The darwin proxy device.
1014 * @param u8Endpoint The endpoint.
1015 * @param pu8PipeRef Where to store the darwin pipe ref.
1016 * @param ppPipe Where to store the darwin pipe pointer. (optional)
1017 */
1018static PUSBPROXYIFOSX usbProxyDarwinGetInterfaceForEndpoint(PUSBPROXYDEVOSX pDevOsX, uint8_t u8Endpoint,
1019 uint8_t *pu8PipeRef, PPUSBPROXYPIPEOSX ppPipe)
1020{
1021 if (!pDevOsX->pIfHead)
1022 usbProxyDarwinSeizeAllInterfaces(pDevOsX, true /* make the best out of it */);
1023
1024 PUSBPROXYIFOSX pIf;
1025 for (pIf = pDevOsX->pIfHead; pIf; pIf = pIf->pNext)
1026 {
1027 unsigned i = pIf->cPipes;
1028 while (i-- > 0)
1029 if (pIf->aPipes[i].u8Endpoint == u8Endpoint)
1030 {
1031 *pu8PipeRef = pIf->aPipes[i].u8PipeRef;
1032 if (ppPipe)
1033 *ppPipe = &pIf->aPipes[i];
1034 return pIf;
1035 }
1036 }
1037
1038 AssertMsgFailed(("Cannot find EndPt=%#x\n", u8Endpoint));
1039 return NULL;
1040}
1041
1042
1043/**
1044 * Gets an unsigned 32-bit integer value.
1045 *
1046 * @returns Success indicator (true/false).
1047 * @param DictRef The dictionary.
1048 * @param KeyStrRef The key name.
1049 * @param pu32 Where to store the key value.
1050 */
1051static bool usbProxyDarwinDictGetU32(CFMutableDictionaryRef DictRef, CFStringRef KeyStrRef, uint32_t *pu32)
1052{
1053 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
1054 if (ValRef)
1055 {
1056 if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt32Type, pu32))
1057 return true;
1058 }
1059 *pu32 = 0;
1060 return false;
1061}
1062
1063
1064/**
1065 * Gets an unsigned 64-bit integer value.
1066 *
1067 * @returns Success indicator (true/false).
1068 * @param DictRef The dictionary.
1069 * @param KeyStrRef The key name.
1070 * @param pu64 Where to store the key value.
1071 */
1072static bool usbProxyDarwinDictGetU64(CFMutableDictionaryRef DictRef, CFStringRef KeyStrRef, uint64_t *pu64)
1073{
1074 CFTypeRef ValRef = CFDictionaryGetValue(DictRef, KeyStrRef);
1075 if (ValRef)
1076 {
1077 if (CFNumberGetValue((CFNumberRef)ValRef, kCFNumberSInt64Type, pu64))
1078 return true;
1079 }
1080 *pu64 = 0;
1081 return false;
1082}
1083
1084
1085static DECLCALLBACK(void) usbProxyDarwinPerformWakeup(void *pInfo)
1086{
1087 RT_NOREF(pInfo);
1088 return;
1089}
1090
1091
1092/* -=-=-=-=-=- The exported methods -=-=-=-=-=- */
1093
1094/**
1095 * Opens the USB Device.
1096 *
1097 * @returns VBox status code.
1098 * @param pProxyDev The device instance.
1099 * @param pszAddress The session id and/or location id of the device to open.
1100 * The format of this string is something iokit.c in Main defines, currently
1101 * it's sequences of "[l|s]=<value>" separated by ";".
1102 * @param pvBackend Backend specific pointer, unused for the Darwin backend.
1103 */
1104static DECLCALLBACK(int) usbProxyDarwinOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
1105{
1106 RT_NOREF(pvBackend);
1107 LogFlow(("usbProxyDarwinOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
1108
1109 /*
1110 * Init globals once.
1111 */
1112 int vrc = RTOnce(&g_usbProxyDarwinOnce, usbProxyDarwinInitOnce, NULL);
1113 AssertRCReturn(vrc, vrc);
1114
1115 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1116
1117 /*
1118 * The idea here was to create a matching directory with the sessionID
1119 * and locationID included, however this doesn't seem to work. So, we'll
1120 * use the product id and vendor id to limit the set of matching device
1121 * and manually match these two properties. sigh.
1122 * (Btw. vendor and product id must be used *together* apparently.)
1123 *
1124 * Wonder if we could use the entry path? Docs indicates says we must
1125 * use IOServiceGetMatchingServices and I'm not in a mood to explore
1126 * this subject further right now. Maybe check this later.
1127 */
1128 CFMutableDictionaryRef RefMatchingDict = IOServiceMatching(kIOUSBDeviceClassName);
1129 AssertReturn(RefMatchingDict != NULL, VERR_OPEN_FAILED);
1130
1131 uint64_t u64SessionId = 0;
1132 uint32_t u32LocationId = 0;
1133 const char *psz = pszAddress;
1134 do
1135 {
1136 const char chValue = *psz;
1137 AssertReleaseReturn(psz[1] == '=', VERR_INTERNAL_ERROR);
1138 uint64_t u64Value;
1139 int rc = RTStrToUInt64Ex(psz + 2, (char **)&psz, 0, &u64Value);
1140 AssertReleaseRCReturn(rc, rc);
1141 AssertReleaseReturn(!*psz || *psz == ';', rc);
1142 switch (chValue)
1143 {
1144 case 'l':
1145 u32LocationId = (uint32_t)u64Value;
1146 break;
1147 case 's':
1148 u64SessionId = u64Value;
1149 break;
1150 case 'p':
1151 case 'v':
1152 {
1153#if 0 /* Guess what, this doesn't 'ing work either! */
1154 SInt32 i32 = (int16_t)u64Value;
1155 CFNumberRef Num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i32);
1156 AssertBreak(Num);
1157 CFDictionarySetValue(RefMatchingDict, chValue == 'p' ? CFSTR(kUSBProductID) : CFSTR(kUSBVendorID), Num);
1158 CFRelease(Num);
1159#endif
1160 break;
1161 }
1162 default:
1163 AssertReleaseMsgFailedReturn(("chValue=%#x\n", chValue), VERR_INTERNAL_ERROR);
1164 }
1165 if (*psz == ';')
1166 psz++;
1167 } while (*psz);
1168
1169 io_iterator_t USBDevices = IO_OBJECT_NULL;
1170 IOReturn irc = IOServiceGetMatchingServices(g_MasterPort, RefMatchingDict, &USBDevices);
1171 AssertMsgReturn(irc == kIOReturnSuccess, ("irc=%#x\n", irc), RTErrConvertFromDarwinIO(irc));
1172 RefMatchingDict = NULL; /* the reference is consumed by IOServiceGetMatchingServices. */
1173
1174 unsigned cMatches = 0;
1175 io_object_t USBDevice;
1176 while ((USBDevice = IOIteratorNext(USBDevices)))
1177 {
1178 cMatches++;
1179 CFMutableDictionaryRef PropsRef = 0;
1180 kern_return_t krc = IORegistryEntryCreateCFProperties(USBDevice, &PropsRef, kCFAllocatorDefault, kNilOptions);
1181 if (krc == KERN_SUCCESS)
1182 {
1183 uint64_t u64CurSessionId;
1184 uint32_t u32CurLocationId;
1185 if ( ( !u64SessionId
1186 || ( usbProxyDarwinDictGetU64(PropsRef, CFSTR("sessionID"), &u64CurSessionId)
1187 && u64CurSessionId == u64SessionId))
1188 && ( !u32LocationId
1189 || ( usbProxyDarwinDictGetU32(PropsRef, CFSTR(kUSBDevicePropertyLocationID), &u32CurLocationId)
1190 && u32CurLocationId == u32LocationId))
1191 )
1192 {
1193 CFRelease(PropsRef);
1194 break;
1195 }
1196 CFRelease(PropsRef);
1197 }
1198 IOObjectRelease(USBDevice);
1199 }
1200 IOObjectRelease(USBDevices);
1201 USBDevices = IO_OBJECT_NULL;
1202 if (!USBDevice)
1203 {
1204 LogRel(("USB: Device '%s' not found (%d pid+vid matches)\n", pszAddress, cMatches));
1205 IOObjectRelease(USBDevices);
1206 return VERR_VUSB_DEVICE_NAME_NOT_FOUND;
1207 }
1208
1209 /*
1210 * Call the USBLib init to make sure we're a valid VBoxUSB client.
1211 * For now we'll ignore failures here and just plunge on, it might still work...
1212 */
1213 vrc = USBLibInit();
1214 if (RT_FAILURE(vrc))
1215 LogRel(("USB: USBLibInit failed - %Rrc\n", vrc));
1216
1217 /*
1218 * Create a plugin interface for the device and query its IOUSBDeviceInterface.
1219 */
1220 SInt32 Score = 0;
1221 IOCFPlugInInterface **ppPlugInInterface = NULL;
1222 irc = IOCreatePlugInInterfaceForService(USBDevice, kIOUSBDeviceUserClientTypeID,
1223 kIOCFPlugInInterfaceID, &ppPlugInInterface, &Score);
1224 if (irc == kIOReturnSuccess)
1225 {
1226 IOUSBDeviceInterface245 **ppDevI = NULL;
1227 HRESULT hrc = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
1228 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245),
1229 (LPVOID *)&ppDevI);
1230 irc = IODestroyPlugInInterface(ppPlugInInterface); Assert(irc == kIOReturnSuccess);
1231 ppPlugInInterface = NULL;
1232 if (hrc == S_OK)
1233 {
1234 /*
1235 * Try open the device for exclusive access.
1236 * If we fail, we'll try figure out who is using the device and
1237 * convince them to let go of it...
1238 */
1239 irc = (*ppDevI)->USBDeviceReEnumerate(ppDevI, kUSBReEnumerateCaptureDeviceMask);
1240 Log(("USBDeviceReEnumerate (capture) returned irc=%#x\n", irc));
1241
1242 irc = (*ppDevI)->USBDeviceOpenSeize(ppDevI);
1243 if (irc == kIOReturnExclusiveAccess)
1244 {
1245 RTThreadSleep(20);
1246 irc = (*ppDevI)->USBDeviceOpenSeize(ppDevI);
1247 }
1248 if (irc == kIOReturnSuccess)
1249 {
1250 /*
1251 * Init a proxy device instance.
1252 */
1253 RTListInit((PRTLISTNODE)&pDevOsX->HeadOfRunLoopLst);
1254 vrc = RTCritSectInit(&pDevOsX->CritSect);
1255 if (RT_SUCCESS(vrc))
1256 {
1257 pDevOsX->USBDevice = USBDevice;
1258 pDevOsX->ppDevI = ppDevI;
1259 pDevOsX->pProxyDev = pProxyDev;
1260 pDevOsX->pTaxingHead = NULL;
1261 pDevOsX->pTaxingTail = NULL;
1262 pDevOsX->hRunLoopReapingLast = NULL;
1263
1264 /*
1265 * Try seize all the interface.
1266 */
1267 char *pszDummyName = pProxyDev->pUsbIns->pszName;
1268 pProxyDev->pUsbIns->pszName = (char *)pszAddress;
1269 vrc = usbProxyDarwinSeizeAllInterfaces(pDevOsX, false /* give up on failure */);
1270 pProxyDev->pUsbIns->pszName = pszDummyName;
1271 if (RT_SUCCESS(vrc))
1272 {
1273 /*
1274 * Create the async event source and add it to the run loop.
1275 */
1276 irc = (*ppDevI)->CreateDeviceAsyncEventSource(ppDevI, &pDevOsX->RunLoopSrcRef);
1277 if (irc == kIOReturnSuccess)
1278 {
1279 /*
1280 * Determine the active configuration.
1281 * Can cause hangs, so drop it for now.
1282 */
1283 /** @todo test Palm. */
1284 //uint8_t u8Cfg;
1285 //irc = (*ppDevI)->GetConfiguration(ppDevI, &u8Cfg);
1286 if (irc != kIOReturnNoDevice)
1287 {
1288 CFRunLoopSourceContext CtxRunLoopSource;
1289 CtxRunLoopSource.version = 0;
1290 CtxRunLoopSource.info = NULL;
1291 CtxRunLoopSource.retain = NULL;
1292 CtxRunLoopSource.release = NULL;
1293 CtxRunLoopSource.copyDescription = NULL;
1294 CtxRunLoopSource.equal = NULL;
1295 CtxRunLoopSource.hash = NULL;
1296 CtxRunLoopSource.schedule = NULL;
1297 CtxRunLoopSource.cancel = NULL;
1298 CtxRunLoopSource.perform = usbProxyDarwinPerformWakeup;
1299 pDevOsX->hRunLoopSrcWakeRef = CFRunLoopSourceCreate(NULL, 0, &CtxRunLoopSource);
1300 if (CFRunLoopSourceIsValid(pDevOsX->hRunLoopSrcWakeRef))
1301 {
1302 //pProxyDev->iActiveCfg = irc == kIOReturnSuccess ? u8Cfg : -1;
1303 RTListInit(&pDevOsX->HeadOfRunLoopWakeLst);
1304 pProxyDev->iActiveCfg = -1;
1305 pProxyDev->cIgnoreSetConfigs = 1;
1306
1307 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopLst, pDevOsX->RunLoopSrcRef);
1308 return VINF_SUCCESS; /* return */
1309 }
1310 else
1311 {
1312 LogRel(("USB: Device '%s' out of memory allocating runloop source\n", pszAddress));
1313 vrc = VERR_NO_MEMORY;
1314 }
1315 }
1316 vrc = VERR_VUSB_DEVICE_NOT_ATTACHED;
1317 }
1318 else
1319 vrc = RTErrConvertFromDarwin(irc);
1320
1321 usbProxyDarwinReleaseAllInterfaces(pDevOsX);
1322 }
1323 /* else: already bitched */
1324
1325 RTCritSectDelete(&pDevOsX->CritSect);
1326 }
1327
1328 irc = (*ppDevI)->USBDeviceClose(ppDevI);
1329 AssertMsg(irc == kIOReturnSuccess, ("%#x\n", irc));
1330 }
1331 else if (irc == kIOReturnExclusiveAccess)
1332 {
1333 LogRel(("USB: Device '%s' is being used by another process\n", pszAddress));
1334 vrc = VERR_SHARING_VIOLATION;
1335 }
1336 else
1337 {
1338 LogRel(("USB: Failed to open device '%s', irc=%#x.\n", pszAddress, irc));
1339 vrc = VERR_OPEN_FAILED;
1340 }
1341 }
1342 else
1343 {
1344 LogRel(("USB: Failed to create plugin interface for device '%s', hrc=%#x.\n", pszAddress, hrc));
1345 vrc = VERR_OPEN_FAILED;
1346 }
1347
1348 (*ppDevI)->Release(ppDevI);
1349 }
1350 else
1351 {
1352 LogRel(("USB: Failed to open device '%s', plug-in creation failed with irc=%#x.\n", pszAddress, irc));
1353 vrc = RTErrConvertFromDarwin(irc);
1354 }
1355
1356 USBLibTerm();
1357 return vrc;
1358}
1359
1360
1361/**
1362 * Closes the proxy device.
1363 */
1364static DECLCALLBACK(void) usbProxyDarwinClose(PUSBPROXYDEV pProxyDev)
1365{
1366 LogFlow(("usbProxyDarwinClose: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1367 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1368 AssertPtrReturnVoid(pDevOsX);
1369
1370 /*
1371 * Release interfaces we've laid claim to, then reset the device
1372 * and finally close it.
1373 */
1374 RTCritSectEnter(&pDevOsX->CritSect);
1375 /* ?? */
1376 RTCritSectLeave(&pDevOsX->CritSect);
1377
1378 usbProxyDarwinReleaseAllInterfaces(pDevOsX);
1379
1380 if (pDevOsX->RunLoopSrcRef)
1381 {
1382 int rc = usbProxyDarwinRemoveSourceRefFromAllRunLoops(&pDevOsX->HeadOfRunLoopLst, pDevOsX->RunLoopSrcRef);
1383 AssertRC(rc);
1384
1385 RTListInit((PRTLISTNODE)&pDevOsX->HeadOfRunLoopLst);
1386
1387 CFRelease(pDevOsX->RunLoopSrcRef);
1388 pDevOsX->RunLoopSrcRef = NULL;
1389 }
1390
1391 if (pDevOsX->hRunLoopSrcWakeRef)
1392 {
1393 int rc = usbProxyDarwinRemoveSourceRefFromAllRunLoops(&pDevOsX->HeadOfRunLoopWakeLst, pDevOsX->hRunLoopSrcWakeRef);
1394 AssertRC(rc);
1395
1396 RTListInit((PRTLISTNODE)&pDevOsX->HeadOfRunLoopWakeLst);
1397
1398 CFRelease(pDevOsX->hRunLoopSrcWakeRef);
1399 pDevOsX->hRunLoopSrcWakeRef = NULL;
1400 }
1401
1402 IOReturn irc = (*pDevOsX->ppDevI)->ResetDevice(pDevOsX->ppDevI);
1403
1404 irc = (*pDevOsX->ppDevI)->USBDeviceClose(pDevOsX->ppDevI);
1405 if (irc != kIOReturnSuccess && irc != kIOReturnNoDevice)
1406 {
1407 LogRel(("USB: USBDeviceClose -> %#x\n", irc));
1408 AssertMsgFailed(("irc=%#x\n", irc));
1409 }
1410
1411 irc = (*pDevOsX->ppDevI)->USBDeviceReEnumerate(pDevOsX->ppDevI, kUSBReEnumerateReleaseDeviceMask);
1412 Log(("USBDeviceReEnumerate (release) returned irc=%#x\n", irc));
1413
1414 (*pDevOsX->ppDevI)->Release(pDevOsX->ppDevI);
1415 pDevOsX->ppDevI = NULL;
1416 kern_return_t krc = IOObjectRelease(pDevOsX->USBDevice); Assert(krc == KERN_SUCCESS); NOREF(krc);
1417 pDevOsX->USBDevice = IO_OBJECT_NULL;
1418 pDevOsX->pProxyDev = NULL;
1419
1420 /*
1421 * Free all the resources.
1422 */
1423 RTCritSectDelete(&pDevOsX->CritSect);
1424
1425 PUSBPROXYURBOSX pUrbOsX;
1426 while ((pUrbOsX = pDevOsX->pFreeHead) != NULL)
1427 {
1428 pDevOsX->pFreeHead = pUrbOsX->pNext;
1429 RTMemFree(pUrbOsX);
1430 }
1431
1432 USBLibTerm();
1433 LogFlow(("usbProxyDarwinClose: returns\n"));
1434}
1435
1436
1437/** @interface_method_impl{USBPROXYBACK,pfnReset}*/
1438static DECLCALLBACK(int) usbProxyDarwinReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
1439{
1440 RT_NOREF(fResetOnLinux);
1441 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1442 LogFlow(("usbProxyDarwinReset: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1443
1444 IOReturn irc = (*pDevOsX->ppDevI)->ResetDevice(pDevOsX->ppDevI);
1445 int rc;
1446 if (irc == kIOReturnSuccess)
1447 {
1448 /** @todo Some docs say that some drivers will do a default config, check this out ... */
1449 pProxyDev->cIgnoreSetConfigs = 0;
1450 pProxyDev->iActiveCfg = -1;
1451
1452 rc = VINF_SUCCESS;
1453 }
1454 else if (irc == kIOReturnNoDevice)
1455 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
1456 else
1457 {
1458 AssertMsgFailed(("irc=%#x\n", irc));
1459 rc = VERR_GENERAL_FAILURE;
1460 }
1461
1462 LogFlow(("usbProxyDarwinReset: returns success %Rrc\n", rc));
1463 return rc;
1464}
1465
1466
1467/**
1468 * SET_CONFIGURATION.
1469 *
1470 * The caller makes sure that it's not called first time after open or reset
1471 * with the active interface.
1472 *
1473 * @returns success indicator.
1474 * @param pProxyDev The device instance data.
1475 * @param iCfg The configuration to set.
1476 */
1477static DECLCALLBACK(int) usbProxyDarwinSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
1478{
1479 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1480 LogFlow(("usbProxyDarwinSetConfig: pProxyDev=%s cfg=%#x\n",
1481 pProxyDev->pUsbIns->pszName, iCfg));
1482
1483 IOReturn irc = (*pDevOsX->ppDevI)->SetConfiguration(pDevOsX->ppDevI, (uint8_t)iCfg);
1484 if (irc != kIOReturnSuccess)
1485 {
1486 Log(("usbProxyDarwinSetConfig: Set configuration -> %#x\n", irc));
1487 return RTErrConvertFromDarwin(irc);
1488 }
1489
1490 usbProxyDarwinReleaseAllInterfaces(pDevOsX);
1491 usbProxyDarwinSeizeAllInterfaces(pDevOsX, true /* make the best out of it */);
1492 return VINF_SUCCESS;
1493}
1494
1495
1496/**
1497 * Claims an interface.
1498 *
1499 * This is a stub on Darwin since we release/claim all interfaces at
1500 * open/reset/setconfig time.
1501 *
1502 * @returns success indicator (always VINF_SUCCESS).
1503 */
1504static DECLCALLBACK(int) usbProxyDarwinClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
1505{
1506 RT_NOREF(pProxyDev, iIf);
1507 return VINF_SUCCESS;
1508}
1509
1510
1511/**
1512 * Releases an interface.
1513 *
1514 * This is a stub on Darwin since we release/claim all interfaces at
1515 * open/reset/setconfig time.
1516 *
1517 * @returns success indicator.
1518 */
1519static DECLCALLBACK(int) usbProxyDarwinReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
1520{
1521 RT_NOREF(pProxyDev, iIf);
1522 return VINF_SUCCESS;
1523}
1524
1525
1526/**
1527 * SET_INTERFACE.
1528 *
1529 * @returns success indicator.
1530 */
1531static DECLCALLBACK(int) usbProxyDarwinSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
1532{
1533 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1534 IOReturn irc = kIOReturnSuccess;
1535 PUSBPROXYIFOSX pIf = usbProxyDarwinGetInterface(pDevOsX, iIf);
1536 LogFlow(("usbProxyDarwinSetInterface: pProxyDev=%s iIf=%#x iAlt=%#x iCurAlt=%#x\n",
1537 pProxyDev->pUsbIns->pszName, iIf, iAlt, pIf ? pIf->u8AltSetting : 0xbeef));
1538 if (pIf)
1539 {
1540 /* Avoid SetAlternateInterface when possible as it will recreate the pipes. */
1541 if (iAlt != pIf->u8AltSetting)
1542 {
1543 irc = (*pIf->ppIfI)->SetAlternateInterface(pIf->ppIfI, iAlt);
1544 if (irc == kIOReturnSuccess)
1545 {
1546 usbProxyDarwinGetPipeProperties(pDevOsX, pIf);
1547 return VINF_SUCCESS;
1548 }
1549 }
1550 else
1551 {
1552 /*
1553 * Just send the request anyway?
1554 */
1555 IOUSBDevRequest Req;
1556 Req.bmRequestType = 0x01;
1557 Req.bRequest = 0x0b; /* SET_INTERFACE */
1558 Req.wIndex = iIf;
1559 Req.wValue = iAlt;
1560 Req.wLength = 0;
1561 Req.wLenDone = 0;
1562 Req.pData = NULL;
1563 irc = (*pDevOsX->ppDevI)->DeviceRequest(pDevOsX->ppDevI, &Req);
1564 Log(("usbProxyDarwinSetInterface: SET_INTERFACE(%d,%d) -> irc=%#x\n", iIf, iAlt, irc));
1565 return VINF_SUCCESS;
1566 }
1567 }
1568
1569 LogFlow(("usbProxyDarwinSetInterface: pProxyDev=%s eiIf=%#x iAlt=%#x - failure - pIf=%p irc=%#x\n",
1570 pProxyDev->pUsbIns->pszName, iIf, iAlt, pIf, irc));
1571 return RTErrConvertFromDarwin(irc);
1572}
1573
1574
1575/**
1576 * Clears the halted endpoint 'EndPt'.
1577 */
1578static DECLCALLBACK(int) usbProxyDarwinClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
1579{
1580 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1581 LogFlow(("usbProxyDarwinClearHaltedEp: pProxyDev=%s EndPt=%#x\n", pProxyDev->pUsbIns->pszName, EndPt));
1582
1583 /*
1584 * Clearing the zero control pipe doesn't make sense and isn't
1585 * supported by the API. Just ignore it.
1586 */
1587 if (EndPt == 0)
1588 return VINF_SUCCESS;
1589
1590 /*
1591 * Find the interface/pipe combination and invoke the ClearPipeStallBothEnds
1592 * method. (The ResetPipe and ClearPipeStall methods will not send the
1593 * CLEAR_FEATURE(ENDPOINT_HALT) request that this method implements.)
1594 */
1595 IOReturn irc = kIOReturnSuccess;
1596 uint8_t u8PipeRef;
1597 PUSBPROXYIFOSX pIf = usbProxyDarwinGetInterfaceForEndpoint(pDevOsX, EndPt, &u8PipeRef, NULL);
1598 if (pIf)
1599 {
1600 irc = (*pIf->ppIfI)->ClearPipeStallBothEnds(pIf->ppIfI, u8PipeRef);
1601 if (irc == kIOReturnSuccess)
1602 return VINF_SUCCESS;
1603 AssertMsg(irc == kIOReturnNoDevice || irc == kIOReturnNotResponding, ("irc=#x (control pipe?)\n", irc));
1604 }
1605
1606 LogFlow(("usbProxyDarwinClearHaltedEp: pProxyDev=%s EndPt=%#x - failure - pIf=%p irc=%#x\n",
1607 pProxyDev->pUsbIns->pszName, EndPt, pIf, irc));
1608 return RTErrConvertFromDarwin(irc);
1609}
1610
1611
1612/**
1613 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
1614 */
1615static DECLCALLBACK(int) usbProxyDarwinUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1616{
1617 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1618 LogFlow(("%s: usbProxyDarwinUrbQueue: pProxyDev=%s pUrb=%p EndPt=%d cbData=%d\n",
1619 pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, pUrb->cbData));
1620
1621 /*
1622 * Find the target interface / pipe.
1623 */
1624 uint8_t u8PipeRef = 0xff;
1625 PUSBPROXYIFOSX pIf = NULL;
1626 PUSBPROXYPIPEOSX pPipe = NULL;
1627 if (pUrb->EndPt)
1628 {
1629 /* Make sure the interface is there. */
1630 const uint8_t EndPt = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
1631 pIf = usbProxyDarwinGetInterfaceForEndpoint(pDevOsX, EndPt, &u8PipeRef, &pPipe);
1632 if (!pIf)
1633 {
1634 LogFlow(("%s: usbProxyDarwinUrbQueue: pProxyDev=%s EndPt=%d cbData=%d - can't find interface / pipe!!!\n",
1635 pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb->EndPt, pUrb->cbData));
1636 return VERR_NOT_FOUND;
1637 }
1638 }
1639 /* else: pIf == NULL -> default control pipe.*/
1640
1641 /*
1642 * Allocate a Darwin urb.
1643 */
1644 PUSBPROXYURBOSX pUrbOsX = usbProxyDarwinUrbAlloc(pDevOsX);
1645 if (!pUrbOsX)
1646 return VERR_NO_MEMORY;
1647
1648 pUrbOsX->u64SubmitTS = RTTimeMilliTS();
1649 pUrbOsX->pVUsbUrb = pUrb;
1650 pUrbOsX->pDevOsX = pDevOsX;
1651 pUrbOsX->enmType = pUrb->enmType;
1652
1653 /*
1654 * Submit the request.
1655 */
1656 IOReturn irc = kIOReturnError;
1657 switch (pUrb->enmType)
1658 {
1659 case VUSBXFERTYPE_MSG:
1660 {
1661 AssertMsgBreak(pUrb->cbData >= sizeof(VUSBSETUP), ("cbData=%d\n", pUrb->cbData));
1662 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1663 pUrbOsX->u.ControlMsg.bmRequestType = pSetup->bmRequestType;
1664 pUrbOsX->u.ControlMsg.bRequest = pSetup->bRequest;
1665 pUrbOsX->u.ControlMsg.wValue = pSetup->wValue;
1666 pUrbOsX->u.ControlMsg.wIndex = pSetup->wIndex;
1667 pUrbOsX->u.ControlMsg.wLength = pSetup->wLength;
1668 pUrbOsX->u.ControlMsg.pData = pSetup + 1;
1669 pUrbOsX->u.ControlMsg.wLenDone = pSetup->wLength;
1670
1671 if (pIf)
1672 irc = (*pIf->ppIfI)->ControlRequestAsync(pIf->ppIfI, u8PipeRef, &pUrbOsX->u.ControlMsg,
1673 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1674 else
1675 irc = (*pDevOsX->ppDevI)->DeviceRequestAsync(pDevOsX->ppDevI, &pUrbOsX->u.ControlMsg,
1676 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1677 break;
1678 }
1679
1680 case VUSBXFERTYPE_BULK:
1681 case VUSBXFERTYPE_INTR:
1682 {
1683 AssertBreak(pIf);
1684 Assert(pUrb->enmDir == VUSBDIRECTION_IN || pUrb->enmDir == VUSBDIRECTION_OUT);
1685 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1686 irc = (*pIf->ppIfI)->WritePipeAsync(pIf->ppIfI, u8PipeRef, pUrb->abData, pUrb->cbData,
1687 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1688 else
1689 irc = (*pIf->ppIfI)->ReadPipeAsync(pIf->ppIfI, u8PipeRef, pUrb->abData, pUrb->cbData,
1690 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1691
1692 break;
1693 }
1694
1695 case VUSBXFERTYPE_ISOC:
1696 {
1697 AssertBreak(pIf);
1698 Assert(pUrb->enmDir == VUSBDIRECTION_IN || pUrb->enmDir == VUSBDIRECTION_OUT);
1699
1700#ifdef USE_LOW_LATENCY_API
1701 /* Allocate an isochronous buffer and copy over the data. */
1702 AssertBreak(pUrb->cbData <= 8192);
1703 int rc = usbProxyDarwinUrbAllocIsocBuf(pUrbOsX, pIf);
1704 AssertRCBreak(rc);
1705 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1706 memcpy(pUrbOsX->u.Isoc.pBuf->pvBuf, pUrb->abData, pUrb->cbData);
1707 else
1708 memset(pUrbOsX->u.Isoc.pBuf->pvBuf, 0xfe, pUrb->cbData);
1709#endif
1710
1711 /* Get the current frame number (+2) and make sure it doesn't
1712 overlap with the previous request. See WARNING in
1713 ApplUSBUHCI::CreateIsochTransfer for details on the +2. */
1714 UInt64 FrameNo;
1715 AbsoluteTime FrameTime;
1716 irc = (*pIf->ppIfI)->GetBusFrameNumber(pIf->ppIfI, &FrameNo, &FrameTime);
1717 AssertMsg(irc == kIOReturnSuccess, ("GetBusFrameNumber -> %#x\n", irc));
1718 FrameNo += 2;
1719 if (FrameNo <= pPipe->u64NextFrameNo)
1720 FrameNo = pPipe->u64NextFrameNo;
1721
1722 for (unsigned j = 0; ; j++)
1723 {
1724 unsigned i;
1725 for (i = 0; i < pUrb->cIsocPkts; i++)
1726 {
1727 pUrbOsX->u.Isoc.aFrames[i].frReqCount = pUrb->aIsocPkts[i].cb;
1728 pUrbOsX->u.Isoc.aFrames[i].frActCount = 0;
1729 pUrbOsX->u.Isoc.aFrames[i].frStatus = kIOUSBNotSent1Err;
1730#ifdef USE_LOW_LATENCY_API
1731 pUrbOsX->u.Isoc.aFrames[i].frTimeStamp.hi = 0;
1732 pUrbOsX->u.Isoc.aFrames[i].frTimeStamp.lo = 0;
1733#endif
1734 }
1735 for (; i < RT_ELEMENTS(pUrbOsX->u.Isoc.aFrames); i++)
1736 {
1737 pUrbOsX->u.Isoc.aFrames[i].frReqCount = 0;
1738 pUrbOsX->u.Isoc.aFrames[i].frActCount = 0;
1739 pUrbOsX->u.Isoc.aFrames[i].frStatus = kIOReturnError;
1740#ifdef USE_LOW_LATENCY_API
1741 pUrbOsX->u.Isoc.aFrames[i].frTimeStamp.hi = 0;
1742 pUrbOsX->u.Isoc.aFrames[i].frTimeStamp.lo = 0;
1743#endif
1744 }
1745
1746#ifdef USE_LOW_LATENCY_API
1747 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1748 irc = (*pIf->ppIfI)->LowLatencyWriteIsochPipeAsync(pIf->ppIfI, u8PipeRef,
1749 pUrbOsX->u.Isoc.pBuf->pvBuf, FrameNo, pUrb->cIsocPkts, 0, pUrbOsX->u.Isoc.aFrames,
1750 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1751 else
1752 irc = (*pIf->ppIfI)->LowLatencyReadIsochPipeAsync(pIf->ppIfI, u8PipeRef,
1753 pUrbOsX->u.Isoc.pBuf->pvBuf, FrameNo, pUrb->cIsocPkts, 0, pUrbOsX->u.Isoc.aFrames,
1754 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1755#else
1756 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1757 irc = (*pIf->ppIfI)->WriteIsochPipeAsync(pIf->ppIfI, u8PipeRef,
1758 pUrb->abData, FrameNo, pUrb->cIsocPkts, &pUrbOsX->u.Isoc.aFrames[0],
1759 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1760 else
1761 irc = (*pIf->ppIfI)->ReadIsochPipeAsync(pIf->ppIfI, u8PipeRef,
1762 pUrb->abData, FrameNo, pUrb->cIsocPkts, &pUrbOsX->u.Isoc.aFrames[0],
1763 usbProxyDarwinUrbAsyncComplete, pUrbOsX);
1764#endif
1765 if ( irc != kIOReturnIsoTooOld
1766 || j >= 5)
1767 {
1768 Log(("%s: usbProxyDarwinUrbQueue: isoc: u64NextFrameNo=%RX64 FrameNo=%RX64 #Frames=%d j=%d (pipe=%d)\n",
1769 pUrb->pszDesc, pPipe->u64NextFrameNo, FrameNo, pUrb->cIsocPkts, j, u8PipeRef));
1770 if (irc == kIOReturnSuccess)
1771 {
1772 if (pPipe->fIsFullSpeed)
1773 pPipe->u64NextFrameNo = FrameNo + pUrb->cIsocPkts;
1774 else
1775 pPipe->u64NextFrameNo = FrameNo + 1;
1776 }
1777 break;
1778 }
1779
1780 /* try again... */
1781 irc = (*pIf->ppIfI)->GetBusFrameNumber(pIf->ppIfI, &FrameNo, &FrameTime);
1782 if (FrameNo <= pPipe->u64NextFrameNo)
1783 FrameNo = pPipe->u64NextFrameNo;
1784 FrameNo += j;
1785 }
1786 break;
1787 }
1788
1789 default:
1790 AssertMsgFailed(("%s: enmType=%#x\n", pUrb->pszDesc, pUrb->enmType));
1791 break;
1792 }
1793
1794 /*
1795 * Success?
1796 */
1797 if (RT_LIKELY(irc == kIOReturnSuccess))
1798 {
1799 Log(("%s: usbProxyDarwinUrbQueue: success\n", pUrb->pszDesc));
1800 return VINF_SUCCESS;
1801 }
1802 switch (irc)
1803 {
1804 case kIOUSBPipeStalled:
1805 {
1806 /* Increment in flight counter because the completion handler will decrease it always. */
1807 usbProxyDarwinUrbAsyncComplete(pUrbOsX, kIOUSBPipeStalled, 0);
1808 Log(("%s: usbProxyDarwinUrbQueue: pProxyDev=%s EndPt=%d cbData=%d - failed irc=%#x! (stall)\n",
1809 pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb->EndPt, pUrb->cbData, irc));
1810 return VINF_SUCCESS;
1811 }
1812 }
1813
1814 usbProxyDarwinUrbFree(pDevOsX, pUrbOsX);
1815 Log(("%s: usbProxyDarwinUrbQueue: pProxyDev=%s EndPt=%d cbData=%d - failed irc=%#x!\n",
1816 pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb->EndPt, pUrb->cbData, irc));
1817 return RTErrConvertFromDarwin(irc);
1818}
1819
1820
1821/**
1822 * Reap URBs in-flight on a device.
1823 *
1824 * @returns Pointer to a completed URB.
1825 * @returns NULL if no URB was completed.
1826 * @param pProxyDev The device.
1827 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
1828 */
1829static DECLCALLBACK(PVUSBURB) usbProxyDarwinUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1830{
1831 PVUSBURB pUrb = NULL;
1832 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1833 CFRunLoopRef hRunLoopRef = CFRunLoopGetCurrent();
1834
1835 Assert(!pDevOsX->hRunLoopReaping);
1836
1837 /*
1838 * If the last seen runloop for reaping differs we have to check whether the
1839 * the runloop sources are in the new runloop.
1840 */
1841 if (pDevOsX->hRunLoopReapingLast != hRunLoopRef)
1842 {
1843 RTCritSectEnter(&pDevOsX->CritSect);
1844
1845 /* Every pipe. */
1846 if (!pDevOsX->pIfHead)
1847 usbProxyDarwinSeizeAllInterfaces(pDevOsX, true /* make the best out of it */);
1848
1849 PUSBPROXYIFOSX pIf;
1850 for (pIf = pDevOsX->pIfHead; pIf; pIf = pIf->pNext)
1851 {
1852 if (!CFRunLoopContainsSource(hRunLoopRef, pIf->RunLoopSrcRef, g_pRunLoopMode))
1853 usbProxyDarwinAddRunLoopRef(&pIf->HeadOfRunLoopLst, pIf->RunLoopSrcRef);
1854 }
1855
1856 /* Default control pipe. */
1857 if (!CFRunLoopContainsSource(hRunLoopRef, pDevOsX->RunLoopSrcRef, g_pRunLoopMode))
1858 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopLst, pDevOsX->RunLoopSrcRef);
1859
1860 /* Runloop wakeup source. */
1861 if (!CFRunLoopContainsSource(hRunLoopRef, pDevOsX->hRunLoopSrcWakeRef, g_pRunLoopMode))
1862 usbProxyDarwinAddRunLoopRef(&pDevOsX->HeadOfRunLoopWakeLst, pDevOsX->hRunLoopSrcWakeRef);
1863 RTCritSectLeave(&pDevOsX->CritSect);
1864
1865 pDevOsX->hRunLoopReapingLast = hRunLoopRef;
1866 }
1867
1868 ASMAtomicXchgPtr((void * volatile *)&pDevOsX->hRunLoopReaping, hRunLoopRef);
1869
1870 if (ASMAtomicXchgBool(&pDevOsX->fReapingThreadWake, false))
1871 {
1872 /* Return immediately. */
1873 ASMAtomicXchgPtr((void * volatile *)&pDevOsX->hRunLoopReaping, NULL);
1874 return NULL;
1875 }
1876
1877 /*
1878 * Excercise the runloop until we get an URB or we time out.
1879 */
1880 if ( !pDevOsX->pTaxingHead
1881 && cMillies)
1882 CFRunLoopRunInMode(g_pRunLoopMode, cMillies / 1000.0, true);
1883
1884 ASMAtomicXchgPtr((void * volatile *)&pDevOsX->hRunLoopReaping, NULL);
1885 ASMAtomicXchgBool(&pDevOsX->fReapingThreadWake, false);
1886
1887 /*
1888 * Any URBs pending delivery?
1889 */
1890 while ( pDevOsX->pTaxingHead
1891 && !pUrb)
1892 {
1893 RTCritSectEnter(&pDevOsX->CritSect);
1894
1895 PUSBPROXYURBOSX pUrbOsX = pDevOsX->pTaxingHead;
1896 if (pUrbOsX)
1897 {
1898 /*
1899 * Remove from the taxing list.
1900 */
1901 if (pUrbOsX->pNext)
1902 pUrbOsX->pNext->pPrev = pUrbOsX->pPrev;
1903 else if (pDevOsX->pTaxingTail == pUrbOsX)
1904 pDevOsX->pTaxingTail = pUrbOsX->pPrev;
1905
1906 if (pUrbOsX->pPrev)
1907 pUrbOsX->pPrev->pNext = pUrbOsX->pNext;
1908 else if (pDevOsX->pTaxingHead == pUrbOsX)
1909 pDevOsX->pTaxingHead = pUrbOsX->pNext;
1910 else
1911 AssertFailed();
1912
1913 pUrb = pUrbOsX->pVUsbUrb;
1914 if (pUrb)
1915 {
1916 pUrb->Dev.pvPrivate = NULL;
1917 usbProxyDarwinUrbFree(pDevOsX, pUrbOsX);
1918 }
1919 }
1920 RTCritSectLeave(&pDevOsX->CritSect);
1921 }
1922
1923 if (pUrb)
1924 LogFlowFunc(("LEAVE: %s: pProxyDev=%s returns %p\n", pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb));
1925 else
1926 LogFlowFunc(("LEAVE: NULL pProxyDev=%s returns NULL\n", pProxyDev->pUsbIns->pszName));
1927
1928 return pUrb;
1929}
1930
1931
1932/**
1933 * Cancels a URB.
1934 *
1935 * The URB requires reaping, so we don't change its state.
1936 *
1937 * @remark There isn't any way to cancel a specific async request
1938 * on darwin. The interface only supports the aborting of
1939 * all URBs pending on an interface / pipe pair. Provided
1940 * the card does the URB cancelling before submitting new
1941 * requests, we should probably be fine...
1942 */
1943static DECLCALLBACK(int) usbProxyDarwinUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1944{
1945 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1946 LogFlow(("%s: usbProxyDarwinUrbCancel: pProxyDev=%s EndPt=%d\n",
1947 pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb->EndPt));
1948
1949 /*
1950 * Determine the interface / endpoint ref and invoke AbortPipe.
1951 */
1952 IOReturn irc = kIOReturnSuccess;
1953 if (!pUrb->EndPt)
1954 irc = (*pDevOsX->ppDevI)->USBDeviceAbortPipeZero(pDevOsX->ppDevI);
1955 else
1956 {
1957 uint8_t u8PipeRef;
1958 const uint8_t EndPt = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
1959 PUSBPROXYIFOSX pIf = usbProxyDarwinGetInterfaceForEndpoint(pDevOsX, EndPt, &u8PipeRef, NULL);
1960 if (pIf)
1961 irc = (*pIf->ppIfI)->AbortPipe(pIf->ppIfI, u8PipeRef);
1962 else /* this may happen if a device reset, set configuration or set interface has been performed. */
1963 Log(("usbProxyDarwinUrbCancel: pProxyDev=%s pUrb=%p EndPt=%d - cannot find the interface / pipe!\n",
1964 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt));
1965 }
1966
1967 int rc = VINF_SUCCESS;
1968 if (irc != kIOReturnSuccess)
1969 {
1970 Log(("usbProxyDarwinUrbCancel: pProxyDev=%s pUrb=%p EndPt=%d -> %#x!\n",
1971 pProxyDev->pUsbIns->pszName, pUrb, pUrb->EndPt, irc));
1972 rc = RTErrConvertFromDarwin(irc);
1973 }
1974
1975 return rc;
1976}
1977
1978
1979static DECLCALLBACK(int) usbProxyDarwinWakeup(PUSBPROXYDEV pProxyDev)
1980{
1981 PUSBPROXYDEVOSX pDevOsX = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVOSX);
1982
1983 LogFlow(("usbProxyDarwinWakeup: pProxyDev=%p\n", pProxyDev));
1984
1985 ASMAtomicXchgBool(&pDevOsX->fReapingThreadWake, true);
1986 usbProxyDarwinReaperKick(pDevOsX);
1987 return VINF_SUCCESS;
1988}
1989
1990
1991/**
1992 * The Darwin USB Proxy Backend.
1993 */
1994extern const USBPROXYBACK g_USBProxyDeviceHost =
1995{
1996 /* pszName */
1997 "host",
1998 /* cbBackend */
1999 sizeof(USBPROXYDEVOSX),
2000 usbProxyDarwinOpen,
2001 NULL,
2002 usbProxyDarwinClose,
2003 usbProxyDarwinReset,
2004 usbProxyDarwinSetConfig,
2005 usbProxyDarwinClaimInterface,
2006 usbProxyDarwinReleaseInterface,
2007 usbProxyDarwinSetInterface,
2008 usbProxyDarwinClearHaltedEp,
2009 usbProxyDarwinUrbQueue,
2010 usbProxyDarwinUrbCancel,
2011 usbProxyDarwinUrbReap,
2012 usbProxyDarwinWakeup,
2013 0
2014};
2015
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