IOFireWireIPLibUnit.cpp [plain text]
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "IOFireWireIPLib.h"
#include "IOFireWireIPUserClientCommon.h"
#include "IOFireWireIPLibUnit.h"
#include <CoreFoundation/CFMachPort.h>
#include <IOKit/IOMessage.h>
#include <syslog.h> // Debug messages
#include <pthread.h> // for mutexes
#if 0
#define FWLOG(x) printf x
#else
#define FWLOG(x) do {} while (0)
#endif
__BEGIN_DECLS
void *IOFireWireIPLibUnitFactory( CFAllocatorRef allocator, CFUUIDRef typeID );
__END_DECLS
struct _IPUnit;
typedef struct _InterfaceMap
{
IUnknownVTbl *pseudoVTable;
struct _IPUnit *obj;
} InterfaceMap;
typedef struct _IPUnit
{
InterfaceMap fIOCFPlugInInterface;
InterfaceMap fIOFireWireIPLibUnitInterface;
CFUUIDRef fFactoryId;
UInt32 fRefCount;
io_service_t fService;
io_connect_t fConnection;
CFRunLoopRef fCFRunLoop;
CFRunLoopSourceRef fCFRunLoopSource;
IONotificationPortRef fNotifyPort;
io_object_t fNotification;
IOFWIPMessageCallback fMessageCallbackRoutine;
void * fMessageCallbackRefCon;
CFMutableArrayRef fACObjectArray;
pthread_mutex_t fACObjectArrayLock;
Boolean fSuspended;
} IPUnit;
#define IPUnit_getThis( self ) \
(((InterfaceMap *) self)->obj)
static IOReturn stop( void * self );
static UInt32 addRef( void * self )
{
IPUnit *me = IPUnit_getThis(self);
me->fRefCount++;
return me->fRefCount;
}
static UInt32 release( void * self )
{
IPUnit *me = IPUnit_getThis(self);
UInt32 retVal = me->fRefCount;
if( 1 == me->fRefCount-- )
{
pthread_mutex_lock( &me->fACObjectArrayLock );
if( me->fACObjectArray )
{
CFRelease( me->fACObjectArray ); me->fACObjectArray = NULL;
}
pthread_mutex_unlock( &me->fACObjectArrayLock );
pthread_mutex_destroy( &me->fACObjectArrayLock );
stop(self);
CFPlugInRemoveInstanceForFactory( me->fFactoryId );
CFRelease( me->fFactoryId );
free(me);
}
else if( me->fRefCount < 0 )
{
me->fRefCount = 0;
}
return retVal;
}
static HRESULT queryInterface( void * self, REFIID iid, void **ppv )
{
CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
HRESULT result = S_OK;
IPUnit *me = IPUnit_getThis(self);
if( CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOCFPlugInInterfaceID) )
{
*ppv = &me->fIOCFPlugInInterface;
addRef(self);
}
else if( CFEqual(uuid, kIOFireWireIPLibUnitInterfaceID) )
{
*ppv = &me->fIOFireWireIPLibUnitInterface;
addRef(self);
}
else
*ppv = 0;
if( !*ppv )
result = E_NOINTERFACE;
CFRelease( uuid );
return result;
}
Boolean isDeviceSuspended( void * self )
{
IPUnit * me = IPUnit_getThis(self);
return me->fSuspended;
}
static IOReturn probe( void * self, CFDictionaryRef propertyTable,
io_service_t service, SInt32 *order )
{
fprintf(stderr, "+ IOFireWireLibUnit probe\n") ;
if( !service || !IOObjectConformsTo(service, "IOFireWireIP") )
return kIOReturnBadArgument;
return kIOReturnSuccess;
}
static IOReturn start( void * self, CFDictionaryRef propertyTable,
io_service_t service )
{
IOReturn status = kIOReturnSuccess;
IPUnit *me = IPUnit_getThis(self);
me->fService = service;
status = IOServiceOpen( me->fService, mach_task_self(),
kIOFireWireIPLibConnection, &me->fConnection );
fprintf(stderr, "+ IOFireWireLibUnit start %x \n", status) ;
if( !me->fConnection )
status = kIOReturnNoDevice;
return status;
}
static IOReturn stop( void * self )
{
IPUnit *me = IPUnit_getThis(self);
if( me->fConnection )
{
IOServiceClose( me->fConnection );
me->fConnection = MACH_PORT_NULL;
}
return kIOReturnSuccess;
}
static IOReturn open( void * self )
{
IPUnit *me = IPUnit_getThis(self);
IOReturn status = kIOReturnSuccess;
if( !me->fConnection )
return kIOReturnNoDevice;
status = IOConnectMethodScalarIScalarO( me->fConnection, kIOFWIPUserClientOpen, 0, 0);
return status;
}
static IOReturn openWithSessionRef( void * self, IOFireWireSessionRef sessionRef )
{
IPUnit *me = IPUnit_getThis(self);
IOReturn status = kIOReturnSuccess;
if( !me->fConnection )
return kIOReturnNoDevice;
status = IOConnectMethodScalarIScalarO( me->fConnection, kIOFWIPUserClientOpenWithSessionRef,
1, 0, sessionRef);
return status;
}
static IOFireWireSessionRef getSessionRef(void * self)
{
IPUnit *me = IPUnit_getThis(self);
IOReturn status = kIOReturnSuccess;
IOFireWireSessionRef sessionRef = 0;
if( !me->fConnection )
return sessionRef;
status = IOConnectMethodScalarIScalarO( me->fConnection, kIOFWIPUserClientGetSessionRef,
0, 1, (int*)&sessionRef);
if( status != kIOReturnSuccess )
sessionRef = 0;
return sessionRef;
}
static void close( void * self )
{
IPUnit *me = IPUnit_getThis(self);
if( !me->fConnection )
return;
IOConnectMethodScalarIScalarO( me->fConnection, kIOFWIPUserClientClose, 0, 0);
}
static void setMessageCallback( void * self, void * refCon,
IOFWIPMessageCallback callback )
{
IPUnit *me = IPUnit_getThis(self);
me->fMessageCallbackRoutine = callback;
me->fMessageCallbackRefCon = refCon;
}
static IOReturn showLcb(void *self, const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 *responseLen)
{
IPUnit *me = IPUnit_getThis(self);
IOReturn status;
IOByteCount outputCnt = *responseLen;
if( !me->fConnection )
return kIOReturnNotOpen;
status = IOConnectMethodStructureIStructureO(
me->fConnection, kIOFWIPUserClientShowLcb,
cmdLen, &outputCnt, (UInt8 *)command, response);
if(status == kIOReturnSuccess)
*responseLen = outputCnt;
return status;
}
static IOReturn IPCommand(void *self, const UInt8 * command, UInt32 cmdLen, UInt8 * response, UInt32 *responseLen)
{
IPUnit *me = IPUnit_getThis(self);
IOReturn status;
IOByteCount outputCnt = *responseLen;
if( !me->fConnection )
return kIOReturnNotOpen;
status = IOConnectMethodStructureIStructureO(
me->fConnection, kIOFWIPUserClientIPCommand,
cmdLen, &outputCnt, (UInt8 *)command, response);
if(status == kIOReturnSuccess)
*responseLen = outputCnt;
return status;
}
static IOCFPlugInInterface sIOCFPlugInInterface =
{
0,
&queryInterface,
&addRef,
&release,
1, 0, &probe,
&start,
&stop
};
static IOFireWireIPLibUnitInterface sUnitInterface =
{
0,
&queryInterface,
&addRef,
&release,
2, 0, &open,
&openWithSessionRef,
&getSessionRef,
&close,
&setMessageCallback,
&IPCommand,
&showLcb
};
static IOCFPlugInInterface ** alloc()
{
IPUnit * me;
IOCFPlugInInterface ** interface = NULL;
me = (IPUnit *)malloc(sizeof(IPUnit));
if( me )
{
memset(me, 0, sizeof(IPUnit));
me->fRefCount = 1;
me->fConnection = MACH_PORT_NULL;
me->fService = MACH_PORT_NULL;
me->fIOCFPlugInInterface.pseudoVTable = (IUnknownVTbl *) &sIOCFPlugInInterface;
me->fIOCFPlugInInterface.obj = me;
me->fIOFireWireIPLibUnitInterface.pseudoVTable
= (IUnknownVTbl *) &sUnitInterface;
me->fIOFireWireIPLibUnitInterface.obj = me;
me->fSuspended = false;
pthread_mutex_init( &me->fACObjectArrayLock, NULL );
me->fACObjectArray = NULL;
me->fFactoryId = kIOFireWireIPLibUnitFactoryID;
CFRetain( me->fFactoryId );
CFPlugInAddInstanceForFactory( me->fFactoryId );
interface = (IOCFPlugInInterface **) &me->fIOCFPlugInInterface.pseudoVTable;
}
return interface;
}
void *IOFireWireIPLibUnitFactory( CFAllocatorRef allocator, CFUUIDRef typeID )
{
if( CFEqual(typeID, kIOFireWireIPLibUnitTypeID) )
return (void *) alloc();
else
return NULL;
}