IOFireWireMultiIsochReceive.cpp   [plain text]


/*
 * Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@ 
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireMultiIsochReceive.h>
///////////////////////////////////////////////////////////////////////////////////
//
// Definition of objects used by the Multi-Isoch Receiver
//
///////////////////////////////////////////////////////////////////////////////////
OSDefineMetaClassAndStructors(IOFireWireMultiIsochReceiveListener, OSObject)
OSDefineMetaClassAndStructors(IOFireWireMultiIsochReceivePacket, OSObject)

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceiveListener::init
///////////////////////////////////////////////////////////////////////////////////
bool IOFireWireMultiIsochReceiveListener::init(IOFireWireController *fwController,
											   UInt32 receiveChannel,
											   FWMultiIsochReceiveListenerCallback callback,
											   void *pCallbackRefCon,
											   FWMultiIsochReceiveListenerParams *pListenerParams)
{
	bool success = true;
	
	//IOLog( "IOFireWireMultiIsochReceiveListener::init (0x%08X)\n",(int) this);
	
	// init super
    if( !OSObject::init() )
        success = false;
	
	if( success )
	{
		// Initialize this object
		fControl = fwController;
		fChannel = receiveChannel;
		fClientCallback = callback;
		fClientCallbackRefCon = pCallbackRefCon;
		fActivated = false;
		
		if (pListenerParams)
		{
			fListenerParams = new FWMultiIsochReceiveListenerParams;
			if (fListenerParams)
			{
				// copy over the parameters specified by the client.
				fListenerParams->maxLatencyInFireWireCycles = pListenerParams->maxLatencyInFireWireCycles;
				fListenerParams->expectedStreamBitRate = pListenerParams->expectedStreamBitRate;
				fListenerParams->clientPacketReturnLatencyInFireWireCycles = pListenerParams->clientPacketReturnLatencyInFireWireCycles;
			}
		}
		else
			fListenerParams = NULL;
	}
	
	return success;
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceiveListener::free
///////////////////////////////////////////////////////////////////////////////////
void IOFireWireMultiIsochReceiveListener::free()
{
	if (fListenerParams)
	{
		delete fListenerParams;
		fListenerParams = NULL;
	}
	
	OSObject::free();
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceiveListener::create
///////////////////////////////////////////////////////////////////////////////////
IOFireWireMultiIsochReceiveListener * IOFireWireMultiIsochReceiveListener::create(IOFireWireController *fwController,
																				  UInt32 channel,
																				  FWMultiIsochReceiveListenerCallback callback,
																				  void *pCallbackRefCon,
																				  FWMultiIsochReceiveListenerParams *pListenerParams)
{
	IOFireWireMultiIsochReceiveListener * listener;
	
	listener = OSTypeAlloc( IOFireWireMultiIsochReceiveListener );
	
    if( listener != NULL && !listener->init(fwController,
											channel,
											callback,
											pCallbackRefCon,
											pListenerParams))
	{
        listener->release();
        listener = NULL;
    }
	
    return listener;
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceiveListener::Activate
///////////////////////////////////////////////////////////////////////////////////
IOReturn IOFireWireMultiIsochReceiveListener::Activate()
{
	return fControl->activateMultiIsochReceiveListener(this);
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceiveListener::Deactivate
///////////////////////////////////////////////////////////////////////////////////
IOReturn IOFireWireMultiIsochReceiveListener::Deactivate()
{
	return fControl->deactivateMultiIsochReceiveListener(this);
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceiveListener::SetCallback
///////////////////////////////////////////////////////////////////////////////////
IOReturn IOFireWireMultiIsochReceiveListener::SetCallback(FWMultiIsochReceiveListenerCallback callback,
														  void *pCallbackRefCon)
{
	if (!fActivated)
	{
		fClientCallback = callback;
		fClientCallbackRefCon = pCallbackRefCon;
		return kIOReturnSuccess;
	}
	else
		return kIOReturnNotPermitted;
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::init
///////////////////////////////////////////////////////////////////////////////////
bool IOFireWireMultiIsochReceivePacket::init(IOFireWireController *fwController)
{
	bool success = true;
	
	//IOLog( "IOFireWireMultiIsochReceivePacket::init (0x%08X)\n",(int) this);
	
	// init super
    if( !OSObject::init() )
        success = false;
	
	if( success )
	{
		// Initialize this object
		fControl = fwController;
		numRanges = 0;
		numClientReferences = 0;
	}
	
	return success;
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::free
///////////////////////////////////////////////////////////////////////////////////
void IOFireWireMultiIsochReceivePacket::free()
{
	OSObject::free();
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::create
///////////////////////////////////////////////////////////////////////////////////
IOFireWireMultiIsochReceivePacket * IOFireWireMultiIsochReceivePacket::create( IOFireWireController *fwController )
{
	IOFireWireMultiIsochReceivePacket * packet;
	
	packet = OSTypeAlloc( IOFireWireMultiIsochReceivePacket );
	
    if( packet != NULL && !packet->init(fwController))
	{
        packet->release();
        packet = NULL;
    }
	
    return packet;
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::clientDone
///////////////////////////////////////////////////////////////////////////////////
void IOFireWireMultiIsochReceivePacket::clientDone( void )
{
	fControl->clientDoneWithMultiIsochReceivePacket(this);
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::isochChannel
///////////////////////////////////////////////////////////////////////////////////
UInt32 
IOFireWireMultiIsochReceivePacket::isochChannel(void)
{
	// The isoch channel number is in the first quad,
	// which is guarranted to be in the first range.
	
	UInt32 *pIsochPacketHeader = (UInt32*)  ranges[0].address;
	UInt32 isochPacketHeader = OSSwapLittleToHostInt32(*pIsochPacketHeader);
	return ((isochPacketHeader & 0x00003F00) >> 8);
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::isochPayloadSize
///////////////////////////////////////////////////////////////////////////////////
UInt32 
IOFireWireMultiIsochReceivePacket::isochPayloadSize(void)
{
	// The isoch payload size is in the first quad,
	// which is guarranted to be in the first range.
	
	UInt32 *pIsochPacketHeader = (UInt32*)  ranges[0].address;
	UInt32 isochPacketHeader = OSSwapLittleToHostInt32(*pIsochPacketHeader);
	return ((isochPacketHeader & 0xFFFF0000) >> 16);
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::packetReceiveTime
///////////////////////////////////////////////////////////////////////////////////
UInt32 
IOFireWireMultiIsochReceivePacket::packetReceiveTime(void)
{
	// The isoch timestamp is in the last quad,
	// which is guarranted to be in the last range.
	
	UInt32 *pIsochPacketTrailer = (UInt32*) ranges[numRanges-1].address;
	pIsochPacketTrailer += ((ranges[numRanges-1].length/4)-1);	// Bump to the last quadlet in the range
	UInt32 isochPacketTrailer = OSSwapLittleToHostInt32(*pIsochPacketTrailer);
	
	// We shift the 16-bit time-stamp into the normal 7:13:12 FireWire cycle-time format!
	return ((isochPacketTrailer & 0x0000FFFF) << 12);
}

///////////////////////////////////////////////////////////////////////////////////
// IOFireWireMultiIsochReceivePacket::createMemoryDescriptorForRanges
///////////////////////////////////////////////////////////////////////////////////
IOMemoryDescriptor*
IOFireWireMultiIsochReceivePacket::createMemoryDescriptorForRanges(void)
{
	IOMemoryDescriptor * bufferDesc = NULL ;
	IOReturn error;
	
	bufferDesc = IOMemoryDescriptor::withAddressRanges (ranges, numRanges, kIODirectionOut, kernel_task) ;
	if ( ! bufferDesc )
	{
		error = kIOReturnNoMemory ;
	}
	else
	{
		error = bufferDesc->prepare() ;
		if (error != kIOReturnSuccess)
		{
			bufferDesc->release();
			bufferDesc = NULL;
		}
	}
	
	return bufferDesc;
}