VirtualBox

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

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

USB/Proxy: More code cleanup and finish a few todos, also some new ones so it doesn't get boring

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