VirtualBox

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

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

Fix darwin burn

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