IOFWIsochChannel.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFWIsochChannel.h>
#include <IOKit/firewire/IOFWLocalIsochPort.h>
#include <IOKit/firewire/IOFWCommand.h>
#include <IOKit/firewire/IOFireWireDevice.h>
#import <IOKit/firewire/IOFWDCLProgram.h>
#import <IOKit/firewire/IOFireWireLink.h>
#include <libkern/c++/OSSet.h>
#include <libkern/c++/OSCollectionIterator.h>
#include "FWDebugging.h"
OSDefineMetaClassAndStructors(IOFWIsochChannel, OSObject)
OSMetaClassDefineReservedUnused(IOFWIsochChannel, 0);
OSMetaClassDefineReservedUnused(IOFWIsochChannel, 1);
OSMetaClassDefineReservedUnused(IOFWIsochChannel, 2);
OSMetaClassDefineReservedUnused(IOFWIsochChannel, 3);
#pragma mark -
bool IOFWIsochChannel::init( IOFireWireController * control,
bool doIRM,
UInt32 packetSize,
IOFWSpeed prefSpeed,
ForceStopNotificationProc * stopProc,
void * stopRefCon )
{
bool success = true;
FWKLOG(( "IOFWIsochChannel::init - doIRM = %d\n", doIRM ));
DebugLog("fPacketSize = %ld\n", packetSize) ;
success = OSObject::init();
if( success )
{
fControl = control;
fDoIRM = doIRM;
fPacketSize = packetSize;
fPrefSpeed = prefSpeed;
fStopProc = stopProc;
fStopRefCon = stopRefCon;
fTalker = NULL;
fChannel = 64; fBandwidth = 0;
fLock = IOLockAlloc();
if( fLock == NULL )
{
success = false;
}
}
if( success )
{
fListeners = OSSet::withCapacity( 1 );
if( fListeners == NULL )
{
success = false;
}
}
if( success )
{
fReadCmd = new IOFWReadQuadCommand;
if( fReadCmd == NULL )
{
success = false;
}
}
if( success )
{
fReadCmd->initAll( fControl, 0, FWAddress(), NULL, 0, NULL, NULL );
}
if( success )
{
fLockCmd = new IOFWCompareAndSwapCommand;
if( fLockCmd == NULL )
{
success = false;
}
}
if( success )
{
fLockCmd->initAll( fControl, 0, FWAddress(), NULL, NULL, 0, NULL, NULL );
}
return success;
}
void IOFWIsochChannel::free()
{
if( fListeners )
{
fListeners->release();
fListeners = NULL;
}
if( fReadCmd )
{
fReadCmd->release();
fReadCmd = NULL;
}
if( fLockCmd )
{
fLockCmd->release();
fLockCmd = NULL;
}
if( fLock )
{
IOLockFree( fLock );
fLock = NULL;
}
OSObject::free();
}
#pragma mark -
IOReturn IOFWIsochChannel::checkMemoryInRange( IOMemoryDescriptor * memory )
{
IOReturn status = kIOReturnSuccess;
if( memory == NULL )
{
status = kIOReturnBadArgument;
}
bool memory_prepared = false;
if( status == kIOReturnSuccess )
{
status = memory->prepare( kIODirectionInOut );
}
if( status == kIOReturnSuccess )
{
memory_prepared = true;
}
UInt64 length = 0;
if( status == kIOReturnSuccess )
{
length = memory->getLength();
if( length == 0 )
{
status = kIOReturnError;
}
}
IODMACommand * dma_command = NULL;
if( status == kIOReturnSuccess )
{
dma_command = IODMACommand::withSpecification(
kIODMACommandOutputHost64, 64, length, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly), length, 0, NULL, NULL ); if( dma_command == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
status = dma_command->setMemoryDescriptor( memory, false );
}
bool dma_command_prepared = false;
if( status == kIOReturnSuccess )
{
status = dma_command->prepare( 0, length, true );
}
if( status == kIOReturnSuccess )
{
dma_command_prepared = true;
}
if( status == kIOReturnSuccess )
{
UInt64 offset = 0;
UInt64 mask = fControl->getFireWirePhysicalAddressMask();
while( (offset < length) && (status == kIOReturnSuccess) )
{
IODMACommand::Segment64 segments[10];
UInt32 num_segments = 10;
status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments );
if( status == kIOReturnSuccess )
{
for( UInt32 i = 0; i < num_segments; i++ )
{
if( (segments[i].fIOVMAddr & (~mask)) )
{
status = kIOReturnNotPermitted;
break;
}
}
}
}
}
if( dma_command_prepared )
{
dma_command->complete();
dma_command_prepared = false;
}
if( dma_command )
{
dma_command->clearMemoryDescriptor();
dma_command->release();
dma_command = NULL;
}
if( memory_prepared )
{
memory->complete();
memory_prepared = false;
}
return status;
}
IOReturn IOFWIsochChannel::setTalker( IOFWIsochPort *talker )
{
IOReturn error = kIOReturnSuccess;
fTalker = talker;
IOFWLocalIsochPort * localIsochPort = OSDynamicCast( IOFWLocalIsochPort, talker );
if ( localIsochPort )
{
IODCLProgram * program = localIsochPort->getProgramRef();
IOMemoryMap * map = program->getBufferMap();
if( map == NULL )
{
error = kIOReturnNoMemory;
}
IOMemoryDescriptor * memory = NULL;
if( error == kIOReturnSuccess )
{
memory = map->getMemoryDescriptor();
if( memory == NULL )
{
error = kIOReturnNoMemory;
}
}
if( error == kIOReturnSuccess )
{
error = checkMemoryInRange( memory );
}
if( error == kIOReturnSuccess )
{
program->setForceStopProc( fStopProc, fStopRefCon, this );
program->release();
}
}
return error;
}
IOReturn IOFWIsochChannel::addListener( IOFWIsochPort *listener )
{
IOReturn error = kIOReturnSuccess;
if( !fListeners->setObject( listener ) )
{
error = kIOReturnNoMemory;
}
if ( !error )
{
IOFWLocalIsochPort * localIsochPort = OSDynamicCast( IOFWLocalIsochPort, listener ) ;
if ( localIsochPort )
{
IODCLProgram * program = localIsochPort->getProgramRef();
IOMemoryMap * map = program->getBufferMap();
if( map == NULL )
{
error = kIOReturnNoMemory;
}
IOMemoryDescriptor * memory = NULL;
if( error == kIOReturnSuccess )
{
memory = map->getMemoryDescriptor();
if( memory == NULL )
{
error = kIOReturnNoMemory;
}
}
if( error == kIOReturnSuccess )
{
error = checkMemoryInRange( memory );
}
if( error == kIOReturnSuccess )
{
program->setForceStopProc( fStopProc, fStopRefCon, this ) ;
program->release() ;
}
}
}
return error ;
}
IOReturn IOFWIsochChannel::start()
{
DebugLog("channel %p start\n", this ) ;
OSIterator *listenIterator;
IOFWIsochPort *listen;
IOReturn error = kIOReturnSuccess ;
if ( fDoIRM && fChannel == 64 )
{
return kIOReturnNotReady ;
}
listenIterator = OSCollectionIterator::withCollection( fListeners );
if( listenIterator )
{
listenIterator->reset();
while( !error && (listen = (IOFWIsochPort *)listenIterator->getNextObject()) )
{
error = listen->start();
}
listenIterator->release();
}
if( !error && fTalker )
{
error = fTalker->start();
}
if (error)
{
DebugLog("channel %p start - error=%x\n", this, error ) ;
}
else
{
DebugLog("channel %p start - started on isoch channel %ld\n", this, fChannel ) ;
}
return error ;
}
IOReturn IOFWIsochChannel::stop()
{
DebugLog("channel %p stop\n", this ) ;
OSIterator *listenIterator;
IOFWIsochPort *listen;
listenIterator = OSCollectionIterator::withCollection( fListeners );
if( listenIterator )
{
listenIterator->reset();
while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) )
{
listen->stop();
}
listenIterator->release();
}
if( fTalker )
{
fTalker->stop();
}
return kIOReturnSuccess;
}
#pragma mark -
IOReturn IOFWIsochChannel::allocateChannel()
{
DebugLog("channel %p allocateChannel\n", this ) ;
IOReturn status = kIOReturnSuccess;
IOFWIsochPort * listen = NULL;
OSIterator * listenIterator = NULL;
if( status == kIOReturnSuccess )
{
UInt64 portChans;
IOFWSpeed portSpeed;
UInt64 allowedChans;
IOFWSpeed speed;
speed = fPrefSpeed;
allowedChans = ~(UInt64)0;
if( fTalker )
{
fTalker->getSupported( portSpeed, portChans );
if( portSpeed < speed )
{
speed = portSpeed;
}
allowedChans &= portChans;
}
listenIterator = OSCollectionIterator::withCollection( fListeners );
if( listenIterator )
{
while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) )
{
listen->getSupported( portSpeed, portChans );
if( portSpeed < speed )
{
speed = portSpeed;
}
allowedChans &= portChans;
}
}
status = allocateChannelBegin( speed, allowedChans );
}
if( status == kIOReturnSuccess )
{
if( listenIterator )
{
listenIterator->reset();
while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) &&
(status == kIOReturnSuccess) )
{
status = listen->allocatePort( fSpeed, fChannel );
}
}
}
if( status == kIOReturnSuccess )
{
if( fTalker )
{
status = fTalker->allocatePort( fSpeed, fChannel );
}
}
if( listenIterator )
{
listenIterator->release();
}
if( status != kIOReturnSuccess )
{
releaseChannel();
}
return status;
}
IOReturn IOFWIsochChannel::allocateChannelBegin( IOFWSpeed inSpeed,
UInt64 inAllowedChans,
UInt32 * outChannel )
{
DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - entered, inSpeed = %d, fDoIRM = %d, inAllowedChans = 0x%016llx, fChannel=%ld, fBandwidth=%ld\n", this, inSpeed, fDoIRM, inAllowedChans, fChannel, fBandwidth );
IOReturn status = kIOReturnSuccess;
IOLockLock( fLock );
fSpeed = ( inSpeed == kFWSpeedMaximum ) ? fControl->getLink()->getPhySpeed() : inSpeed ;
if( fDoIRM )
{
UInt32 oldIRM[3];
UInt32 bandwidth = (fPacketSize/4 + 3) * 16 / (1 << inSpeed);
do
{
FWAddress addr ;
UInt32 generation ;
status = kIOReturnSuccess ;
fControl->getIRMNodeID( generation, addr.nodeID );
DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - generation %ld\n", this, generation );
{
unsigned delayRetries = 15;
while (delayRetries > 0)
{
UInt32 currentGeneration;
AbsoluteTime currentUpTime;
UInt64 nanos;
UInt32 delayInMSec;
clock_get_uptime( & currentUpTime );
SUB_ABSOLUTETIME( & currentUpTime, fControl->getResetTime() ) ;
absolutetime_to_nanoseconds( currentUpTime, & nanos ) ;
if (nanos < 1000000000LL)
{
delayInMSec = (UInt32) ((1000000000LL - nanos)/1000000LL);
DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - delaying for %ld msec\n", this, delayInMSec);
IOSleep(delayInMSec);
fControl->getIRMNodeID( currentGeneration, addr.nodeID );
if (currentGeneration == generation)
{
break;
}
else
{
generation = currentGeneration; }
}
else
{
break;
}
delayRetries--;
}
if (delayRetries == 0)
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - timed out waiting for bus resets to end\n", this) ;
status = kIOReturnTimeout;
}
}
if( status == kIOReturnSuccess )
{
addr.addressHi = kCSRRegisterSpaceBaseAddressHi ;
addr.addressLo = kCSRBandwidthAvailable ;
fReadCmd->reinit( generation, addr, oldIRM, 3 );
fReadCmd->setMaxPacket( 4 );
status = fReadCmd->submit();
DebugLogCond( status, "IOFWIsochChannel<%p>::allocateChannelBegin() line %u - read command got error 0x%x\n", this, __LINE__, status ) ;
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - oldIRM set to %08x %08x %08x\n", this,
OSSwapBigToHostInt32(oldIRM[0]), OSSwapBigToHostInt32(oldIRM[1]), OSSwapBigToHostInt32(oldIRM[2]) ) ;
}
if ( fBandwidth == 0 )
{
UInt32 old_bandwidth = OSSwapBigToHostInt32( oldIRM[0] );
if( ( status == kIOReturnSuccess ) && ( old_bandwidth < bandwidth ) )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - no bandwidth left\n", this) ;
status = kIOReturnNoSpace;
}
if( status == kIOReturnSuccess )
{
UInt32 newVal = OSSwapHostToBigInt32(old_bandwidth - bandwidth);
fLockCmd->reinit( generation, addr, &oldIRM[0], &newVal, 1 );
status = fLockCmd->submit();
if ( status )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() line %u - lock command got error 0x%x\n", this, __LINE__, status ) ;
}
else
{
if ( !fLockCmd->locked( &oldIRM[0] ) )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - lock for bandwidth failed\n", this) ;
status = kIOReturnCannotLock;
}
}
if( status == kIOReturnSuccess )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - allocated bandwidth %lu\n", this, bandwidth) ;
fBandwidth = bandwidth;
}
}
}
if ( status == kIOReturnSuccess && fChannel == 64 )
{
unsigned channel ;
UInt32 old_channel_hi = OSSwapBigToHostInt32( oldIRM[1] );
UInt32 old_channel_lo = OSSwapBigToHostInt32( oldIRM[2] );
inAllowedChans &= (UInt64)(old_channel_lo) | ((UInt64)old_channel_hi << 32);
for( channel = 0; channel < 64; ++channel )
{
if( inAllowedChans & ((UInt64)1 << (63 - channel)) )
{
break;
}
}
if( channel == 64 )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - no acceptable free channels\n", this) ;
status = kIOReturnNoResources;
}
if( status == kIOReturnSuccess )
{
UInt32 * oldPtr;
UInt32 newVal ;
if( channel < 32 )
{
addr.addressLo = kCSRChannelsAvailable31_0;
oldPtr = &oldIRM[1];
newVal = OSSwapHostToBigInt32( old_channel_hi & ~(1<<(31 - channel)) );
}
else
{
addr.addressLo = kCSRChannelsAvailable63_32;
oldPtr = &oldIRM[2];
newVal = OSSwapHostToBigInt32( old_channel_lo & ~(1 << (63 - channel)) );
}
fLockCmd->reinit( generation, addr, oldPtr, &newVal, 1 );
status = fLockCmd->submit();
if ( status )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - lock command got error 0x%x\n", this, status ) ;
}
else
{
if( !fLockCmd->locked(oldPtr) )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - couldn't claim channel %u\n", this, channel) ;
status = kIOReturnCannotLock;
}
}
}
if( status == kIOReturnSuccess )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - allocated channel %u\n", this, channel) ;
fChannel = channel;
if( outChannel != NULL )
{
*outChannel = channel;
}
}
else if ( fBandwidth != 0 )
{
fControl->releaseIRMBandwidthInGeneration(fBandwidth, generation);
}
}
if( status == kIOReturnSuccess )
{
fGeneration = generation;
fControl->addAllocatedChannel(this);
}
if( status == kIOFireWireBusReset )
{
fBandwidth = 0;
fChannel = 64;
}
} while( (status == kIOFireWireBusReset) || (status == kIOReturnCannotLock) );
}
else
{
unsigned channel ;
{
for( channel = 0; channel < 64; channel++ )
{
if( inAllowedChans & ((UInt64)1 << (63 - channel)) )
{
break;
}
}
if( channel == 64 )
{
DebugLog("IOFWIsochChannel<%p>::allocateChannelBegin() - couldn't find acceptable channel\n", this) ;
status = kIOReturnNoResources;
}
}
if( status == kIOReturnSuccess )
{
DebugLog( "IOFWIsochChannel<%p>::allocateChannelBegin() - allocated channel = %d\n", this, channel );
fChannel = channel;
if( outChannel != NULL )
{
*outChannel = channel;
}
}
}
IOLockUnlock( fLock );
DebugLogCond( status, "IOFWIsochChannel<%p>::allocateChannelBegin() - exited with status = 0x%x\n", this, status );
return status;
}
struct ChannelThreadInfo
{
IOFWIsochChannel * fChannel;
UInt32 fGeneration;
};
void IOFWIsochChannel::handleBusReset()
{
ChannelThreadInfo * threadInfo = (ChannelThreadInfo *)IOMalloc( sizeof(ChannelThreadInfo) );
if( threadInfo )
{
threadInfo->fGeneration = fControl->getGeneration();
threadInfo->fChannel = this;
retain(); IOCreateThread( threadFunc, threadInfo );
}
}
void IOFWIsochChannel::threadFunc( void * arg )
{
ChannelThreadInfo * threadInfo = (ChannelThreadInfo *)arg;
IOFWIsochChannel * channel = threadInfo->fChannel;
UInt32 generation = threadInfo->fGeneration;
channel->reallocBandwidth( generation );
IOFree( threadInfo, sizeof(threadInfo) );
channel->release(); }
void IOFWIsochChannel::reallocBandwidth( UInt32 generation )
{
IOReturn result = kIOReturnSuccess;
FWAddress addr( kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable );
IOLockLock( fLock );
InfoLog( "IOFWIsochChannel<%p>::reallocBandwidth() - bandwidth %ld, channel = %ld\n", this, fBandwidth, fChannel );
if( result == kIOReturnSuccess )
{
UInt32 current_generation;
UInt16 irm;
fControl->getIRMNodeID( current_generation, irm );
addr.nodeID = irm;
if( current_generation != generation )
{
result = kIOFireWireBusReset;
}
}
if( result == kIOReturnSuccess )
{
if( fGeneration == generation )
{
result = kIOReturnError;
}
}
if( fBandwidth != 0 )
{
UInt32 oldVal = 0;
if( result == kIOReturnSuccess )
{
fReadCmd->reinit( generation, addr, &oldVal, 1 );
result = fReadCmd->submit();
}
bool done = false;
while( (result == kIOReturnSuccess) && !done )
{
UInt32 newVal = 0;
UInt32 old_bandwidth = OSSwapBigToHostInt32( oldVal );
if( old_bandwidth < fBandwidth )
{
result = kIOReturnNoSpace;
}
if( result == kIOReturnSuccess )
{
newVal = OSSwapHostToBigInt32(old_bandwidth - fBandwidth);
fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 );
result = fLockCmd->submit();
}
if( result == kIOReturnSuccess )
{
done = fLockCmd->locked(&oldVal);
}
}
if( result == kIOReturnNoSpace )
{
DebugLog( "IOFWIsochChannel<%p>::reallocBandwidth() - failed to reallocate bandwidth = %ld, channel = %ld\n", this, fBandwidth, fChannel );
fBandwidth = 0;
fChannel = 64; }
else
{
InfoLog( "IOFWIsochChannel<%p>::reallocBandwidth() - reallocated bandwidth = %ld\n", this, fBandwidth );
}
}
if( fChannel != 64 )
{
UInt32 mask = 0;
UInt32 oldVal = 0;
if( result == kIOReturnSuccess )
{
if( fChannel <= 31 )
{
addr.addressLo = kCSRChannelsAvailable31_0;
mask = 1 << (31-fChannel);
}
else
{
addr.addressLo = kCSRChannelsAvailable63_32;
mask = 1 << (63-fChannel);
}
fReadCmd->reinit( generation, addr, &oldVal, 1 );
result = fReadCmd->submit();
}
bool done = false;
while( (result == kIOReturnSuccess) && !done )
{
UInt32 old_channels_avail = OSSwapBigToHostInt32( oldVal );
UInt32 newVal = OSSwapHostToBigInt32( old_channels_avail & ~mask );
if( newVal == oldVal )
{
result = kIOFireWireChannelNotAvailable ;
}
if( result == kIOReturnSuccess )
{
fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 );
result = fLockCmd->submit();
}
if( result == kIOReturnSuccess )
{
done = fLockCmd->locked( &oldVal );
}
}
if( result == kIOFireWireChannelNotAvailable )
{
DebugLog( "IOFWIsochChannel<%p>::reallocBandwidth() - failed to reallocate channel = %ld\n", this, fChannel );
fChannel = 64;
}
else
{
InfoLog( "IOFWIsochChannel<%p>::reallocBandwidth() - reallocated channel = %ld\n", this, fChannel );
}
}
fGeneration = generation;
DebugLogCond( result, "IOFWIsochChannel<%p>::reallocBandwidth() - exited with result = 0x%x\n", this, result );
IOLockUnlock( fLock );
if( result == kIOReturnNoSpace || result == kIOFireWireChannelNotAvailable )
{
stop();
releaseChannel();
if ( fStopProc )
{
(*fStopProc)( fStopRefCon, this, kIOFireWireChannelNotAvailable );
}
}
}
IOReturn IOFWIsochChannel::releaseChannel()
{
DebugLog("IOFWIsochChannel<%p>::releaseChannel()\n", this ) ;
OSIterator *listenIterator;
IOFWIsochPort *listen;
if( fTalker )
{
fTalker->releasePort();
}
listenIterator = OSCollectionIterator::withCollection(fListeners);
if( listenIterator )
{
while( (listen = (IOFWIsochPort *)listenIterator->getNextObject()) )
{
listen->releasePort();
}
listenIterator->release();
}
return releaseChannelComplete();
}
IOReturn IOFWIsochChannel::releaseChannelComplete()
{
IOReturn result = kIOReturnSuccess;
FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - entered, fDoIRM = %d\n", fDoIRM ));
if( fDoIRM )
{
FWAddress addr( kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable );
UInt32 generation = 0;
IOLockLock( fLock );
if( result == kIOReturnSuccess )
{
fControl->removeAllocatedChannel( this );
}
if( result == kIOReturnSuccess )
{
UInt16 irm;
fControl->getIRMNodeID( generation, irm );
addr.nodeID = irm;
FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - generation = %d allocated generation = %d\n", generation, fGeneration ));
if( generation != fGeneration )
{
result = kIOFireWireBusReset;
fBandwidth = 0;
fChannel = 64;
}
}
if( fBandwidth != 0 )
{
UInt32 oldVal = 0;
if( result == kIOReturnSuccess )
{
fReadCmd->reinit( generation, addr, &oldVal, 1 );
result = fReadCmd->submit();
}
bool done = false;
while( (result == kIOReturnSuccess) && !done )
{
UInt32 old_bandwidth = OSSwapBigToHostInt32( oldVal );
UInt32 newVal = OSSwapHostToBigInt32( old_bandwidth + fBandwidth );
fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 );
result = fLockCmd->submit();
if( result == kIOReturnSuccess )
{
done = fLockCmd->locked(&oldVal);
}
}
fBandwidth = 0;
FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - released bandwidth\n" ));
if( result != kIOFireWireBusReset )
{
result = kIOReturnSuccess;
}
}
if( fChannel != 64 )
{
UInt32 mask = 0;
UInt32 oldVal = 0;
if( result == kIOReturnSuccess )
{
if( fChannel <= 31 )
{
addr.addressLo = kCSRChannelsAvailable31_0;
mask = 1 << (31-fChannel);
}
else
{
addr.addressLo = kCSRChannelsAvailable63_32;
mask = 1 << (63-fChannel);
}
fReadCmd->reinit( generation, addr, &oldVal, 1 );
result = fReadCmd->submit();
}
bool done = false;
while( (result == kIOReturnSuccess) && !done )
{
UInt32 old_channels_avail = OSSwapBigToHostInt32( oldVal );
UInt32 newVal = OSSwapHostToBigInt32( old_channels_avail | mask );
fLockCmd->reinit( generation, addr, &oldVal, &newVal, 1 );
result = fLockCmd->submit();
if( result == kIOReturnSuccess )
{
done = fLockCmd->locked( &oldVal );
}
}
FWKLOG(( "IOFWIsochChannel::releaseChannelComplete - released channel\n" ));
fChannel = 64;
}
fBandwidth = 0;
fChannel = 64;
fGeneration = generation;
IOLockUnlock( fLock );
}
return kIOReturnSuccess;
}
IOReturn IOFWIsochChannel::updateBandwidth( bool )
{
DebugLog("driver calling deprecated IOFWIsochChannel::updateBandwidth on channel %p\n", this ) ;
return kIOReturnUnsupported;
}