IOUSBDeviceClass.cpp [plain text]
#define CFRUNLOOP_NEW_API 1
#include <CoreFoundation/CFMachPort.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CoreFoundation.h>
#include "IOUSBDeviceClass.h"
#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBUserClient.h>
#include <IOKit/usb/IOUSBLib.h>
#include <stdio.h>
__BEGIN_DECLS
#include <mach/mach.h>
#include <IOKit/iokitmig.h>
__END_DECLS
#ifndef IOUSBLIBDEBUG
#define IOUSBLIBDEBUG 0
#endif
#if IOUSBLIBDEBUG
#define DEBUGPRINT(x,...) printf(x, ##__VA_ARGS__)
#else
#define DEBUGPRINT(x,...)
#endif
#define connectCheck() do { \
if (!fConnection) \
{ \
DEBUGPRINT("+IOUSBDeviceClass[%p]::connectCheck failed\n", this); \
return kIOReturnNoDevice; \
} \
} while (0)
#define openCheck() do { \
if (!fIsOpen) \
{ \
DEBUGPRINT("+IOUSBDeviceClass[%p]::openCheck failed\n", this);\
return kIOReturnNotOpen; \
} \
} while (0)
#define allChecks() do { \
connectCheck(); \
openCheck(); \
} while (0)
IOCFPlugInInterface **
IOUSBDeviceClass::alloc()
{
IOUSBDeviceClass *me;
me = new IOUSBDeviceClass;
if (me)
return (IOCFPlugInInterface **) &me->iunknown.pseudoVTable;
else
return 0;
}
IOUSBDeviceClass::IOUSBDeviceClass()
: IOUSBIUnknown(&sIOCFPlugInInterfaceV1),
fService(MACH_PORT_NULL),
fConnection(MACH_PORT_NULL),
fAsyncPort(MACH_PORT_NULL),
fCFSource(0),
fIsOpen(false),
fConfigurations(NULL)
{
DEBUGPRINT("+IOUSBDeviceClass[%p]::IOUSBDeviceClass\n", this);
fUSBDevice.pseudoVTable = (IUnknownVTbl *) &sUSBDeviceInterfaceV197;
fUSBDevice.obj = this;
}
IOUSBDeviceClass::~IOUSBDeviceClass()
{
DEBUGPRINT("+IOUSBDeviceClass[%p]::~IOUSBDeviceClass\n", this);
if (fConfigurations)
{
int i;
for (i=0; i< fNumConfigurations; i++)
if (fConfigurations[i])
free(fConfigurations[i]);
free(fConfigurations);
fConfigurations = NULL;
}
if (fConnection)
{
IOServiceClose(fConnection);
fConnection = MACH_PORT_NULL;
}
if (fService)
{
IOObjectRelease(fService);
fService = MACH_PORT_NULL;
}
}
HRESULT
IOUSBDeviceClass::queryInterface(REFIID iid, void **ppv)
{
DEBUGPRINT("+IOUSBDeviceClass[%p]::queryInterface, fService= 0x%x\n", this, fService);
CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
HRESULT res = S_OK;
if (CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOCFPlugInInterfaceID))
{
DEBUGPRINT("IOUSBDeviceClass[%p]::queryInterface for IUnknownUUID or kIOCFPlugInInterfaceID\n", this);
*ppv = &iunknown;
addRef();
}
else if (CFEqual(uuid, kIOUSBDeviceInterfaceID) ||
CFEqual(uuid, kIOUSBDeviceInterfaceID182) ||
CFEqual(uuid, kIOUSBDeviceInterfaceID187) ||
CFEqual(uuid, kIOUSBDeviceInterfaceID197) ||
CFEqual(uuid, kIOUSBDeviceInterfaceID245) )
{
*ppv = &fUSBDevice;
addRef();
if ( (CFEqual(uuid, kIOUSBDeviceInterfaceID)
|| CFEqual(uuid, kIOUSBDeviceInterfaceID182)
|| CFEqual(uuid, kIOUSBDeviceInterfaceID187)
|| CFEqual(uuid, kIOUSBDeviceInterfaceID197)) )
{
if ( fService != IO_OBJECT_NULL )
{
DEBUGPRINT("IOUSBDeviceClass[%p]::queryInterface releasing retained fService. See rdar://3030440\n", this);
IOObjectRelease(fService);
}
}
}
else
*ppv = 0;
if (!*ppv)
res = E_NOINTERFACE;
CFRelease(uuid);
return res;
}
IOReturn
IOUSBDeviceClass::probe(CFDictionaryRef propertyTable, io_service_t inService, SInt32 *order)
{
DEBUGPRINT("+IOUSBDeviceClass[%p]::probe\n", this);
if (!inService || !IOObjectConformsTo(inService, "IOUSBDevice"))
{
DEBUGPRINT("+IOUSBDeviceClass[%p]::probe returning kIOReturnBadArgument\n", this);
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::start(CFDictionaryRef propertyTable, io_service_t inService)
{
IOReturn res;
CFMutableDictionaryRef entryProperties = 0;
kern_return_t kr;
res = IOServiceOpen(inService, mach_task_self(), 0, &fConnection);
if (res != kIOReturnSuccess)
{
DEBUGPRINT("IOUSBDeviceClass[%p]::start IOServiceOpen returned 0x%x\n", this, res);
return res;
}
connectCheck();
res = IOObjectRetain(inService);
if (res)
{
DEBUGPRINT("IOUSBDeviceClass[%p]::start IOObjectRetain returned 0x%x\n", this, res);
return res;
}
fService = inService;
kr = IORegistryEntryCreateCFProperties(fService, &entryProperties, NULL, 0);
if (entryProperties)
{
CFTypeRef val;
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDeviceClass));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fClass);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDeviceSubClass));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fSubClass);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDeviceProtocol));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fProtocol);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBVendorID));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberShortType, (void*)&fVendor);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBProductID));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberShortType, (void*)&fProduct);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDeviceReleaseNumber));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberShortType, (void*)&fDeviceReleaseNumber);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBManufacturerStringIndex));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fManufacturerStringIndex);
else
fManufacturerStringIndex = 0;
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBProductStringIndex));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fProductStringIndex);
else
fProductStringIndex = 0;
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBSerialNumberStringIndex));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fSerialNumberStringIndex);
else
fSerialNumberStringIndex = 0;
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDeviceNumConfigs));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fNumConfigurations);
else
fNumConfigurations = 0;
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDevicePropertySpeed));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberCharType, (void*)&fSpeed);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDevicePropertyBusPowerAvailable));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberLongType, (void*)&fPowerAvail);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDevicePropertyAddress));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberShortType, (void*)&fAddress);
val = CFDictionaryGetValue(entryProperties, CFSTR(kUSBDevicePropertyLocationID));
if (val)
CFNumberGetValue((CFNumberRef)val, kCFNumberLongType, (void*)&fLocationID);
fConfigDescCacheValid = false;
if (fNumConfigurations)
{
fConfigurations = (IOUSBConfigurationDescriptorPtr*) malloc(fNumConfigurations * sizeof(IOUSBConfigurationDescriptorPtr));
bzero(fConfigurations, fNumConfigurations * sizeof(IOUSBConfigurationDescriptorPtr));
kr = CacheConfigDescriptor();
}
CFRelease(entryProperties);
}
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::stop()
{
IOReturn ret = kIOReturnSuccess;
connectCheck();
if (fIsOpen)
ret = USBDeviceClose();
return ret;
}
IOReturn
IOUSBDeviceClass::CacheConfigDescriptor()
{
int i;
IOReturn kr = kIOReturnSuccess;
DEBUGPRINT("+IOUSBDeviceClass[%p]::CacheConfigDescriptor\n", this);
for (i = 0; i < fNumConfigurations; i++)
{
IOUSBConfigurationDescriptorPtr config;
IOUSBConfigurationDescHeader configHdr;
mach_msg_type_number_t size;
size = sizeof(configHdr);
DEBUGPRINT("+IOUSBDeviceClass[%p]::CacheConfigDescriptor asking for config = 0x%x\n", this, i);
kr = io_connect_method_scalarI_structureO(fConnection, kUSBDeviceUserClientGetConfigDescriptor, &i, 1, (char *)&configHdr, &size);
if (kr)
break;
size = USBToHostWord(configHdr.wTotalLength);
config = (IOUSBConfigurationDescriptorPtr)malloc(size+2);
kr = io_connect_method_scalarI_structureO(fConnection, kUSBDeviceUserClientGetConfigDescriptor, &i, 1, (char *)config, &size);
if (kr)
break;
*((char*)config + size) = 0;
*((char*)config + size + 1) = 0;
fConfigurations[i] = config;
}
if ( kr == kIOReturnSuccess )
fConfigDescCacheValid = TRUE;
DEBUGPRINT("-IOUSBDeviceClass[%p]::CacheConfigDescriptor returning 0x%x\n", this, kr);
return kr;
}
IOReturn
IOUSBDeviceClass::GetDeviceClass(UInt8 *devClass)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceClass\n");
*devClass = fClass;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceSubClass(UInt8 *devSubClass)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceSubClass\n");
*devSubClass = fSubClass;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceProtocol(UInt8 *devProtocol)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceProtocol\n");
*devProtocol = fProtocol;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceVendor(UInt16 *devVendor)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceVendor\n");
*devVendor = fVendor;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceProduct(UInt16 *devProduct)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceProduct\n");
*devProduct = fProduct;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceReleaseNumber(UInt16 *devRelNum)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceReleaseNumber\n");
*devRelNum = fDeviceReleaseNumber;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceAddress(USBDeviceAddress *addr)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceClass\n");
*addr = fAddress;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceBusPowerAvailable(UInt32 *powerAvail)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceClass\n");
*powerAvail = fPowerAvail;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetDeviceSpeed(UInt8 *devSpeed)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetDeviceSpeed\n");
*devSpeed = fSpeed;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetNumberOfConfigurations(UInt8 *numConfig)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetNumberOfConfigurations\n");
*numConfig = fNumConfigurations;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetLocationID(UInt32 *locationID)
{
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetLocationID\n");
*locationID = fLocationID;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetConfigurationDescriptorPtr(UInt8 index, IOUSBConfigurationDescriptorPtr *desc)
{
IOReturn kr = kIOReturnSuccess;
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::GetConfigurationDescriptorPtr\n");
if (index >= fNumConfigurations)
return kIOUSBConfigNotFound;
if ( !fConfigDescCacheValid )
{
printf("IOUSBDeviceClass::GetConfigurationDescriptorPtr cache was INVALID\n");
kr = CacheConfigDescriptor();
}
*desc = fConfigurations[index];
return kr;
}
IOReturn
IOUSBDeviceClass::SetConfiguration(UInt8 configNum)
{
mach_msg_type_number_t len = 0;
int t = configNum;
IOReturn ret;
allChecks();
DEBUGPRINT("IOUSBDeviceClass::SetConfiguration\n");
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientSetConfig, &t, 1, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::GetConfiguration(UInt8 *config)
{
mach_msg_type_number_t len = 1;
IOReturn ret;
int result;
connectCheck();
DEBUGPRINT("+IOUSBDeviceClass[%p]::GetConfiguration\n", this);
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientGetConfig, NULL, 0, &result, &len);
DEBUGPRINT("IOUSBDeviceClass::GetConfiguration ret: 0x%x, result = 0x%x", ret, result);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
if (ret == kIOReturnSuccess)
{
*config = *(UInt8*)&result;
}
DEBUGPRINT("-IOUSBDeviceClass::GetConfiguration returning 0x%x, config = 0x%x\n", ret, *config);
return ret;
}
IOReturn IOUSBDeviceClass::
CreateDeviceAsyncEventSource(CFRunLoopSourceRef *source)
{
IOReturn ret;
CFMachPortRef cfPort;
CFMachPortContext context;
Boolean shouldFreeInfo;
DEBUGPRINT("+IOUSBDeviceClass[%p]::CreateDeviceAsyncEventSource\n", this);
if (!fAsyncPort)
{
ret = CreateDeviceAsyncPort(0);
if (kIOReturnSuccess != ret)
return ret;
}
context.version = 1;
context.info = this;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
cfPort = CFMachPortCreateWithPort(NULL, fAsyncPort, (CFMachPortCallBack) IODispatchCalloutFromMessage, &context, &shouldFreeInfo);
if (!cfPort)
return kIOReturnNoMemory;
fCFSource = CFMachPortCreateRunLoopSource(NULL, cfPort, 0);
CFRelease(cfPort);
if (!fCFSource)
return kIOReturnNoMemory;
if (source)
*source = fCFSource;
DEBUGPRINT("-IOUSBDeviceClass::CreateDeviceAsyncEventSource\n");
return kIOReturnSuccess;
}
CFRunLoopSourceRef
IOUSBDeviceClass::GetDeviceAsyncEventSource()
{
return fCFSource;
}
IOReturn
IOUSBDeviceClass::CreateDeviceAsyncPort(mach_port_t *port)
{
IOReturn ret;
ret = IOCreateReceivePort(kOSAsyncCompleteMessageID, &fAsyncPort);
if (kIOReturnSuccess == ret)
{
if (port)
*port = fAsyncPort;
if (fIsOpen)
{
natural_t asyncRef[1];
mach_msg_type_number_t len = 0;
ret = io_async_method_scalarI_scalarO( fConnection, fAsyncPort, asyncRef, 1, kUSBDeviceUserClientSetAsyncPort, NULL, 0, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
}
}
return ret;
}
mach_port_t
IOUSBDeviceClass::GetDeviceAsyncPort()
{
return fAsyncPort;
}
IOReturn
IOUSBDeviceClass::USBDeviceOpen(bool seize)
{
IOReturn ret;
int t = seize;
DEBUGPRINT("+IOUSBDeviceClass[%p]::USBDeviceOpen\n", this);
connectCheck();
if (fIsOpen)
return kIOReturnSuccess;
mach_msg_type_number_t len = 0;
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientOpen, &t, 1, NULL, &len);
if (ret == kIOReturnSuccess)
{
fIsOpen = true;
if (fAsyncPort)
{
natural_t asyncRef[1];
mach_msg_type_number_t len = 0;
ret = io_async_method_scalarI_scalarO(fConnection, fAsyncPort, asyncRef, 1, kUSBDeviceUserClientSetAsyncPort, NULL, 0, NULL, &len);
if ((ret != kIOReturnSuccess) && (ret != MACH_SEND_INVALID_DEST))
USBDeviceClose();
}
}
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
DEBUGPRINT("+IOUSBDeviceClass[%p]::USBDeviceOpen returns 0x%x\n", this, ret);
return ret;
}
IOReturn
IOUSBDeviceClass::USBDeviceClose()
{
IOReturn ret;
allChecks();
mach_msg_type_number_t len = 0;
fIsOpen = false;
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientClose, NULL, 0, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::GetBusFrameNumber(UInt64 *frame, AbsoluteTime *atTime)
{
IOUSBGetFrameStruct stuff;
mach_msg_type_number_t outSize = sizeof(stuff);
IOReturn ret;
connectCheck();
ret = io_connect_method_scalarI_structureO(fConnection, kUSBDeviceUserClientGetFrameNumber, NULL, 0, (char *)&stuff, &outSize);
if(kIOReturnSuccess == ret)
{
{
*frame = stuff.frame;
*atTime = stuff.timeStamp;
}
DEBUGPRINT("IOUSBDeviceClass::GetBusFrameNumber frame: 0x%qx, time.hi: 0x%lx, time.lo: 0x%lx\n", *frame, (*atTime).hi, (*atTime).lo);
}
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::ResetDevice()
{
mach_msg_type_number_t len = 0;
IOReturn ret;
allChecks();
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientResetDevice, NULL, 0, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::USBDeviceReEnumerate(UInt32 options)
{
mach_msg_type_number_t len = 0;
int t = options;
IOReturn ret;
allChecks();
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientReEnumerateDevice, &t, 1, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::DeviceRequest(IOUSBDevRequestTO *req)
{
IOReturn ret = kIOReturnSuccess;
connectCheck();
DEBUGPRINT("IOUSBDeviceClass::DeviceRequest: \n\tbmRequestType = 0x%2.2x\n\tbRequest = 0x%2.2x\n\twValue = 0x%4.4x\n\twIndex = 0x%4.4x\n\twLength = 0x%4.4x\n\tpData = %p\n\tnoDataTimeout = %ld\n\tcompletionTimeout = %ld\n",
req->bmRequestType,
req->bRequest,
req->wValue,
req->wIndex,
req->wLength,
req->pData,
req->noDataTimeout,
req->completionTimeout);
if ( req->wLength <= sizeof(io_struct_inband_t))
{
int in[4];
in[0] = (req->bmRequestType << 8) | req->bRequest;
in[1] = (req->wValue << 16) | req->wIndex;
in[2] = req->noDataTimeout;
in[3] = req->completionTimeout;
DEBUGPRINT("IOUSBDeviceClass::DeviceRequest: in[0] = 0x%8.8x, in[1] = 0x%8.8x, in[2] = 0x%8.8x, in[3] = 0x%8.8x\n", in[0], in[1], in[2], in[3]);
switch ((req->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask)
{
case kUSBOut:
ret = io_connect_method_scalarI_structureI(fConnection, kUSBDeviceUserClientDeviceRequestOut, in, 4, (char *)req->pData, req->wLength);
if(kIOReturnSuccess == ret)
req->wLenDone = req->wLength;
else
req->wLenDone = 0;
break;
case kUSBIn:
mach_msg_type_number_t reqSize = req->wLength;
ret = io_connect_method_scalarI_structureO(fConnection, kUSBDeviceUserClientDeviceRequestIn, in, 4, (char *)req->pData, &reqSize);
if(kIOReturnSuccess == ret)
req->wLenDone = reqSize;
break;
}
}
else
{
mach_msg_type_number_t outSize = 0;
UInt16 length = req->wLength;
switch ((req->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask)
{
case kUSBOut:
ret = io_connect_method_structureI_structureO(fConnection, kUSBDeviceUserClientDeviceRequestOutOOL,
(char *)req, sizeof(IOUSBDevRequestTO), NULL, &outSize);
if(kIOReturnSuccess == ret)
req->wLenDone = length;
else
req->wLenDone = 0;
break;
case kUSBIn:
mach_msg_type_number_t reqSize = length; outSize = sizeof(reqSize);
DEBUGPRINT("IOUSBDeviceClass::DeviceRequest reqSize = 0x%x, outSize = 0x%x\n", reqSize, outSize);
ret = io_connect_method_structureI_structureO(fConnection, kUSBDeviceUserClientDeviceRequestInOOL,
(char *)req, sizeof(IOUSBDevRequestTO), (char *)&reqSize, &outSize);
if(kIOReturnSuccess == ret)
{
req->wLenDone = length;
}
break;
}
}
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::DeviceRequestAsync(IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon)
{
connectCheck();
mach_msg_type_number_t outSize = 0;
natural_t asyncRef[kIOAsyncCalloutCount];
int selector = 0;
IOReturn ret;
connectCheck();
if (!fAsyncPort)
{
DEBUGPRINT("IOUSBDeviceClass::DeviceRequestAsync NO async port\n");
return kIOUSBNoAsyncPortErr;
}
DEBUGPRINT("IOUSBDeviceClass::DeviceRequestAsync: \n\tbmRequestType = 0x%2.2x\n\tbRequest = 0x%2.2x\n\twValue = 0x%4.4x\n\twIndex = 0x%4.4x\n\twLength = 0x%4.4x\n\tpData = %p\n\tnoDataTimeout = %ld\n\tcompletionTimeout = %ld\n",
req->bmRequestType,
req->bRequest,
req->wValue,
req->wIndex,
req->wLength,
req->pData,
req->noDataTimeout,
req->completionTimeout);
asyncRef[kIOAsyncCalloutFuncIndex] = (natural_t) callback;
asyncRef[kIOAsyncCalloutRefconIndex] = (natural_t) refCon;
DEBUGPRINT("\tAsyncRef[0]: 0x%x, [1]: 0x%x, [2]: 0x%x, [3]: 0x%x, [4]: 0x%x, [5]:0x%x, [6]:0x%x, [7]:0x%x\n", asyncRef[0], asyncRef[1], asyncRef[2], asyncRef[3], asyncRef[4], asyncRef[5], asyncRef[6], asyncRef[7]);
switch ((req->bmRequestType >> kUSBRqDirnShift) & kUSBRqDirnMask)
{
case kUSBOut:
selector = kUSBDeviceUserClientDeviceAsyncRequestOut;
break;
case kUSBIn:
selector = kUSBDeviceUserClientDeviceAsyncRequestIn;
break;
}
ret = io_async_method_structureI_structureO(fConnection, fAsyncPort, asyncRef, kIOAsyncCalloutCount,
selector, (char*)req, sizeof(IOUSBDevRequestTO), NULL, &outSize);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
DEBUGPRINT("IOUSBDeviceClass::DeviceRequestAsync returning 0x%x\n",ret);
return ret;
}
IOReturn
IOUSBDeviceClass::CreateInterfaceIterator(IOUSBFindInterfaceRequest *intfReq, io_iterator_t *iter)
{
mach_msg_type_number_t outSize = sizeof(io_iterator_t);
IOReturn ret;
connectCheck();
DEBUGPRINT("+IOUSBDeviceClass[%p]::CreateInterfaceIterator bInterfaceClass 0x%x, bInterfaceSubClass = 0x%x, bInterfaceProtocol = 0x%x, bAlternateSetting = 0x%x\n", this,
intfReq->bInterfaceClass,
intfReq->bInterfaceSubClass,
intfReq->bInterfaceProtocol,
intfReq->bAlternateSetting);
ret = io_connect_method_structureI_structureO(fConnection, kUSBDeviceUserClientCreateInterfaceIterator,
(char *)intfReq, sizeof(IOUSBFindInterfaceRequest), (char*)iter, &outSize);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
DEBUGPRINT("-IOUSBDeviceClass::CreateInterfaceIterator reurning error 0x%x, iterator: 0x%x\n", ret, *iter);
return ret;
}
IOReturn
IOUSBDeviceClass::USBDeviceSuspend(bool suspend)
{
mach_msg_type_number_t len = 0;
int t = suspend;
IOReturn ret;
allChecks();
ret = io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientSuspend, &t, 1, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::USBDeviceAbortPipeZero(void)
{
mach_msg_type_number_t len = 0;
IOReturn ret;
allChecks();
return io_connect_method_scalarI_scalarO(fConnection, kUSBDeviceUserClientAbortPipeZero, NULL, 0, NULL, &len);
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::USBDeviceGetManufacturerStringIndex(UInt8 *msi)
{
connectCheck();
*msi = fManufacturerStringIndex;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::USBDeviceGetProductStringIndex(UInt8 *psi)
{
connectCheck();
*psi = fProductStringIndex;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::USBDeviceGetSerialNumberStringIndex(UInt8 *snsi)
{
connectCheck();
*snsi = fSerialNumberStringIndex;
return kIOReturnSuccess;
}
IOReturn
IOUSBDeviceClass::GetBusMicroFrameNumber(UInt64 *microFrame, AbsoluteTime *atTime)
{
IOUSBGetFrameStruct stuff;
mach_msg_type_number_t outSize = sizeof(stuff);
IOReturn ret;
connectCheck();
ret = io_connect_method_scalarI_structureO(fConnection, kUSBDeviceUserClientGetMicroFrameNumber, NULL, 0, (char *)&stuff, &outSize);
if(kIOReturnSuccess == ret)
{
{
*microFrame = stuff.frame;
*atTime = stuff.timeStamp;
}
DEBUGPRINT("IOUSBDeviceClass::GetBusMicroFrameNumber frame: 0x%qx, time.hi: 0x%lx, time.lo: 0x%lx\n", *microFrame, (*atTime).hi, (*atTime).lo);
}
if (ret == MACH_SEND_INVALID_DEST)
{
fIsOpen = false;
fConnection = MACH_PORT_NULL;
ret = kIOReturnNoDevice;
}
return ret;
}
IOReturn
IOUSBDeviceClass::GetIOUSBLibVersion(NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion)
{
CFURLRef bundleURL;
CFBundleRef myBundle;
UInt32 usbFamilyBundleVersion;
UInt32 usbLibBundleVersion;
UInt32 * tmp;
connectCheck();
bundleURL = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
CFSTR("/System/Library/Extensions/IOUSBFamily.kext"),
kCFURLPOSIXPathStyle,
true );
myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
usbFamilyBundleVersion = CFBundleGetVersionNumber( myBundle );
CFRelease( bundleURL );
CFRelease( myBundle );
bundleURL = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
CFSTR("/System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"),
kCFURLPOSIXPathStyle,
true );
myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
usbLibBundleVersion = CFBundleGetVersionNumber( myBundle );
CFRelease( bundleURL );
CFRelease( myBundle );
if ( ioUSBLibVersion )
{
tmp = (UInt32 *) ioUSBLibVersion;
*tmp = usbLibBundleVersion;
}
if ( usbFamilyVersion )
{
tmp = (UInt32 *) usbFamilyVersion;
*tmp = usbFamilyBundleVersion;
}
return kIOReturnSuccess;
}
IOCFPlugInInterface
IOUSBDeviceClass::sIOCFPlugInInterfaceV1 = {
0,
&IOUSBIUnknown::genericQueryInterface,
&IOUSBIUnknown::genericAddRef,
&IOUSBIUnknown::genericRelease,
1, 0, &IOUSBDeviceClass::deviceProbe,
&IOUSBDeviceClass::deviceStart,
&IOUSBDeviceClass::deviceStop
};
IOUSBDeviceStruct197
IOUSBDeviceClass::sUSBDeviceInterfaceV197 = {
0,
&IOUSBIUnknown::genericQueryInterface,
&IOUSBIUnknown::genericAddRef,
&IOUSBIUnknown::genericRelease,
&IOUSBDeviceClass::deviceCreateDeviceAsyncEventSource,
&IOUSBDeviceClass::deviceGetDeviceAsyncEventSource,
&IOUSBDeviceClass::deviceCreateDeviceAsyncPort,
&IOUSBDeviceClass::deviceGetDeviceAsyncPort,
&IOUSBDeviceClass::deviceUSBDeviceOpen,
&IOUSBDeviceClass::deviceUSBDeviceClose,
&IOUSBDeviceClass::deviceGetDeviceClass,
&IOUSBDeviceClass::deviceGetDeviceSubClass,
&IOUSBDeviceClass::deviceGetDeviceProtocol,
&IOUSBDeviceClass::deviceGetDeviceVendor,
&IOUSBDeviceClass::deviceGetDeviceProduct,
&IOUSBDeviceClass::deviceGetDeviceReleaseNumber,
&IOUSBDeviceClass::deviceGetDeviceAddress,
&IOUSBDeviceClass::deviceGetDeviceBusPowerAvailable,
&IOUSBDeviceClass::deviceGetDeviceSpeed,
&IOUSBDeviceClass::deviceGetNumberOfConfigurations,
&IOUSBDeviceClass::deviceGetLocationID,
&IOUSBDeviceClass::deviceGetConfigurationDescriptorPtr,
&IOUSBDeviceClass::deviceGetConfiguration,
&IOUSBDeviceClass::deviceSetConfiguration,
&IOUSBDeviceClass::deviceGetBusFrameNumber,
&IOUSBDeviceClass::deviceResetDevice,
&IOUSBDeviceClass::deviceDeviceRequest,
&IOUSBDeviceClass::deviceDeviceRequestAsync,
&IOUSBDeviceClass::deviceCreateInterfaceIterator,
&IOUSBDeviceClass::deviceUSBDeviceOpenSeize,
&IOUSBDeviceClass::deviceDeviceRequestTO,
&IOUSBDeviceClass::deviceDeviceRequestAsyncTO,
&IOUSBDeviceClass::deviceUSBDeviceSuspend,
&IOUSBDeviceClass::deviceUSBDeviceAbortPipeZero,
&IOUSBDeviceClass::deviceGetManufacturerStringIndex,
&IOUSBDeviceClass::deviceGetProductStringIndex,
&IOUSBDeviceClass::deviceGetSerialNumberStringIndex,
&IOUSBDeviceClass::deviceReEnumerateDevice,
&IOUSBDeviceClass::deviceGetBusMicroFrameNumber,
&IOUSBDeviceClass::deviceGetIOUSBLibVersion
};
IOReturn
IOUSBDeviceClass:: deviceProbe(void *self, CFDictionaryRef propertyTable, io_service_t inService, SInt32 *order)
{ return getThis(self)->probe(propertyTable, inService, order); }
IOReturn
IOUSBDeviceClass::deviceStart(void *self, CFDictionaryRef propertyTable, io_service_t inService)
{ return getThis(self)->start(propertyTable, inService); }
IOReturn
IOUSBDeviceClass::deviceStop(void *self)
{ return getThis(self)->stop(); }
IOReturn
IOUSBDeviceClass::deviceCreateDeviceAsyncEventSource(void *self, CFRunLoopSourceRef *source)
{ return getThis(self)->CreateDeviceAsyncEventSource(source); }
CFRunLoopSourceRef
IOUSBDeviceClass::deviceGetDeviceAsyncEventSource(void *self)
{ return getThis(self)->GetDeviceAsyncEventSource(); }
IOReturn
IOUSBDeviceClass::deviceCreateDeviceAsyncPort(void *self, mach_port_t *port)
{ return getThis(self)->CreateDeviceAsyncPort(port); }
mach_port_t
IOUSBDeviceClass::deviceGetDeviceAsyncPort(void *self)
{ return getThis(self)->GetDeviceAsyncPort(); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceClass(void *self, UInt8 *devClass)
{ return getThis(self)->GetDeviceClass(devClass); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceSubClass(void *self, UInt8 *devSubClass)
{ return getThis(self)->GetDeviceSubClass(devSubClass); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceProtocol(void *self, UInt8 *devProtocol)
{ return getThis(self)->GetDeviceProtocol(devProtocol); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceVendor(void *self, UInt16 *devVendor)
{ return getThis(self)->GetDeviceVendor(devVendor); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceProduct(void *self, UInt16 *devProduct)
{ return getThis(self)->GetDeviceProduct(devProduct); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceReleaseNumber(void *self, UInt16 *devRelNum)
{ return getThis(self)->GetDeviceReleaseNumber(devRelNum); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceAddress(void *self, USBDeviceAddress *addr)
{ return getThis(self)->GetDeviceAddress(addr); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceBusPowerAvailable(void *self, UInt32 *powerAvail)
{ return getThis(self)->GetDeviceBusPowerAvailable(powerAvail); }
IOReturn
IOUSBDeviceClass::deviceGetDeviceSpeed(void *self, UInt8 *devSpeed)
{ return getThis(self)->GetDeviceSpeed(devSpeed); }
IOReturn
IOUSBDeviceClass::deviceGetNumberOfConfigurations(void *self, UInt8 *numConfig)
{ return getThis(self)->GetNumberOfConfigurations(numConfig); }
IOReturn
IOUSBDeviceClass::deviceGetLocationID(void *self, UInt32 *locationID)
{ return getThis(self)->GetLocationID(locationID); }
IOReturn
IOUSBDeviceClass::deviceGetConfigurationDescriptorPtr(void *self, UInt8 index, IOUSBConfigurationDescriptorPtr *desc)
{ return getThis(self)->GetConfigurationDescriptorPtr(index, desc); }
IOReturn
IOUSBDeviceClass::deviceGetConfiguration(void *self, UInt8 *configNum)
{ return getThis(self)->GetConfiguration(configNum); }
IOReturn
IOUSBDeviceClass::deviceSetConfiguration(void *self, UInt8 configNum)
{ return getThis(self)->SetConfiguration(configNum); }
IOReturn
IOUSBDeviceClass::deviceUSBDeviceOpen(void *self)
{ return getThis(self)->USBDeviceOpen(false); }
IOReturn
IOUSBDeviceClass::deviceUSBDeviceClose(void *self)
{ return getThis(self)->USBDeviceClose(); }
IOReturn
IOUSBDeviceClass::deviceGetBusFrameNumber(void *self, UInt64 *frame, AbsoluteTime *atTime)
{ return getThis(self)->GetBusFrameNumber(frame, atTime); }
IOReturn
IOUSBDeviceClass::deviceResetDevice(void *self)
{ return getThis(self)->ResetDevice(); }
IOReturn
IOUSBDeviceClass::deviceDeviceRequest(void *self, IOUSBDevRequest *reqIn)
{
IOUSBDevRequestTO req;
IOReturn err;
req.bmRequestType = reqIn->bmRequestType;
req.bRequest = reqIn->bRequest;
req.wValue = reqIn->wValue;
req.wIndex = reqIn->wIndex;
req.wLength = reqIn->wLength;
req.pData = reqIn->pData;
req.wLenDone = reqIn->wLenDone;
req.completionTimeout = kUSBDefaultControlCompletionTimeoutMS;
req.noDataTimeout = kUSBDefaultControlNoDataTimeoutMS;
err = getThis(self)->DeviceRequest(&req);
reqIn->wLenDone = req.wLenDone;
return err;
}
IOReturn
IOUSBDeviceClass::deviceDeviceRequestAsync(void *self, IOUSBDevRequest *reqIn, IOAsyncCallback1 callback, void *refCon)
{
IOUSBDevRequestTO req;
req.bmRequestType = reqIn->bmRequestType;
req.bRequest = reqIn->bRequest;
req.wValue = reqIn->wValue;
req.wIndex = reqIn->wIndex;
req.wLength = reqIn->wLength;
req.pData = reqIn->pData;
req.wLenDone = reqIn->wLenDone;
req.completionTimeout = kUSBDefaultControlCompletionTimeoutMS;
req.noDataTimeout = kUSBDefaultControlNoDataTimeoutMS;
return getThis(self)->DeviceRequestAsync(&req, callback, refCon);
}
IOReturn
IOUSBDeviceClass::deviceCreateInterfaceIterator(void *self, IOUSBFindInterfaceRequest *intfReq, io_iterator_t *iter)
{ return getThis(self)->CreateInterfaceIterator(intfReq, iter); }
IOReturn
IOUSBDeviceClass::deviceUSBDeviceOpenSeize(void *self)
{ return getThis(self)->USBDeviceOpen(true); }
IOReturn
IOUSBDeviceClass::deviceDeviceRequestTO(void *self, IOUSBDevRequestTO *req)
{ return getThis(self)->DeviceRequest(req); }
IOReturn
IOUSBDeviceClass::deviceDeviceRequestAsyncTO(void *self, IOUSBDevRequestTO *req, IOAsyncCallback1 callback, void *refCon)
{ return getThis(self)->DeviceRequestAsync(req, callback, refCon); }
IOReturn
IOUSBDeviceClass::deviceUSBDeviceSuspend(void *self, Boolean suspend)
{ return getThis(self)->USBDeviceSuspend(suspend); }
IOReturn
IOUSBDeviceClass::deviceUSBDeviceAbortPipeZero(void *self)
{ return getThis(self)->USBDeviceAbortPipeZero(); }
IOReturn
IOUSBDeviceClass::deviceGetManufacturerStringIndex(void *self, UInt8 *msi)
{ return getThis(self)->USBDeviceGetManufacturerStringIndex(msi); }
IOReturn
IOUSBDeviceClass::deviceGetProductStringIndex(void *self, UInt8 *psi)
{ return getThis(self)->USBDeviceGetProductStringIndex(psi); }
IOReturn
IOUSBDeviceClass::deviceGetSerialNumberStringIndex(void *self, UInt8 *snsi)
{ return getThis(self)->USBDeviceGetSerialNumberStringIndex(snsi); }
IOReturn
IOUSBDeviceClass::deviceReEnumerateDevice(void *self, UInt32 options)
{ return getThis(self)->USBDeviceReEnumerate(options); }
IOReturn
IOUSBDeviceClass::deviceGetBusMicroFrameNumber(void *self, UInt64 *microFrame, AbsoluteTime *atTime)
{ return getThis(self)->GetBusMicroFrameNumber(microFrame, atTime); }
IOReturn
IOUSBDeviceClass::deviceGetIOUSBLibVersion( void *self, NumVersion *ioUSBLibVersion, NumVersion *usbFamilyVersion)
{ return getThis(self)->GetIOUSBLibVersion(ioUSBLibVersion, usbFamilyVersion); }