VirtualBox

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

Last change on this file since 45671 was 45626, checked in by vboxsync, 12 years ago

USB/Darwin: checks whether event's sources presents in the run loop of the current thread and adds them if they missed.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette