IOFWUserClientPsdoAddrSpace.cpp [plain text]
#ifndef __IOFWUserClientPseuAddrSpace_H__
#define __IOFWUserClientPseuAddrSpace_H__
#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOTypes.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireLink.h>
#include "IOFWUserClientPsdoAddrSpace.h"
class IOFireWireUserClient ;
IOFWPacketHeader_t::IOFWPacketHeader_t()
{
CommonHeader.type = IOFWPacketHeader::kFree ;
CommonHeader.next = this ;
IOFWPacketHeaderGetSize(this) = 0 ;
IOFWPacketHeaderGetOffset(this) = 0 ;
}
inline IOByteCount& IOFWPacketHeaderGetSize(IOFWPacketHeader_t* hdr)
{
return hdr->CommonHeader.args[1] ;
}
inline IOByteCount& IOFWPacketHeaderGetOffset(IOFWPacketHeader_t* hdr)
{
return hdr->CommonHeader.args[2] ;
}
inline void InitIncomingPacketHeader(
IOFWPacketHeader_t* header,
IOFWPacketHeader_t* next,
const IOByteCount len,
const IOByteCount offset,
OSAsyncReference* ref,
void* refCon,
UInt16 nodeID,
const IOFWSpeed& speed,
const FWAddress& addr,
const Boolean lockWrite)
{
header->CommonHeader.type = IOFWPacketHeader::kIncomingPacket ;
header->CommonHeader.next = next ;
IOFWPacketHeaderGetSize(header) = len ;
IOFWPacketHeaderGetOffset(header) = offset ;
header->CommonHeader.whichAsyncRef = ref ;
header->CommonHeader.argCount = 8;
header->IncomingPacket.commandID = (UInt32) header ;
header->IncomingPacket.nodeID = nodeID ;
header->IncomingPacket.speed = speed ;
header->IncomingPacket.addrHi = addr.addressHi;
header->IncomingPacket.addrLo = addr.addressLo;
header->IncomingPacket.lockWrite = lockWrite ;
}
inline void InitSkippedPacketHeader(
IOFWPacketHeader* header,
IOFWPacketHeader* next,
const IOByteCount offset,
OSAsyncReference* ref,
void* refCon)
{
header->CommonHeader.type = IOFWPacketHeader::kSkippedPacket ;
header->CommonHeader.next = next ;
IOFWPacketHeaderGetSize(header) = 0;
IOFWPacketHeaderGetOffset(header) = offset ;
header->CommonHeader.whichAsyncRef = ref ;
header->CommonHeader.argCount = 2;
header->SkippedPacket.commandID = (UInt32) header ;
header->SkippedPacket.skippedPacketCount= 1;
}
inline void InitReadPacketHeader(
IOFWPacketHeader* header,
IOFWPacketHeader* next,
IOByteCount len,
IOByteCount offset,
OSAsyncReference* ref,
IOFWRequestRefCon reqrefcon,
UInt16 nodeID,
IOFWSpeed& speed,
FWAddress addr,
UInt32 generation)
{
header->CommonHeader.type = IOFWPacketHeader::kReadPacket ;
header->CommonHeader.next = next ;
IOFWPacketHeaderGetSize(header) = len ;
IOFWPacketHeaderGetOffset(header) = offset ;
header->CommonHeader.whichAsyncRef = ref ;
header->CommonHeader.argCount = 7 ;
header->ReadPacket.commandID = (UInt32) header ;
header->ReadPacket.nodeID = nodeID ;
header->ReadPacket.speed = speed ;
header->ReadPacket.addrHi = addr.addressHi ;
header->ReadPacket.addrLo = addr.addressLo ;
header->ReadPacket.reqrefcon = reqrefcon ;
header->ReadPacket.generation = generation ;
}
inline Boolean IsSkippedPacketHeader(
IOFWPacketHeader* header)
{
return header->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ;
}
inline Boolean IsFreePacketHeader(
IOFWPacketHeader* header)
{
return header->CommonHeader.type == IOFWPacketHeader::kFree ;
}
inline Boolean IsReadPacketHeader(
IOFWPacketHeader* header)
{
return header->CommonHeader.type == IOFWPacketHeader::kReadPacket ;
}
OSDefineMetaClassAndStructors(IOFWUserClientPseudoAddrSpace, IOFWPseudoAddressSpace) ;
bool
IOFWUserClientPseudoAddrSpace::initAll(
IOFireWireUserClient* inUserClient,
FWAddrSpaceCreateParams* inParams)
{
Boolean status = true ;
if (!IOFWPseudoAddressSpace::initAll(inUserClient->getOwner()->getBus(), & fAddress,
inParams->size, NULL, NULL, this))
return false ;
fUserRefCon = inParams->refCon ;
fFlags = inParams->flags ;
fWaitingForUserCompletion = false ;
fUserClient = inUserClient ;
fUserClient->retain() ;
if ( !inParams->queueBuffer && !( (fFlags & kFWAddressSpaceAutoWriteReply) && (fFlags & kFWAddressSpaceAutoReadReply) ) )
{
IOFireWireUserClientLog_(("IOFWUserClientPseudoAddrSpace::initAll: address space without queue buffer must have both auto-write and auto-read set\n")) ;
status = false ;
}
if ( status )
{
if ( inParams->queueBuffer )
{
fPacketQueueBuffer = IOMemoryDescriptor::withAddress( (vm_address_t) inParams->queueBuffer,
(IOByteCount) inParams->queueSize,
kIODirectionOutIn,
fUserClient->getOwningTask() ) ;
if ( !fPacketQueueBuffer )
status = false ;
if ( status )
{
status = ( kIOReturnSuccess == fPacketQueueBuffer->prepare() ) ;
fPacketQueuePrepared = status ;
}
if ( status )
fBufferAvailable = fPacketQueueBuffer->getLength() ;
}
}
if ( status )
{
fLastReadHeader = new IOFWPacketHeader ;
fLastWrittenHeader = fLastReadHeader ;
fLock = IOLockAlloc() ;
if ( !fLock )
status = false ;
}
if ( status )
if ( NULL != inParams->backingStore )
{
fDesc = IOMemoryDescriptor::withAddress( (vm_address_t) inParams->backingStore,
(IOByteCount) inParams->size,
kIODirectionOutIn,
inUserClient->getOwningTask()) ;
if (!fDesc)
status = false ;
if ( status )
status = ( kIOReturnSuccess == fDesc->prepare() ) ;
fBackingStorePrepared = status ;
}
if (status)
{
if (!(inParams->flags & kFWAddressSpaceNoWriteAccess))
{
if (inParams->flags & kFWAddressSpaceAutoWriteReply)
{
if (inParams->backingStore)
fWriter = & IOFWUserClientPseudoAddrSpace::simpleWriter ;
else
{ IOFireWireUserClientLog_(("IOFireWireUserClient::allocateAddressSpace(): can't create auto-write address space w/o backing store!\n")) ;
}
}
else
fWriter = & IOFWUserClientPseudoAddrSpace::pseudoAddrSpaceWriter ;
}
if (!(inParams->flags & kFWAddressSpaceNoReadAccess))
{
if (inParams->flags & kFWAddressSpaceAutoReadReply)
{
if (inParams->backingStore)
fReader = & IOFWUserClientPseudoAddrSpace::simpleReader ;
else
{ IOFireWireUserClientLog_(("IOFireWireUserClient::allocateAddressSpace(): can't create auto-read address space w/o backing store!\n")) ;
}
}
else
fReader = & IOFWUserClientPseudoAddrSpace::pseudoAddrSpaceReader ;
}
}
return status ;
}
void
IOFWUserClientPseudoAddrSpace::free()
{
if ( fPacketQueuePrepared )
fPacketQueueBuffer->complete() ;
if ( fPacketQueueBuffer )
fPacketQueueBuffer->release() ;
if ( fBackingStorePrepared )
fDesc->complete() ;
if ( fLastWrittenHeader )
delete fLastWrittenHeader ;
if ( fUserClient )
fUserClient->release() ;
IOFWPseudoAddressSpace::free() ;
}
void
IOFWUserClientPseudoAddrSpace::deactivate()
{
fBufferAvailable = 0 ; fLastReadHeader = NULL ;
IOFWPacketHeader* firstHeader = fLastWrittenHeader ;
IOFWPacketHeader* tempHeader ;
if (fLastWrittenHeader)
{
while (fLastWrittenHeader->CommonHeader.next != firstHeader)
{
tempHeader = fLastWrittenHeader->CommonHeader.next ;
delete fLastWrittenHeader ;
fLastWrittenHeader = tempHeader ;
}
}
if ( fBackingStorePrepared )
{
fDesc->complete() ;
fBackingStorePrepared = false ;
}
IOFWPseudoAddressSpace::deactivate() ;
}
UInt32
IOFWUserClientPseudoAddrSpace::pseudoAddrSpaceReader(
void* refCon,
UInt16 nodeID,
IOFWSpeed& speed,
FWAddress addr,
UInt32 len,
IOMemoryDescriptor** buf,
IOByteCount* outOffset,
IOFWRequestRefCon reqrefcon)
{
IOFWUserClientPseudoAddrSpace* me = (IOFWUserClientPseudoAddrSpace*)refCon ;
if ( 0 == me->fReadAsyncNotificationRef[0] )
return kFWResponseTypeError ;
IOLockLock( me->fLock ) ;
IOFWPacketHeader* currentHeader = me->fLastWrittenHeader ;
if ( !IsFreePacketHeader(currentHeader) )
{
if ( !IsFreePacketHeader(currentHeader->CommonHeader.next) )
{
IOFWPacketHeader* newHeader = new IOFWPacketHeader ;
newHeader->CommonHeader.next = currentHeader->CommonHeader.next ;
currentHeader->CommonHeader.next = newHeader ;
}
}
currentHeader = currentHeader->CommonHeader.next ;
UInt32 generation = me->fUserClient->getOwner()->getController()->getGeneration() ;
InitReadPacketHeader(
currentHeader,
currentHeader->CommonHeader.next,
len,
addr.addressLo - me->fAddress.addressLo,
& (me->fReadAsyncNotificationRef),
reqrefcon,
nodeID,
speed,
addr,
generation) ;
me->fLastWrittenHeader = currentHeader ;
IOLockUnlock( me->fLock ) ;
me->sendPacketNotification(currentHeader) ;
return kFWResponsePending ;
}
UInt32
IOFWUserClientPseudoAddrSpace::pseudoAddrSpaceWriter(
void* refCon,
UInt16 nodeID,
IOFWSpeed& speed,
FWAddress addr,
UInt32 len,
const void* buf,
IOFWRequestRefCon reqrefcon)
{
static UInt32 packetsWritten = 0 ;
packetsWritten++ ;
IOFWUserClientPseudoAddrSpace* me = (IOFWUserClientPseudoAddrSpace*)refCon ;
IOByteCount destOffset = 0 ;
bool wontFit = false ;
IOLockLock(me->fLock) ;
IOByteCount spaceAtEnd = me->fPacketQueueBuffer->getLength() ;
IOFWPacketHeader* currentHeader = me->fLastWrittenHeader ;
spaceAtEnd -= (IOFWPacketHeaderGetOffset(currentHeader)
+ IOFWPacketHeaderGetSize(currentHeader)) ;
if (me->fBufferAvailable < len)
wontFit = true ;
else
{
if (len <= spaceAtEnd)
destOffset = IOFWPacketHeaderGetOffset(currentHeader) + IOFWPacketHeaderGetSize(currentHeader) ;
else
{
if ( (len + spaceAtEnd) <= me->fBufferAvailable )
destOffset = 0 ;
else
{
destOffset = IOFWPacketHeaderGetOffset(currentHeader) ;
wontFit = true ;
}
}
}
if (wontFit)
{
if (IsSkippedPacketHeader(currentHeader))
currentHeader->SkippedPacket.skippedPacketCount++ ;
else
{
if (!IsFreePacketHeader(currentHeader))
{
if ( !IsFreePacketHeader(currentHeader->CommonHeader.next) )
{
IOFWPacketHeader* newHeader = new IOFWPacketHeader ;
newHeader->CommonHeader.next = currentHeader->CommonHeader.next ;
currentHeader->CommonHeader.next = newHeader ;
}
currentHeader = currentHeader->CommonHeader.next ;
}
InitSkippedPacketHeader(
currentHeader,
currentHeader->CommonHeader.next,
destOffset,
& (me->fSkippedPacketAsyncNotificationRef),
(void*) currentHeader ) ;
}
}
else
{
if (!IsFreePacketHeader(currentHeader))
{
if ( !IsFreePacketHeader(currentHeader->CommonHeader.next) )
{
IOFWPacketHeader* newHeader = new IOFWPacketHeader ;
newHeader->CommonHeader.next = currentHeader->CommonHeader.next ;
currentHeader->CommonHeader.next = newHeader ;
}
}
currentHeader = currentHeader->CommonHeader.next ;
InitIncomingPacketHeader(
currentHeader,
currentHeader->CommonHeader.next,
len,
destOffset,
& (me->fPacketAsyncNotificationRef),
(void*) currentHeader, nodeID,
speed,
addr,
me->fControl->isLockRequest(reqrefcon)) ;
me->fPacketQueueBuffer->writeBytes(destOffset, buf, len) ;
if ( me->fFlags & kFWAddressSpaceAutoCopyOnWrite )
me->fDesc->writeBytes( addr.addressLo - me->fAddress.addressLo, buf, len ) ;
me->fBufferAvailable -= len ;
me->fLastWrittenHeader = currentHeader ;
}
me->sendPacketNotification(currentHeader) ;
IOLockUnlock(me->fLock) ;
return kFWResponseComplete ;
}
void
IOFWUserClientPseudoAddrSpace::setAsyncRef_Packet(
OSAsyncReference asyncRef)
{
bcopy(asyncRef, fPacketAsyncNotificationRef, sizeof(OSAsyncReference)) ;
}
void
IOFWUserClientPseudoAddrSpace::setAsyncRef_SkippedPacket(
OSAsyncReference asyncRef)
{
bcopy(asyncRef, fSkippedPacketAsyncNotificationRef, sizeof(OSAsyncReference)) ;
}
void
IOFWUserClientPseudoAddrSpace::setAsyncRef_Read(
OSAsyncReference asyncRef)
{
bcopy(asyncRef, fReadAsyncNotificationRef, sizeof(OSAsyncReference)) ;
}
void
IOFWUserClientPseudoAddrSpace::clientCommandIsComplete(
FWClientCommandID inCommandID,
IOReturn inResult)
{
IOLockLock(fLock) ;
if ( fWaitingForUserCompletion )
{
IOFWPacketHeader* oldHeader = fLastReadHeader ;
IOFWPacketHeader::QueueTag type = oldHeader->CommonHeader.type ;
fLastReadHeader = fLastReadHeader->CommonHeader.next ;
switch(type)
{
case IOFWPacketHeader::kIncomingPacket:
fBufferAvailable += oldHeader->IncomingPacket.packetSize ;
break ;
case IOFWPacketHeader::kReadPacket:
fUserClient->getOwner()->getController()->asyncReadResponse( oldHeader->ReadPacket.generation,
oldHeader->ReadPacket.nodeID,
oldHeader->ReadPacket.speed,
fDesc, oldHeader->ReadPacket.addrLo - fAddress.addressLo,
oldHeader->ReadPacket.packetSize,
oldHeader->ReadPacket.reqrefcon ) ;
break ;
default:
break ;
}
oldHeader->CommonHeader.type = IOFWPacketHeader::kFree ;
fWaitingForUserCompletion = false ;
if ( fLastReadHeader->CommonHeader.type != IOFWPacketHeader::kFree )
{
sendPacketNotification(fLastReadHeader) ;
}
}
IOLockUnlock(fLock) ;
}
void
IOFWUserClientPseudoAddrSpace::sendPacketNotification(
IOFWPacketHeader* inPacketHeader)
{
static UInt32 notificationsSent = 0 ;
if (!fWaitingForUserCompletion)
if (inPacketHeader->CommonHeader.whichAsyncRef[0] != 0)
{
IOFireWireUserClient::sendAsyncResult(*(inPacketHeader->CommonHeader.whichAsyncRef),
kIOReturnSuccess,
(void**)inPacketHeader->CommonHeader.args,
inPacketHeader->CommonHeader.argCount) ;
fWaitingForUserCompletion = true ;
}
}
#endif //__IOFWUserClientPseuAddrSpace_H__