VirtualBox

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

Last change on this file since 58268 was 58165, checked in by vboxsync, 9 years ago

USB/Darwin: Attempt to fix high-speed isochronous transfers.

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