IOFireWireIPCommand.cpp [plain text]
#define FIREWIREPRIVATE
#include <IOKit/firewire/IOFireWireController.h>
#include <IOKit/firewire/IOFireWireNub.h>
#include <IOKit/IOSyncer.h>
#include "IOFireWireIPCommand.h"
#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
extern "C"
{
extern void moveMbufWithOffset(SInt32 tempOffset, struct mbuf **srcm, vm_address_t *src, SInt32 *srcLen);
}
#pragma mark -
#pragma mark еее IOFWIPAsyncWriteCommand methods еее
OSDefineMetaClassAndStructors(IOFWIPAsyncWriteCommand, IOFWWriteCommand);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 0);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 1);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 2);
OSMetaClassDefineReservedUnused(IOFWIPAsyncWriteCommand, 3);
bool IOFWIPAsyncWriteCommand::initAll(IOFireWireNub *device, UInt32 cmdLen,FWAddress devAddress,FWDeviceCallback completion, void *refcon, bool failOnReset)
{
if(!IOFWWriteCommand::initWithController(device->getController()))
return false;
fBuffer = new IOBufferMemoryDescriptor;
if(fBuffer == NULL)
return false;
if(!fBuffer->initWithOptions(kIODirectionOutIn | kIOMemoryUnshared, cmdLen, 1))
return false;
fMem = IOMemoryDescriptor::withAddress((void *)fBuffer->getBytesNoCopy(), cmdLen,
kIODirectionOutIn);
if(!fMem) {
return false;
}
fCursorBuf = (UInt8*)getBufferFromDescriptor();
maxBufLen = cmdLen;
fMaxRetries = 3;
fCurRetries = 3;
fMemDesc = fMem;
fComplete = completion;
fSync = completion == NULL;
fRefCon = refcon;
fTimeout = 5*8*125;
if(fMem)
fSize = fMem->getLength();
fBytesTransferred = 0;
fLinkFragmentType = UNFRAGMENTED;
fDevice = device;
device->getNodeIDGeneration(fGeneration, fNodeID);
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
fSpeed = fControl->FWSpeed(fNodeID);
fFailOnReset = failOnReset;
return true;
}
void IOFWIPAsyncWriteCommand::free()
{
if(fBuffer){
fBuffer->release();
fBuffer = NULL;
}
if(fMem){
fMem->release();
fMem = NULL;
}
IOFWWriteCommand::free();
}
IOReturn IOFWIPAsyncWriteCommand::reinit(IOFireWireNub *device, UInt32 cmdLen,
FWAddress devAddress, FWDeviceCallback completion, void *refcon, bool failOnReset)
{
if(cmdLen > maxBufLen)
return kIOReturnNoResources;
fComplete = completion;
fRefCon = refcon;
if(fMem)
fSize = cmdLen;
fBytesTransferred = 0;
fDevice = device;
device->getNodeIDGeneration(fGeneration, fNodeID);
fAddressHi = devAddress.addressHi;
fAddressLo = devAddress.addressLo;
fMaxPack = 1 << device->maxPackLog(fWrite, devAddress);
fSpeed = fControl->FWSpeed(fNodeID);
fFailOnReset = failOnReset;
return kIOReturnSuccess;
}
IOReturn IOFWIPAsyncWriteCommand::createFragmentedDescriptors()
{
struct mbuf *m = fMBuf;
vm_address_t src;
SInt32 srcLen, dstLen, copylen, tempOffset;
struct mbuf *temp = NULL;
struct mbuf *srcm = NULL;
srcm = m;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
tempOffset = fOffset;
moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
dstLen = fLength;
copylen = dstLen;
for (;;)
{
if (fIndex > (MAX_ALLOWED_SEGS-2))
{
IOLog("IOFWIPCmd: Number of segs unsupported\n");
return kIOReturnNoResources;
}
if (srcLen < dstLen)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
fVirtualRange[fIndex].length = srcLen;
fIndex++;
dstLen -= srcLen;
copylen -= srcLen;
fOffset = fOffset + srcLen;
if(copylen == 0)
{
temp = srcm->m_next;
srcm = temp;
break;
}
temp = srcm->m_next; assert(temp);
srcm = temp;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
else if (srcLen > dstLen)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
fVirtualRange[fIndex].length = dstLen;
fIndex++;
src += dstLen;
srcLen -= dstLen;
copylen -= dstLen;
fOffset = fOffset + dstLen;
if(copylen == 0)
{
break;
}
}
else
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(src);
fVirtualRange[fIndex].length = srcLen;
fIndex++;
copylen -= srcLen;
if(copylen == 0)
{
fOffset = 0;
temp = srcm->m_next;
srcm = temp;
break;
}
srcm = srcm->m_next;
if (dstLen == 0)
break;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
}
return copylen;
}
IOReturn IOFWIPAsyncWriteCommand::createUnFragmentedDescriptors()
{
UInt32 offset = 0;
struct mbuf *m = fMBuf;
struct mbuf *n = 0;
UInt32 totalLength = 0;
UInt32 amtCopied = 0;
UInt32 pktLen = 0;
fIndex = 0;
if (m->m_flags & M_PKTHDR)
{
pktLen = m->m_pkthdr.len;
offset = fOffset;
}
while (m)
{
if(m->m_data != NULL)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(m->m_data + offset);
fVirtualRange[fIndex].length = m->m_len - offset;
totalLength += fVirtualRange[fIndex].length;
fIndex++;
}
offset = 0;
m = m->m_next;
if ((fIndex > MAX_ALLOWED_SEGS-3) && (m != NULL))
{
n = m->m_next;
if(n == NULL)
{
fVirtualRange[fIndex].address = (IOVirtualAddress)(m->m_data);
fVirtualRange[fIndex].length = m->m_len;
}
else
{
fTailMbuf = m;
fLength = fLength - totalLength + fHeaderSize;
fCursorBuf = (UInt8*)getBufferFromDescriptor();
amtCopied = copyToBufferDescriptors();
if(amtCopied != 0)
return kIOReturnError;
fVirtualRange[fIndex].address = (IOVirtualAddress)(fCursorBuf);
fVirtualRange[fIndex].length = fLength;
}
fIndex++;
return kIOReturnSuccess;
}
}
return kIOReturnSuccess;
}
IOReturn IOFWIPAsyncWriteCommand::copyToBufferDescriptors()
{
vm_address_t src, dst;
SInt32 srcLen, dstLen, copylen, tempOffset;
struct mbuf *temp = NULL;
struct mbuf *srcm = NULL;
UInt32 totalLen = 0;
srcm = fMBuf;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
if(fTailMbuf != NULL)
{
srcm = fTailMbuf;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
tempOffset = 0;
}
else
{
tempOffset = fOffset;
moveMbufWithOffset(tempOffset, &srcm, &src, &srcLen);
}
dstLen = fLength;
copylen = dstLen;
dst = (vm_address_t)fCursorBuf;
for (;;)
{
if (srcLen < dstLen)
{
BCOPY(src, dst, srcLen);
totalLen += srcLen;
dst += srcLen;
dstLen -= srcLen;
copylen -= srcLen;
fOffset = fOffset + srcLen;
if(copylen == 0)
{
temp = srcm->m_next;
srcm = temp;
break;
}
temp = srcm->m_next;
if(temp == NULL)
{
break;
}
assert(temp);
srcm = temp;
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
else if (srcLen > dstLen)
{
BCOPY(src, dst, dstLen);
totalLen += dstLen;
src += dstLen;
srcLen -= dstLen;
copylen -= dstLen;
fOffset = fOffset + dstLen;
if(copylen == 0)
{
break;
}
}
else
{
BCOPY(src, dst, srcLen);
totalLen += srcLen;
copylen -= srcLen;
if(copylen == 0)
{
fOffset = 0;
temp = srcm->m_next;
srcm = temp;
break;
}
srcm = srcm->m_next;
if (dstLen == 0)
{
break;
}
srcLen = srcm->m_len;
src = mtod(srcm, vm_offset_t);
}
}
return copylen;
}
IOReturn IOFWIPAsyncWriteCommand::initDescriptor(bool unfragmented, UInt32 length)
{
IOReturn status = kIOReturnSuccess;
UInt32 amtCopied = 0;
bool ret = false;
fUnfragmented = unfragmented;
fLength = length;
if(fCopy == true)
{
fCursorBuf = fCursorBuf + fHeaderSize;
amtCopied = copyToBufferDescriptors();
if(amtCopied != 0)
return kIOReturnError;
}
else
{
if(fUnfragmented)
{
status = createUnFragmentedDescriptors();
}
else
{
status = createFragmentedDescriptors();
}
if(status != kIOReturnSuccess)
{
return status;
}
ret = fMem->initWithRanges (fVirtualRange,
fIndex,
kIODirectionOutIn,
kernel_task,
true);
if(ret == false)
{
IOLog("IOFWIPCmd : initWithRanges ret %d\n", ret);
return kIOReturnError;
}
}
return status;
}
void IOFWIPAsyncWriteCommand::resetDescriptor()
{
if(fCopy == false)
{
fMem->initWithAddress ((void *)fBuffer->getBytesNoCopy(),
maxBufLen,
kIODirectionOutIn);
memset(fVirtualRange, 0, MAX_ALLOWED_SEGS);
fTailMbuf = NULL;
}
else
{
fCursorBuf = (UInt8*)getBufferFromDescriptor();
}
fLinkFragmentType = UNFRAGMENTED;
setDeviceObject(NULL);
setMbuf(NULL, false);
}
void* IOFWIPAsyncWriteCommand::getDescriptorHeader(bool unfragmented)
{
if(fCopy == false)
{
if(unfragmented)
{
fOffset = fOffset - fHeaderSize;
return fMBuf->m_data + fOffset;
}
else
{
fIndex = 0;
fVirtualRange[fIndex].address = (IOVirtualAddress)(getCursorBuf());
fVirtualRange[fIndex].length = fHeaderSize;
fIndex++;
return getCursorBuf();
}
}
return getBufferFromDescriptor();
}
void IOFWIPAsyncWriteCommand::setOffset(UInt32 offset, bool fFirst)
{
fOffset = offset;
}
void IOFWIPAsyncWriteCommand::setHeaderSize(UInt32 headerSize)
{
fHeaderSize = headerSize;
}
void IOFWIPAsyncWriteCommand::setLinkFragmentType(UInt32 fType)
{
fLinkFragmentType = fType;
}
UInt32 IOFWIPAsyncWriteCommand::getLinkFragmentType()
{
return fLinkFragmentType;
}
void IOFWIPAsyncWriteCommand::setMbuf(struct mbuf * pkt, bool doCopy)
{
fCopy = doCopy;
fMBuf = pkt;
}
struct mbuf *IOFWIPAsyncWriteCommand::getMbuf()
{
return fMBuf;
}
void IOFWIPAsyncWriteCommand::setDeviceObject(IOFireWireNub *device)
{
fDevice = device;
}
void* IOFWIPAsyncWriteCommand::getCursorBuf()
{
return fCursorBuf;
}
void* IOFWIPAsyncWriteCommand::getBufferFromDescriptor()
{
return fBuffer->getBytesNoCopy();
}
UInt32 IOFWIPAsyncWriteCommand::getMaxBufLen()
{
return maxBufLen;
}
#pragma mark -
#pragma mark еее IOFWIPAsyncStreamTxCommand methods еее
OSDefineMetaClassAndStructors(IOFWIPAsyncStreamTxCommand, IOFWAsyncStreamCommand);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 0);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 1);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 2);
OSMetaClassDefineReservedUnused(IOFWIPAsyncStreamTxCommand, 3);
bool IOFWIPAsyncStreamTxCommand::initAll(
IOFireWireController *control,
UInt32 generation,
UInt32 channel,
UInt32 sync,
UInt32 tag,
UInt32 cmdLen,
int speed,
FWAsyncStreamCallback completion,
void *refcon)
{
if(!IOFWCommand::initWithController(control))
return false;
fBuffer = new IOBufferMemoryDescriptor;
if(fBuffer == NULL)
return false;
if(!fBuffer->initWithOptions(kIODirectionOutIn | kIOMemoryUnshared, cmdLen, 1))
return false;
fMem = IOMemoryDescriptor::withAddress((void *)fBuffer->getBytesNoCopy(), cmdLen,
kIODirectionOutIn);
if(!fMem) {
return false;
}
maxBufLen = cmdLen;
fMaxRetries = 3;
fCurRetries = fMaxRetries;
fMemDesc = fMem;
fComplete = completion;
fSync = completion == NULL;
fRefCon = refcon;
fTimeout = 1000*125;
if(fMem)
fSize = fMem->getLength();
fGeneration = generation;
fChannel = channel;
fSyncBits = sync;
fTag = tag;
fSpeed = speed;
fFailOnReset = false;
return true;
}
void IOFWIPAsyncStreamTxCommand::free()
{
if(fBuffer){
fBuffer->release();
fBuffer = NULL;
}
if(fMem){
fMem->release();
fMem = NULL;
}
IOFWAsyncStreamCommand::free();
}
IOReturn IOFWIPAsyncStreamTxCommand::reinit(
UInt32 generation,
UInt32 channel,
UInt32 cmdLen,
int speed,
FWAsyncStreamCallback completion,
void *refcon)
{
if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
return fStatus;
if(cmdLen > maxBufLen)
return kIOReturnNoResources;
fComplete = completion;
fRefCon = refcon;
if(fMem)
fSize = cmdLen;
fCurRetries = fMaxRetries;
fGeneration = generation;
fChannel = channel;
fSpeed = speed;
return fStatus = kIOReturnSuccess;
}
void* IOFWIPAsyncStreamTxCommand::getBufferFromDesc()
{
return fBuffer->getBytesNoCopy();
}
UInt32 IOFWIPAsyncStreamTxCommand::getMaxBufLen()
{
return maxBufLen;
}
void IOFWIPAsyncStreamTxCommand::setMbuf(struct mbuf * pkt)
{
fMBuf = pkt;
}
struct mbuf *IOFWIPAsyncStreamTxCommand::getMbuf()
{
return fMBuf;
}