IOFWUserPHYPacketListener.cpp [plain text]
#include "IOFWUserPHYPacketListener.h"
#import <IOKit/firewire/IOFireWireController.h>
#import <IOKit/firewire/IOFireWireNub.h>
#import <IOKit/firewire/IOFWPHYPacketListener.h>
OSDefineMetaClassAndStructors( IOFWUserPHYPacketListener, IOFWPHYPacketListener );
IOFWUserPHYPacketListener *
IOFWUserPHYPacketListener::withUserClient( IOFireWireUserClient * inUserClient, UInt32 queue_count )
{
IOFWUserPHYPacketListener* result = NULL;
result = OSTypeAlloc( IOFWUserPHYPacketListener );
if( result && !result->initWithUserClient( inUserClient, queue_count ) )
{
result->release();
result = NULL;
}
return result;
}
bool
IOFWUserPHYPacketListener::initWithUserClient( IOFireWireUserClient * inUserClient, UInt32 queue_count )
{
bool success = true;
IOFireWireController * control = inUserClient->getOwner()->getController();
if( !IOFWPHYPacketListener::initWithController( control ) )
success = false;
if( success )
{
fUserClient = inUserClient;
fMaxQueueCount = queue_count;
if( fMaxQueueCount < 2 )
{
fMaxQueueCount = 2;
}
fAllocatedQueueCount = 0;
fElementWaitingCompletion = NULL;
fLock = IOLockAlloc();
if( fLock == NULL )
{
success = false;
}
}
return success;
}
void
IOFWUserPHYPacketListener::free( void )
{
destroyAllElements();
if( fLock )
{
IOLockFree( fLock );
fLock = NULL;
}
IOFWPHYPacketListener::free();
}
void
IOFWUserPHYPacketListener::exporterCleanup( const OSObject * self )
{
IOFWUserPHYPacketListener * me = (IOFWUserPHYPacketListener*)self;
DebugLog("IOFWUserPHYPacketListener::exporterCleanup\n");
me->deactivate();
}
#pragma mark -
IOReturn
IOFWUserPHYPacketListener::setPacketCallback( OSAsyncReference64 async_ref,
mach_vm_address_t callback,
io_user_reference_t refCon )
{
if( callback )
{
IOFireWireUserClient::setAsyncReference64( fCallbackAsyncRef, (mach_port_t)async_ref[0], callback, refCon );
}
else
{
fCallbackAsyncRef[0] = 0;
}
return kIOReturnSuccess;
}
IOReturn
IOFWUserPHYPacketListener::setSkippedCallback( OSAsyncReference64 async_ref,
mach_vm_address_t callback,
io_user_reference_t refCon )
{
if( callback )
{
IOFireWireUserClient::setAsyncReference64( fSkippedAsyncRef, (mach_port_t)async_ref[0], callback, refCon );
}
else
{
fSkippedAsyncRef[0] = 0;
}
return kIOReturnSuccess;
}
void IOFWUserPHYPacketListener::processPHYPacket( UInt32 data1, UInt32 data2 )
{
IOLockLock( fLock );
PHYRxElement * element = NULL;
element = allocateDataElement();
if( element )
{
element->type = kTypeData;
element->data1 = data1;
element->data2 = data2;
if( fElementWaitingCompletion == NULL )
{
sendPacketNotification( element );
}
else
{
addElementToPendingList( element );
}
}
else
{
FWKLOGASSERT( fElementWaitingCompletion != NULL );
if( fPendingListTail && fPendingListTail->type == kTypeSkipped )
{
element = fPendingListTail;
FWKLOGASSERT( fPendingListTail != fElementWaitingCompletion );
UInt32 count = element->getSkippedCount();
count++;
element->setSkippedCount( count );
}
else
{
element = allocateElement();
if( element )
{
element->type = kTypeSkipped;
element->setSkippedCount( 1 );
addElementToPendingList( element );
}
else
{
IOLog( "FireWire - UserPHYPacketListener out of elements\n" );
}
}
}
IOLockUnlock( fLock );
}
void
IOFWUserPHYPacketListener::clientCommandIsComplete( FWClientCommandID commandID )
{
IOLockLock( fLock );
if( fElementWaitingCompletion == commandID )
{
deallocateElement( fElementWaitingCompletion );
fElementWaitingCompletion = NULL;
PHYRxElement * element = fPendingListHead;
if( element )
{
removeElementFromPendingList( element );
sendPacketNotification( element );
}
}
IOLockUnlock( fLock );
}
void
IOFWUserPHYPacketListener::sendPacketNotification( IOFWUserPHYPacketListener::PHYRxElement * element )
{
if( fElementWaitingCompletion == NULL )
{
if( element->type == kTypeData )
{
fElementWaitingCompletion = element;
io_user_reference_t args[3];
args[0] = (io_user_reference_t)element; args[1] = element->data1; args[2] = element->data2;
IOFireWireUserClient::sendAsyncResult64( fCallbackAsyncRef, kIOReturnSuccess, args, 3 );
}
else if( element->type == kTypeSkipped )
{
fElementWaitingCompletion = element;
io_user_reference_t args[3];
args[0] = (io_user_reference_t)element; args[1] = element->getSkippedCount(); args[2] = 0;
IOFireWireUserClient::sendAsyncResult64( fSkippedAsyncRef, kIOReturnSuccess, args, 3 );
}
}
}
#pragma mark -
IOFWUserPHYPacketListener::PHYRxElement * IOFWUserPHYPacketListener::allocateElement( void )
{
PHYRxElement * element = fFreeListHead;
if( element == NULL )
{
if(fAllocatedQueueCount < fMaxQueueCount )
{
element = new PHYRxElement;
if( element != NULL )
{
element->next = NULL;
element->prev = NULL;
element->type = kTypeNone;
element->state = kFreeState;
element->data1 = 0;
element->data2 = 0;
fFreeListHead = element;
fFreeListTail = element;
fAllocatedQueueCount++;
}
}
}
if( element != NULL )
{
fFreeListHead = element->next;
if( fFreeListHead )
{
fFreeListHead->prev = NULL;
}
else
{
FWKLOGASSERT( fFreeListTail == element );
fFreeListTail = NULL;
}
FWKLOGASSERT( element->prev == NULL );
FWKLOGASSERT( element->state == kFreeState );
element->next = NULL;
element->prev = NULL;
element->state = kFreeState;
DebugLog( "IOFWUserPHYPacketListener::allocateElement - element = %p\n", element );
}
return element;
}
IOFWUserPHYPacketListener::PHYRxElement * IOFWUserPHYPacketListener::allocateDataElement( void )
{
PHYRxElement * element = fFreeListHead;
if( element == NULL )
{
if( fAllocatedQueueCount < (fMaxQueueCount - 1) )
{
element = new PHYRxElement;
if( element != NULL )
{
element->next = NULL;
element->prev = NULL;
element->type = kTypeNone;
element->state = kFreeState;
element->data1 = 0;
element->data2 = 0;
fFreeListHead = element;
fFreeListTail = element;
fAllocatedQueueCount++;
}
}
}
if( element != NULL )
{
if( (element != fFreeListTail) || (fAllocatedQueueCount < (fMaxQueueCount - 1)) ) {
fFreeListHead = element->next;
if( fFreeListHead )
{
fFreeListHead->prev = NULL;
}
else
{
FWKLOGASSERT( fFreeListTail == element );
fFreeListTail = NULL;
}
FWKLOGASSERT( element->prev == NULL );
FWKLOGASSERT( element->state == kFreeState );
element->next = NULL;
element->prev = NULL;
element->state = kFreeState;
DebugLog( "IOFWUserPHYPacketListener::allocateDataElement - element = %p\n", element );
}
else
{
element = NULL;
}
}
return element;
}
void IOFWUserPHYPacketListener::deallocateElement( PHYRxElement * element )
{
DebugLog( "IOFWUserPHYPacketListener::deallocateElement - element = %p\n", element );
element->next = NULL;
element->prev = fFreeListTail;
element->state = kFreeState;
if( fFreeListTail )
{
fFreeListTail->next = element;
}
else
{
FWKLOGASSERT( fFreeListHead == NULL )
fFreeListHead = element;
}
fFreeListTail = element;
FWKLOGASSERT( fFreeListHead != NULL );
FWKLOGASSERT( fFreeListTail != NULL );
}
#pragma mark -
void IOFWUserPHYPacketListener::destroyAllElements( void )
{
DebugLog(( "IOFWUserPHYPacketListener::destroyAllElements\n" ));
{
PHYRxElement * element = fPendingListHead;
while( element )
{
PHYRxElement * next_element = element->next;
removeElementFromPendingList( element );
deallocateElement( element );
element = next_element;
}
FWKLOGASSERT( fPendingListHead == NULL );
fPendingListHead = NULL;
FWKLOGASSERT( fPendingListTail == NULL );
fPendingListTail = NULL; }
{
PHYRxElement * element = fFreeListHead;
while( element )
{
PHYRxElement * next_element = element->next;
delete element;
element = next_element;
}
fFreeListHead = 0;
fFreeListTail = 0;
}
}
#pragma mark -
void IOFWUserPHYPacketListener::addElementToPendingList( PHYRxElement * element )
{
DebugLog( "IOFWUserPHYPacketListener::addElementToPendingList - element = %p\n", element );
FWKLOGASSERT( element != NULL );
FWKLOGASSERT( element->next == NULL );
FWKLOGASSERT( element->state == kFreeState );
element->next = NULL;
element->prev = fPendingListTail;
element->state = kPendingState;
if( fPendingListTail )
{
fPendingListTail->next = element;
}
else
{
FWKLOGASSERT( fPendingListHead == NULL );
fPendingListHead = element;
}
fPendingListTail = element;
FWKLOGASSERT( fPendingListHead != NULL );
FWKLOGASSERT( fPendingListTail != NULL );
}
void IOFWUserPHYPacketListener::removeElementFromPendingList( PHYRxElement * element )
{
DebugLog( "IOFWUserPHYPacketListener::removeElementFromPendingList - element = %p\n", element );
FWKLOGASSERT( element->state != kFreeState );
if( fPendingListHead == element )
{
FWKLOGASSERT( element->prev == NULL );
fPendingListHead = element->next;
if( fPendingListHead != NULL )
{
fPendingListHead->prev = NULL;
}
}
else
{
FWPANICASSERT( element->prev != NULL );
element->prev->next = element->next;
}
if( fPendingListTail == element )
{
FWKLOGASSERT( element->next == NULL );
fPendingListTail = element->prev;
if( fPendingListTail != NULL )
{
fPendingListTail->prev = NULL;
}
}
else
{
FWPANICASSERT( element->next != NULL );
element->next->prev = element->prev;
}
element->next = NULL;
element->prev = NULL;
}