VirtualBox

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

Last change on this file since 57444 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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