VirtualBox

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

Last change on this file since 45761 was 45756, checked in by vboxsync, 12 years ago

VBox/USB:proxy:darwin: detaching bits for vSMP case.

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