SCSITaskDeviceClass.cpp [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/scsi-commands/SCSICmds_INQUIRY_Definitions.h>
#include "SCSITaskDeviceClass.h"
#include "SCSITaskClass.h"
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <mach/mach_interface.h>
#include <IOKit/iokitmig.h>
#ifdef __cplusplus
}
#endif
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "SCSITaskDeviceClass"
#if DEBUG
#define PRINT(x) printf x
#else
#define PRINT(x)
#endif
#include "IOSCSIArchitectureModelFamilyDebugging.h"
IOCFPlugInInterface
SCSITaskDeviceClass::sIOCFPlugInInterface =
{
0,
&SCSITaskIUnknown::sQueryInterface,
&SCSITaskIUnknown::sAddRef,
&SCSITaskIUnknown::sRelease,
1, 0, &SCSITaskDeviceClass::sProbe,
&SCSITaskDeviceClass::sStart,
&SCSITaskDeviceClass::sStop
};
SCSITaskDeviceInterface
SCSITaskDeviceClass::sSCSITaskDeviceInterface =
{
0,
&SCSITaskDeviceClass::sQueryInterface,
&SCSITaskDeviceClass::sAddRef,
&SCSITaskDeviceClass::sRelease,
1, 0, &SCSITaskDeviceClass::sIsExclusiveAccessAvailable,
&SCSITaskDeviceClass::sAddCallbackDispatcherToRunLoop,
&SCSITaskDeviceClass::sRemoveCallbackDispatcherFromRunLoop,
&SCSITaskDeviceClass::sObtainExclusiveAccess,
&SCSITaskDeviceClass::sReleaseExclusiveAccess,
&SCSITaskDeviceClass::sCreateSCSITask,
};
#if 0
#pragma mark -
#pragma mark Public Methods
#pragma mark -
#endif
IOCFPlugInInterface **
SCSITaskDeviceClass::alloc ( void )
{
SCSITaskDeviceClass * userClient = NULL;
IOCFPlugInInterface ** interface = NULL;
IOReturn status = kIOReturnSuccess;
PRINT ( ( "SCSITaskDeviceClass::alloc called\n" ) );
userClient = new SCSITaskDeviceClass;
require_nonzero ( userClient, Error_Exit );
status = userClient->Init ( );
require_success_action_string ( status, Error_Exit, delete userClient, "Init failed" );
userClient->AddRef ( );
interface = ( IOCFPlugInInterface ** ) &userClient->fInterfaceMap.pseudoVTable;
Error_Exit:
return interface;
}
SCSITaskDeviceInterface **
SCSITaskDeviceClass::alloc ( io_service_t service, io_connect_t connection )
{
SCSITaskDeviceClass * userClient = NULL;
SCSITaskDeviceInterface ** interface = NULL;
IOReturn status = kIOReturnSuccess;
PRINT ( ( "SCSITaskDeviceClass::alloc called\n" ) );
userClient = new SCSITaskDeviceClass;
require_nonzero ( userClient, Error_Exit );
status = userClient->InitWithConnection ( service, connection );
require_success_action_string ( status, Error_Exit, delete userClient, "InitWithConnection failed" );
userClient->AddRef ( );
interface = ( SCSITaskDeviceInterface ** ) &userClient->fSCSITaskDeviceInterfaceMap.pseudoVTable;
Error_Exit:
return interface;
}
IOReturn
SCSITaskDeviceClass::Init ( void )
{
IOReturn status = kIOReturnNoResources;
PRINT ( ( "SCSITaskDeviceClass::Init called\n" ) );
fTaskSet = CFSetCreateMutable ( kCFAllocatorDefault, 0, NULL );
require_nonzero ( fTaskSet, Error_Exit );
status = kIOReturnSuccess;
Error_Exit:
return status;
}
IOReturn
SCSITaskDeviceClass::InitWithConnection ( io_service_t service,
io_connect_t connection )
{
IOReturn status = kIOReturnBadArgument;
PRINT ( ( "SCSITaskDeviceClass::InitWithConnection called\n" ) );
require_nonzero ( service, Error_Exit );
require_nonzero ( connection, Error_Exit );
status = Init ( );
require_success ( status, Error_Exit );
fService = service;
fConnection = connection;
fIsServicesLayerInterface = true;
status = kIOReturnSuccess;
Error_Exit:
return status;
}
#if 0
#pragma mark -
#pragma mark Protected Methods
#pragma mark -
#endif
SCSITaskDeviceClass::SCSITaskDeviceClass ( void ) :
SCSITaskIUnknown ( &sIOCFPlugInInterface )
{
PRINT ( ( "SCSITaskDeviceClass constructor called\n" ) );
fAsyncPort = MACH_PORT_NULL;
fCFRunLoop = 0;
fCFRunLoopSource = 0;
fTaskSet = 0;
fConnection = MACH_PORT_NULL;
fService = MACH_PORT_NULL;
fHasExclusiveAccess = false;
fIsServicesLayerInterface = false;
fSCSITaskDeviceInterfaceMap.pseudoVTable = ( IUnknownVTbl * ) &sSCSITaskDeviceInterface;
fSCSITaskDeviceInterfaceMap.obj = this;
}
SCSITaskDeviceClass::~SCSITaskDeviceClass ( void )
{
PRINT ( ( "SCSITaskDeviceClass : Destructor called\n" ) );
if ( fAsyncPort != MACH_PORT_NULL )
{
PRINT ( ( "SCSITaskDeviceClass : fAsyncPort != MACH_PORT_NULL\n" ) );
IOObjectRelease ( fAsyncPort );
fAsyncPort = MACH_PORT_NULL;
}
if ( fTaskSet != 0 )
{
PRINT ( ( "SCSITaskDeviceClass : fTaskSet != 0\n" ) );
CFRelease ( fTaskSet );
}
}
#if 0
#pragma mark -
#endif
HRESULT
SCSITaskDeviceClass::QueryInterface ( REFIID iid, void ** ppv )
{
CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes ( NULL, iid );
HRESULT result = S_OK;
PRINT ( ( "SCSITaskDeviceClass : QueryInterface called\n" ) );
if ( CFEqual ( uuid, IUnknownUUID ) ||
CFEqual ( uuid, kIOCFPlugInInterfaceID ) )
{
*ppv = &fInterfaceMap;
AddRef ( );
}
else if ( CFEqual ( uuid, kIOSCSITaskDeviceInterfaceID ) )
{
PRINT ( ( "kSCSITaskDeviceUserClientInterfaceID requested\n" ) );
*ppv = &fSCSITaskDeviceInterfaceMap;
AddRef ( );
}
else
{
*ppv = 0;
result = E_NOINTERFACE;
}
CFRelease ( uuid );
return result;
}
IOReturn
SCSITaskDeviceClass::Probe ( CFDictionaryRef propertyTable,
io_service_t inService,
SInt32 * order )
{
CFMutableDictionaryRef dict = 0;
IOReturn status = kIOReturnBadArgument;
Boolean ok = false;
PRINT ( ( "SCSITaskDeviceClass::Probe called\n" ) );
require_nonzero ( inService, Error_Exit );
status = IORegistryEntryCreateCFProperties ( inService, &dict, NULL, 0 );
require_success ( status, Error_Exit );
ok = CFDictionaryContainsKey ( dict, CFSTR ( "IOCFPlugInTypes" ) );
require_action ( ok, ReleaseDictionary, status = kIOReturnNoDevice );
status = kIOReturnSuccess;
ReleaseDictionary:
require_nonzero ( dict, Error_Exit );
CFRelease ( dict );
Error_Exit:
return status;
}
IOReturn
SCSITaskDeviceClass::Start ( CFDictionaryRef propertyTable,
io_service_t service )
{
IOReturn status = kIOReturnNoDevice;
PRINT ( ( "SCSITaskDeviceClass : Start\n" ) );
fService = service;
status = IOServiceOpen ( fService,
mach_task_self ( ),
kSCSITaskLibConnection,
&fConnection );
require_success ( status, Error_Exit );
require_nonzero_action ( fConnection, Error_Exit, status = kIOReturnNoDevice );
fHasExclusiveAccess = true;
PRINT ( ( "SCSITaskDeviceClass : IOServiceOpen status = 0x%08lx, connection = %d\n",
( UInt32 ) status, fConnection ) );
Error_Exit:
return status;
}
IOReturn
SCSITaskDeviceClass::Stop ( void )
{
PRINT ( ( "SCSITaskDeviceClass : Stop\n" ) );
if ( fTaskSet != 0 )
{
CFRelease ( fTaskSet );
fTaskSet = 0;
}
if ( fConnection != 0 )
{
PRINT ( ( "SCSITaskDeviceClass : IOServiceClose connection = %d\n", fConnection ) );
IOServiceClose ( fConnection );
fConnection = MACH_PORT_NULL;
}
return kIOReturnSuccess;
}
#if 0
#pragma mark -
#endif
Boolean
SCSITaskDeviceClass::IsExclusiveAccessAvailable ( void )
{
Boolean result = false;
IOReturn status = kIOReturnSuccess;
PRINT ( ( "SCSITaskDeviceClass : IsExclusiveAccessAvailable\n" ) );
require_nonzero ( fConnection, Error_Exit );
if ( fIsServicesLayerInterface )
{
status = IOConnectMethodScalarIScalarO ( fConnection,
kSCSITaskUserClientIsExclusiveAccessAvailable,
0,
0 );
if ( status == kIOReturnSuccess )
{
result = true;
}
}
else
{
result = true;
}
Error_Exit:
return result;
}
IOReturn
SCSITaskDeviceClass::CreateDeviceAsyncEventSource ( CFRunLoopSourceRef * source )
{
IOReturn status = kIOReturnNoDevice;
CFMachPortRef cfMachPort = NULL;
CFMachPortContext context;
Boolean shouldFreeInfo;
PRINT ( ( "SCSITaskDeviceClass : CreateDeviceAsyncEventSource\n" ) );
require_nonzero ( fConnection, Error_Exit );
status = CreateDeviceAsyncPort ( NULL );
require ( ( status == kIOReturnNotPermitted ) || ( status == kIOReturnSuccess ), Error_Exit );
context.version = 1;
context.info = this;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
cfMachPort = CFMachPortCreateWithPort (
kCFAllocatorDefault,
fAsyncPort,
( CFMachPortCallBack ) IODispatchCalloutFromMessage,
&context,
&shouldFreeInfo );
require_nonzero_action ( cfMachPort, Error_Exit, status = kIOReturnNoMemory );
PRINT ( ( "CFMachPortCreateWithPort\n" ) );
fCFRunLoopSource = CFMachPortCreateRunLoopSource ( kCFAllocatorDefault, cfMachPort, 0 );
require_nonzero_action ( fCFRunLoopSource, Error_Exit, status = kIOReturnNoMemory );
PRINT ( ( "CFMachPortCreateRunLoopSource\n" ) );
status = kIOReturnSuccess;
require_nonzero ( source, Error_Exit );
*source = fCFRunLoopSource;
Error_Exit:
if ( cfMachPort != 0 )
{
CFRelease ( cfMachPort );
}
return status;
}
CFRunLoopSourceRef
SCSITaskDeviceClass::GetDeviceAsyncEventSource ( void )
{
PRINT ( ( "GetDeviceAsyncEventSource, %p\n", fCFRunLoopSource ) );
return fCFRunLoopSource;
}
IOReturn
SCSITaskDeviceClass::CreateDeviceAsyncPort ( mach_port_t * port )
{
IOReturn status = kIOReturnNotPermitted;
MyConnectionAndPortContext context;
PRINT ( ( "CreateDeviceAsyncPort called\n" ) );
require ( ( fAsyncPort == MACH_PORT_NULL ), Error_Exit );
IOCreateReceivePort ( kOSAsyncCompleteMessageID, &fAsyncPort );
context.connection = fConnection;
context.asyncPort = fAsyncPort;
CFSetApplyFunction ( fTaskSet, &SCSITaskClass::sSetConnectionAndPort, &context );
status = kIOReturnSuccess;
require_nonzero ( port, Error_Exit );
*port = fAsyncPort;
Error_Exit:
return status;
}
mach_port_t
SCSITaskDeviceClass::GetDeviceAsyncPort ( void )
{
PRINT ( ( "GetDeviceAsyncPort : %d\n", fAsyncPort ) );
return fAsyncPort;
}
IOReturn
SCSITaskDeviceClass::AddCallbackDispatcherToRunLoop ( CFRunLoopRef cfRunLoopRef )
{
IOReturn status = kIOReturnNoDevice;
PRINT ( ( "SCSITaskDeviceClass : AddCallbackDispatcherToRunLoop\n" ) );
require_nonzero ( fConnection, Error_Exit );
status = CreateDeviceAsyncEventSource ( NULL );
require_success ( status, Error_Exit );
fCFRunLoop = cfRunLoopRef;
CFRunLoopAddSource ( fCFRunLoop, fCFRunLoopSource, kCFRunLoopCommonModes );
PRINT ( ( "CFRunLoopAddSource\n" ) );
Error_Exit:
return status;
}
void
SCSITaskDeviceClass::RemoveCallbackDispatcherFromRunLoop ( void )
{
PRINT ( ( "SCSITaskDeviceClass : RemoveCallbackDispatcherFromRunLoop\n" ) );
if ( fCFRunLoopSource != 0 )
{
CFRunLoopRemoveSource ( fCFRunLoop, fCFRunLoopSource, kCFRunLoopCommonModes );
fCFRunLoopSource = 0;
}
if ( fAsyncPort != MACH_PORT_NULL )
{
IOObjectRelease ( fAsyncPort );
fAsyncPort = MACH_PORT_NULL;
}
}
IOReturn
SCSITaskDeviceClass::ObtainExclusiveAccess ( void )
{
IOReturn status = kIOReturnSuccess;
PRINT ( ( "SCSITaskDeviceClass : ObtainExclusiveAccess\n" ) );
require ( fIsServicesLayerInterface, Exit );
status = IOConnectMethodScalarIScalarO ( fConnection,
kSCSITaskUserClientObtainExclusiveAccess,
0,
0 );
require_success ( status, Error_Exit );
PRINT ( ( "we have exclusive access\n" ) );
fHasExclusiveAccess = true;
Error_Exit:
Exit:
return status;
}
IOReturn
SCSITaskDeviceClass::ReleaseExclusiveAccess ( void )
{
IOReturn status = kIOReturnExclusiveAccess;
PRINT ( ( "SCSITaskDeviceClass : ReleaseExclusiveAccess\n" ) );
require ( fHasExclusiveAccess, Error_Exit );
require_action ( fIsServicesLayerInterface, Exit, status = kIOReturnSuccess );
status = IOConnectMethodScalarIScalarO ( fConnection,
kSCSITaskUserClientReleaseExclusiveAccess,
0,
0 );
PRINT ( ( "ReleaseExclusiveAccess status = 0x%08x\n", status ) );
Error_Exit:
Exit:
return status;
}
SCSITaskInterface **
SCSITaskDeviceClass::CreateSCSITask ( void )
{
SCSITaskInterface ** interface = NULL;
PRINT ( ( "SCSITaskDeviceClass : CreateSCSITask\n" ) );
require ( fHasExclusiveAccess, Error_Exit );
interface = SCSITaskClass::alloc ( this, fConnection, fAsyncPort );
require_nonzero ( interface, Error_Exit );
CFSetAddValue ( fTaskSet, interface );
Error_Exit:
return interface;
}
void
SCSITaskDeviceClass::RemoveTaskFromTaskSet ( SCSITaskInterface ** task )
{
PRINT ( ( "SCSITaskDeviceClass : RemoveTaskFromTaskSet called\n" ) );
check ( task );
if ( fTaskSet )
{
CFSetRemoveValue ( fTaskSet, task );
}
}
#if 0
#pragma mark -
#pragma mark Static C->C++ Glue Functions
#pragma mark -
#endif
IOReturn
SCSITaskDeviceClass::sProbe ( void * self,
CFDictionaryRef propertyTable,
io_service_t service,
SInt32 * order )
{
check ( self );
return getThis ( self )->Probe ( propertyTable, service, order );
}
IOReturn
SCSITaskDeviceClass::sStart ( void * self,
CFDictionaryRef propertyTable,
io_service_t service )
{
check ( self );
return getThis ( self )->Start ( propertyTable, service );
}
IOReturn
SCSITaskDeviceClass::sStop ( void * self )
{
check ( self );
return getThis ( self )->Stop ( );
}
Boolean
SCSITaskDeviceClass::sIsExclusiveAccessAvailable ( void * self )
{
check ( self );
return getThis ( self )->IsExclusiveAccessAvailable ( );
}
IOReturn
SCSITaskDeviceClass::sCreateDeviceAsyncEventSource (
void * self,
CFRunLoopSourceRef * source )
{
check ( self );
return getThis ( self )->CreateDeviceAsyncEventSource ( source );
}
CFRunLoopSourceRef
SCSITaskDeviceClass::sGetDeviceAsyncEventSource ( void * self )
{
check ( self );
return getThis ( self )->GetDeviceAsyncEventSource ( );
}
IOReturn
SCSITaskDeviceClass::sCreateDeviceAsyncPort ( void * self, mach_port_t * port )
{
check ( self );
return getThis ( self )->CreateDeviceAsyncPort ( port );
}
mach_port_t
SCSITaskDeviceClass::sGetDeviceAsyncPort ( void * self )
{
check ( self );
return getThis ( self )->GetDeviceAsyncPort ( );
}
IOReturn
SCSITaskDeviceClass::sAddCallbackDispatcherToRunLoop (
void * self,
CFRunLoopRef cfRunLoopRef )
{
check ( self );
return getThis ( self )->AddCallbackDispatcherToRunLoop ( cfRunLoopRef );
}
void
SCSITaskDeviceClass::sRemoveCallbackDispatcherFromRunLoop ( void * self )
{
check ( self );
return getThis ( self )->RemoveCallbackDispatcherFromRunLoop ( );
}
IOReturn
SCSITaskDeviceClass::sObtainExclusiveAccess ( void * self )
{
check ( self );
return getThis ( self )->ObtainExclusiveAccess ( );
}
IOReturn
SCSITaskDeviceClass::sReleaseExclusiveAccess ( void * self )
{
check ( self );
return getThis ( self )->ReleaseExclusiveAccess ( );
}
SCSITaskInterface **
SCSITaskDeviceClass::sCreateSCSITask ( void * self )
{
check ( self );
return getThis ( self )->CreateSCSITask ( );
}