/* * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. * * HISTORY * */ #include //////////////////////////////////////////////////////////////////////////////// // // FWDCLReceivePacketStart // // This routine runs a DCL receive packet start command. // static void DCLReceivePacketStart( DCLCommand** ppCurrentDCLCommand, UInt32 packetHeader, UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket) { DCLTransferPacket* pDCLTransferPacket; UInt8 * transferBuffer; UInt8 * packetBuffer; SInt32 transferSize, packetSize; // Recast DCL command. pDCLTransferPacket = (DCLTransferPacket*) *ppCurrentDCLCommand; // Get some parameters. transferBuffer = (UInt8 *)pDCLTransferPacket->buffer; transferSize = pDCLTransferPacket->size - sizeof (UInt32); packetSize = *pPacketSize; if (transferSize > packetSize) transferSize = packetSize; packetBuffer = *pPacketBuffer; // Transfer the packet data. *((UInt32 *) transferBuffer) = packetHeader; transferBuffer += sizeof (UInt32); if (transferSize > 0) { bcopy (packetBuffer, transferBuffer, transferSize); packetSize -= transferSize; packetBuffer += transferSize; } // Check if we need another packet. *pGetNextPacket = true; if (pDCLTransferPacket->pNextDCLCommand != NULL) { if ((pDCLTransferPacket->pNextDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLReceivePacketOp) { *pGetNextPacket = false; } } // Update parameters. *ppCurrentDCLCommand = pDCLTransferPacket->pNextDCLCommand; *pPacketBuffer = packetBuffer; *pPacketSize = packetSize; } //////////////////////////////////////////////////////////////////////////////// // // DCLReceivePacket // // This routine runs a DCL receive packet command. // static void DCLReceivePacket( DCLCommand** ppCurrentDCLCommand, UInt32 packetHeader, UInt8 * *pPacketBuffer, UInt32 *pPacketSize, bool *pGetNextPacket) { DCLTransferPacket* pDCLTransferPacket; UInt8 * transferBuffer; UInt8 * packetBuffer; UInt32 transferSize, packetSize; // Recast DCL command. pDCLTransferPacket = (DCLTransferPacket*) *ppCurrentDCLCommand; // Get some parameters. transferBuffer = (UInt8 *)pDCLTransferPacket->buffer; transferSize = pDCLTransferPacket->size; packetSize = *pPacketSize; if (transferSize > packetSize) transferSize = packetSize; packetBuffer = *pPacketBuffer; // Transfer the packet data. if (transferSize > 0) { bcopy (packetBuffer, transferBuffer, transferSize); packetSize -= transferSize; packetBuffer += transferSize; } // Check if we need another packet. *pGetNextPacket = true; if (pDCLTransferPacket->pNextDCLCommand != NULL) { if ((pDCLTransferPacket->pNextDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLReceivePacketOp) { *pGetNextPacket = false; } } // Update parameters. *ppCurrentDCLCommand = pDCLTransferPacket->pNextDCLCommand; *pPacketBuffer = packetBuffer; *pPacketSize = packetSize; } //////////////////////////////////////////////////////////////////////////////// // // FWDCLReceiveBuffer // // This routine runs a DCL receive buffer command. //zzz should we include packet header? //zzz should we clip off end of packet when buffer is filled? // static void DCLReceiveBuffer( DCLCommand** ppCurrentDCLCommand, UInt32 packetHeader, UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket ) { DCLTransferBuffer* pDCLTransferBuffer; UInt8 * buffer; UInt32 bufferOffset, bufferSize; UInt32 bufferSizeLeft; UInt8 * packetBuffer; UInt32 packetSize; UInt32 transferSize; // Recast current DCL command. pDCLTransferBuffer = (DCLTransferBuffer*) *ppCurrentDCLCommand; // Get some parameters. buffer = (UInt8 *)pDCLTransferBuffer->buffer; bufferOffset = pDCLTransferBuffer->bufferOffset; bufferSize = pDCLTransferBuffer->size; packetBuffer = *pPacketBuffer; packetSize = *pPacketSize; // Compute size of transfer. bufferSizeLeft = bufferSize - bufferOffset; if (bufferSizeLeft > packetSize) transferSize = packetSize; else transferSize = bufferSizeLeft; // Transfer the packet data. if (transferSize > 0) { bcopy (packetBuffer, buffer + bufferOffset, transferSize); packetBuffer += transferSize; packetSize -= transferSize; bufferOffset += transferSize; } // Check if we're done with this DCL or need another packet. if (bufferOffset == bufferSize) { *ppCurrentDCLCommand = pDCLTransferBuffer->pNextDCLCommand; *pGetNextPacket = false; } else { *pGetNextPacket = true; } // Update parameters. pDCLTransferBuffer->bufferOffset = bufferOffset; *pPacketBuffer = packetBuffer; *pPacketSize = packetSize; } //////////////////////////////////////////////////////////////////////////////// // // DCLSendPacket // // This routine runs a DCL send packet command. // static void DCLSendPacket( DCLCommand** ppCurrentDCLCommand, UInt8 * *pPacketBuffer, UInt32 *pPacketSize, bool *pGetNextPacket) { DCLTransferPacket* pDCLTransferPacket; UInt8 * transferBuffer; UInt8 * packetBuffer; UInt32 transferSize, packetSize; // Recast DCL command. pDCLTransferPacket = (DCLTransferPacket*) *ppCurrentDCLCommand; // Get some parameters. transferBuffer = (UInt8 *)pDCLTransferPacket->buffer; transferSize = pDCLTransferPacket->size; packetSize = *pPacketSize; packetBuffer = *pPacketBuffer + packetSize; // Transfer the packet data. bcopy (transferBuffer, packetBuffer, transferSize); packetSize += transferSize; // Check if we need another packet. *pGetNextPacket = true; if (pDCLTransferPacket->pNextDCLCommand != NULL) { if ((pDCLTransferPacket->pNextDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLSendPacketOp) { *pGetNextPacket = false; } } // Update parameters. *ppCurrentDCLCommand = pDCLTransferPacket->pNextDCLCommand; *pPacketSize = packetSize; } //////////////////////////////////////////////////////////////////////////////// // // DCLSendBuffer // // This routine runs a DCL send buffer command. //zzz should we clip off end of packet when buffer is emptied? // static void DCLSendBuffer( DCLCommand** ppCurrentDCLCommand, UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket) { DCLTransferBuffer* pDCLTransferBuffer; UInt8 * buffer; UInt32 bufferOffset, bufferSize; UInt32 bufferSizeLeft; UInt8 * packetBuffer; UInt32 packetSize; UInt32 transferPacketSize; UInt32 transferSize; // Recast current DCL command. pDCLTransferBuffer = (DCLTransferBuffer*) *ppCurrentDCLCommand; // Get some parameters. buffer = (UInt8 *)pDCLTransferBuffer->buffer; bufferOffset = pDCLTransferBuffer->bufferOffset; bufferSize = pDCLTransferBuffer->size; packetSize = *pPacketSize; packetBuffer = *pPacketBuffer + packetSize; transferPacketSize = pDCLTransferBuffer->packetSize; // Compute size of transfer. bufferSizeLeft = bufferSize - bufferOffset; if (bufferSizeLeft > transferPacketSize) transferSize = transferPacketSize; else transferSize = bufferSizeLeft; // Transfer the packet data. if (transferSize > 0) { bcopy (buffer + bufferOffset, packetBuffer, transferSize); packetSize += transferSize; bufferOffset += transferSize; } // Check if we're done with this DCL or need another packet. //zzz is this the best way to do this? //zzz what if the next transfer command is a transfer packet command? if (bufferOffset == bufferSize) { *ppCurrentDCLCommand = pDCLTransferBuffer->pNextDCLCommand; *pGetNextPacket = false; } else { *pGetNextPacket = true; } // Update parameters. pDCLTransferBuffer->bufferOffset = bufferOffset; *pPacketSize = packetSize; } //////////////////////////////////////////////////////////////////////////////// // // FWRunTranslatedDCLEngine // // This routine runs the current DCL command using the given packet. It will // update the current DCL command, packet buffer pointer, packet size, and will // set get next packet to true if it needs another packet. //zzz maybe a vector table would be nice //zzz implement rest of DCL commands. // static void RunListeningDCLEngine( DCLCommand** ppCurrentDCLCommand, UInt32 packetHeader, UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket) { DCLCommand* pCurrentDCLCommand; DCLCallProc* pDCLCallProc; DCLJump* pDCLJump; // Run the current DCL command. pCurrentDCLCommand = *ppCurrentDCLCommand; switch (pCurrentDCLCommand->opcode & ~kFWDCLOpFlagMask) { case kDCLReceivePacketStartOp : DCLReceivePacketStart ( &pCurrentDCLCommand, packetHeader, pPacketBuffer, pPacketSize, pGetNextPacket); break; case kDCLReceivePacketOp : DCLReceivePacket ( &pCurrentDCLCommand, packetHeader, pPacketBuffer, pPacketSize, pGetNextPacket); break; case kDCLReceiveBufferOp : DCLReceiveBuffer ( &pCurrentDCLCommand, packetHeader, pPacketBuffer, pPacketSize, pGetNextPacket); break; case kDCLCallProcOp : pDCLCallProc = (DCLCallProc*) pCurrentDCLCommand; // Call the handler if there is one. if (pDCLCallProc->proc != NULL) (*(pDCLCallProc->proc)) ((DCLCommand*) pDCLCallProc); pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; *pGetNextPacket = false; break; case kDCLJumpOp : pDCLJump = (DCLJump*) pCurrentDCLCommand; pCurrentDCLCommand = (DCLCommand*) pDCLJump->pJumpDCLLabel; *pGetNextPacket = false; break; default : pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; *pGetNextPacket = false; break; } // Update current DCL command. *ppCurrentDCLCommand = pCurrentDCLCommand; } //////////////////////////////////////////////////////////////////////////////// // // FWRunTranslatedTalkingDCLEngine // // This routine runs the current DCL command using the given packet. It will // update the current DCL command, packet buffer pointer, packet size, and will // set get next packet to true if it needs another packet. //zzz maybe a vector table would be nice // static void RunTalkingDCLEngine( UInt32* packetHeader, DCLCommand** ppCurrentDCLCommand, UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket) { DCLCommand* pCurrentDCLCommand; DCLCallProc* pDCLCallProc; DCLJump* pDCLJump; DCLSetTagSyncBits* pDCLSetTagSyncBits; // Run the current DCL command. pCurrentDCLCommand = *ppCurrentDCLCommand; switch (pCurrentDCLCommand->opcode & ~kFWDCLOpFlagMask) { case kDCLSendPacketStartOp : case kDCLSendPacketOp : DCLSendPacket ( &pCurrentDCLCommand, pPacketBuffer, pPacketSize, pGetNextPacket); break; case kDCLSendBufferOp : DCLSendBuffer ( &pCurrentDCLCommand, pPacketBuffer, pPacketSize, pGetNextPacket); break; case kDCLCallProcOp : pDCLCallProc = (DCLCallProc*) pCurrentDCLCommand; // Call the handler if there is one. if (pDCLCallProc->proc != NULL) (*(pDCLCallProc->proc)) ((DCLCommand*) pDCLCallProc); pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; *pGetNextPacket = false; break; case kDCLJumpOp : pDCLJump = (DCLJump*) pCurrentDCLCommand; pCurrentDCLCommand = (DCLCommand*) pDCLJump->pJumpDCLLabel; *pGetNextPacket = false; break; case kDCLLabelOp : pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; *pGetNextPacket = false; break; case kDCLSetTagSyncBitsOp : pDCLSetTagSyncBits = (DCLSetTagSyncBits*) pCurrentDCLCommand; *packetHeader &= ~(kFWIsochTag | kFWIsochSy); *packetHeader |= (pDCLSetTagSyncBits->tagBits << kFWIsochTagPhase); *packetHeader |= (pDCLSetTagSyncBits->syncBits << kFWIsochSyPhase); pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; *pGetNextPacket = false; break; default : pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; *pGetNextPacket = false; break; } // Update current DCL command. *ppCurrentDCLCommand = pCurrentDCLCommand; } OSDefineMetaClass( IODCLTranslator, IODCLProgram ) OSDefineAbstractStructors(IODCLTranslator, IODCLProgram) bool IODCLTranslator::init(DCLCommand* toInterpret) { if(!IODCLProgram::init()) return false; // Allocate buffers etc. for programs fToInterpret = toInterpret; return true; } IOReturn IODCLTranslator::notify(UInt32 notificationType, DCLCommand** dclCommandList, UInt32 numDCLCommands) { return kIOReturnSuccess; // Nothing to do, we're interpreting anyway } IOReturn IODCLTranslator::allocateHW(IOFWSpeed speed, UInt32 chan) { if(!fHWProgram) return kIOReturnInternalError; return fHWProgram->allocateHW(speed, chan); } IOReturn IODCLTranslator::releaseHW() { if(!fHWProgram) return kIOReturnInternalError; return fHWProgram->releaseHW(); } void IODCLTranslator::stop() { fHWProgram->stop(); } DCLCommand* IODCLTranslator::getTranslatorOpcodes() { return (DCLCommand*)&fStartLabel; } void IODCLTranslator::setHWProgram(IODCLProgram *program) { fHWProgram = program; } void IODCLTranslator::ListeningDCLPingPongProc(DCLCommand* pDCLCommand) { IODCLTranslator * me; DCLCommand* pCurrentDCLCommand; DCLTransferPacket* pDCLTransferPacket; UInt8 * packetBuffer; UInt32 packetHeader; UInt32 packetSize; UInt32 packetNum; bool getNextPacket; me = (IODCLTranslator *)((DCLCallProc*)pDCLCommand)->procData; pCurrentDCLCommand = me->fCurrentDCLCommand; pDCLTransferPacket = &me->fTransfers[me->fPingCount * kNumPacketsPerPingPong]; // Run all packets through DCL program. for (packetNum = 0; ((packetNum < kNumPacketsPerPingPong) && (pCurrentDCLCommand != NULL)); packetNum++) { // Compute packet size. packetBuffer = (UInt8 *)pDCLTransferPacket->buffer; packetHeader = *((UInt32 *) packetBuffer); packetBuffer += sizeof (UInt32); packetSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase; // Run this packet through DCL program. getNextPacket = false; while ((!getNextPacket) && (pCurrentDCLCommand != NULL)) { RunListeningDCLEngine ( &pCurrentDCLCommand, packetHeader, &packetBuffer, &packetSize, &getNextPacket); } // Update for next packet. pDCLTransferPacket++; } // Update DCL translation data. me->fCurrentDCLCommand = pCurrentDCLCommand; me->fPingCount++; if(me->fPingCount > kNumPingPongs) me->fPingCount = 0; } void IODCLTranslator::TalkingDCLPingPongProc(DCLCommand* pDCLCommand) { IODCLTranslator * me; DCLCommand* pCurrentDCLCommand; DCLTransferPacket* pDCLTransferPacket; UInt8 * packetBuffer; UInt32 packetHeader; UInt32 packetSize; UInt32 packetNum; bool getNextPacket; me = (IODCLTranslator *)((DCLCallProc*)pDCLCommand)->procData; pCurrentDCLCommand = me->fCurrentDCLCommand; pDCLTransferPacket = &me->fTransfers[me->fPingCount * kNumPacketsPerPingPong]; // Run all packets through DCL program. for (packetNum = 0; ((packetNum < kNumPacketsPerPingPong) && (pCurrentDCLCommand != NULL)); packetNum++) { // Compute packet size. packetBuffer = (UInt8 *)pDCLTransferPacket->buffer; packetSize = sizeof (UInt32); // Run this packet through DCL program. getNextPacket = false; while ((!getNextPacket) && (pCurrentDCLCommand != NULL)) { RunTalkingDCLEngine (&(me->fPacketHeader), &pCurrentDCLCommand, &packetBuffer, &packetSize, &getNextPacket); } // Update packet header. packetSize -= 4;//zzz not the best way packetHeader = (packetSize << kFWIsochDataLengthPhase) | (me->fPacketHeader & ~(kFWIsochDataLength)); *((UInt32 *) packetBuffer) = packetHeader; // Update send packet DCL. packetSize += 4;//zzz really, not the best way // Change the transfer packet command. pDCLTransferPacket->size = packetSize; // Send notification to DCL compiler. me->fHWProgram->notify(kFWDCLModifyNotification, (DCLCommand**) pDCLTransferPacket, 1); // Update for next packet. pDCLTransferPacket++; } // Update DCL translation data. me->fCurrentDCLCommand = pCurrentDCLCommand; me->fPingCount++; if(me->fPingCount > kNumPingPongs) me->fPingCount = 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ OSDefineMetaClassAndStructors(IODCLTranslateTalk, IODCLTranslator) IOReturn IODCLTranslateTalk::compile(IOFWSpeed speed, UInt32 chan) { int pingPongNum; int packetNum; DCLTransferPacket* pDCLTransferPacket = &fTransfers[0]; DCLCallProc* pDCLPingPongProc = &fCalls[0]; UInt8 *pingPongBuffer = fBuffer; if(!fHWProgram) return kIOReturnInternalError; fPacketHeader = chan << kFWIsochChanNumPhase; // Create label for start of loop. fStartLabel.pNextDCLCommand = (DCLCommand*)pDCLTransferPacket; fStartLabel.opcode = kDCLLabelOp; // Create kNumPingPongs ping pong buffer lists of kNumPacketsPerPingPong // packets each. for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++) { // Create transfer DCL for each packet. for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++) { // Receive one packet up to kMaxIsochPacketSize bytes. pDCLTransferPacket->pNextDCLCommand = (DCLCommand*)(pDCLTransferPacket+1); pDCLTransferPacket->opcode = kDCLSendPacketWithHeaderStartOp | kFWDCLOpDynamicFlag; pDCLTransferPacket->buffer = pingPongBuffer; pDCLTransferPacket->size = kMaxIsochPacketSize; pingPongBuffer += kMaxIsochPacketSize; pDCLTransferPacket++; } // Correct next opcode for last transfer op. (pDCLTransferPacket-1)->pNextDCLCommand = (DCLCommand*)pDCLPingPongProc; // Call the ping pong proc. pDCLPingPongProc->pNextDCLCommand = (DCLCommand*) pDCLTransferPacket; pDCLPingPongProc->opcode = kDCLCallProcOp; pDCLPingPongProc->proc = TalkingDCLPingPongProc; pDCLPingPongProc->procData = (UInt32) this; pDCLPingPongProc++; } // Correct next opcode for last call op. (pDCLPingPongProc-1)->pNextDCLCommand = (DCLCommand*)&fJumpToStart; // Loop to start of ping pong. fJumpToStart.pNextDCLCommand = NULL; fJumpToStart.opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; fJumpToStart.pJumpDCLLabel = &fStartLabel; return fHWProgram->compile(speed, chan); } IOReturn IODCLTranslateTalk::start() { int i; fPingCount = 0; // Prime all buffers for(i=0; istart(); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ OSDefineMetaClassAndStructors(IODCLTranslateListen, IODCLTranslator) IOReturn IODCLTranslateListen::compile(IOFWSpeed speed, UInt32 chan) { int pingPongNum; int packetNum; DCLTransferPacket* pDCLTransferPacket = &fTransfers[0]; DCLCallProc* pDCLPingPongProc = &fCalls[0]; UInt8 *pingPongBuffer = fBuffer; if(!fHWProgram) return kIOReturnInternalError; fPacketHeader = chan << kFWIsochChanNumPhase; // Create label for start of loop. fStartLabel.pNextDCLCommand = (DCLCommand*)pDCLTransferPacket; fStartLabel.opcode = kDCLLabelOp; // Create kNumPingPongs ping pong buffer lists of kNumPacketsPerPingPong // packets each. for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++) { // Create transfer DCL for each packet. for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++) { // Receive one packet up to kMaxIsochPacketSize bytes. pDCLTransferPacket->pNextDCLCommand = (DCLCommand*)(pDCLTransferPacket+1); pDCLTransferPacket->opcode = kDCLReceivePacketStartOp | kFWDCLOpDynamicFlag; pDCLTransferPacket->buffer = pingPongBuffer; pDCLTransferPacket->size = kMaxIsochPacketSize; pingPongBuffer += kMaxIsochPacketSize; pDCLTransferPacket++; } // Correct next opcode for last transfer op. (pDCLTransferPacket-1)->pNextDCLCommand = (DCLCommand*)pDCLPingPongProc; // Call the ping pong proc. pDCLPingPongProc->pNextDCLCommand = (DCLCommand*) pDCLTransferPacket; pDCLPingPongProc->opcode = kDCLCallProcOp; pDCLPingPongProc->proc = ListeningDCLPingPongProc; pDCLPingPongProc->procData = (UInt32) this; pDCLPingPongProc++; } // Correct next opcode for last call op. (pDCLPingPongProc-1)->pNextDCLCommand = (DCLCommand*)&fJumpToStart; // Loop to start of ping pong. fJumpToStart.pNextDCLCommand = NULL; fJumpToStart.opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; fJumpToStart.pJumpDCLLabel = &fStartLabel; return fHWProgram->compile(speed, chan); } IOReturn IODCLTranslateListen::start() { fPingCount = 0; return fHWProgram->start(); }