VirtualBox

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

Last change on this file since 54266 was 52254, checked in by vboxsync, 10 years ago

Devices/USB: Several fixes and misc cleanups, the VM crash when detaching a USB device while transfering data should be fixed, likewise several assertions in debug builds should be fixed now. Removed a bit dead code in the linux backend (timeout handling which wasn't active)

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