1/*
2 * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1999-2002 Apple Computer, Inc.  All rights reserved.
24 *
25 * HISTORY
26 *
27 */
28
29#include <IOKit/firewire/IOFWDCLTranslator.h>
30
31////////////////////////////////////////////////////////////////////////////////
32//
33// FWDCLReceivePacketStart
34//
35//   This routine runs a DCL receive packet start command.
36//
37
38static void	DCLReceivePacketStart(
39	DCLCommand**			ppCurrentDCLCommand,
40	UInt32					packetHeader,
41	UInt8**					pPacketBuffer,
42	UInt32*					pPacketSize,
43	bool*					pGetNextPacket)
44{
45	DCLTransferPacket*		pDCLTransferPacket;
46	UInt8 *				transferBuffer;
47	UInt8 *				packetBuffer;
48	SInt32				transferSize, packetSize;
49
50	// Recast DCL command.
51	pDCLTransferPacket = (DCLTransferPacket*) *ppCurrentDCLCommand;
52
53	// Get some parameters.
54	transferBuffer = (UInt8 *)pDCLTransferPacket->buffer;
55	transferSize = pDCLTransferPacket->size - sizeof (UInt32);
56	packetSize = *pPacketSize;
57	if (transferSize > packetSize)
58		transferSize = packetSize;
59	packetBuffer = *pPacketBuffer;
60
61	// Transfer the packet data.
62	*((UInt32 *) transferBuffer) = packetHeader;
63	transferBuffer += sizeof (UInt32);
64	if (transferSize > 0) {
65		bcopy (packetBuffer, transferBuffer, transferSize);
66		packetSize -= transferSize;
67		packetBuffer += transferSize;
68	}
69
70	// Check if we need another packet.
71	*pGetNextPacket = true;
72	if (pDCLTransferPacket->pNextDCLCommand != NULL)
73	{
74		if ((pDCLTransferPacket->pNextDCLCommand->opcode & ~kFWDCLOpFlagMask) ==
75			kDCLReceivePacketOp)
76		{
77			*pGetNextPacket = false;
78		}
79	}
80
81	// Update parameters.
82	*ppCurrentDCLCommand = pDCLTransferPacket->pNextDCLCommand;
83	*pPacketBuffer = packetBuffer;
84	*pPacketSize = packetSize;
85}
86
87
88////////////////////////////////////////////////////////////////////////////////
89//
90// DCLReceivePacket
91//
92//   This routine runs a DCL receive packet command.
93//
94
95static void	DCLReceivePacket(
96	DCLCommand**			ppCurrentDCLCommand,
97	UInt32					packetHeader,
98	UInt8 *					*pPacketBuffer,
99	UInt32					*pPacketSize,
100	bool					*pGetNextPacket)
101{
102	DCLTransferPacket*		pDCLTransferPacket;
103	UInt8 *				transferBuffer;
104	UInt8 *				packetBuffer;
105	UInt32				transferSize, packetSize;
106
107	// Recast DCL command.
108	pDCLTransferPacket = (DCLTransferPacket*) *ppCurrentDCLCommand;
109
110	// Get some parameters.
111	transferBuffer = (UInt8 *)pDCLTransferPacket->buffer;
112	transferSize = pDCLTransferPacket->size;
113	packetSize = *pPacketSize;
114	if (transferSize > packetSize)
115		transferSize = packetSize;
116	packetBuffer = *pPacketBuffer;
117
118	// Transfer the packet data.
119	if (transferSize > 0)
120	{
121		bcopy (packetBuffer, transferBuffer, transferSize);
122		packetSize -= transferSize;
123		packetBuffer += transferSize;
124	}
125
126	// Check if we need another packet.
127	*pGetNextPacket = true;
128	if (pDCLTransferPacket->pNextDCLCommand != NULL)
129	{
130		if ((pDCLTransferPacket->pNextDCLCommand->opcode & ~kFWDCLOpFlagMask) ==
131			kDCLReceivePacketOp)
132		{
133			*pGetNextPacket = false;
134		}
135	}
136
137	// Update parameters.
138	*ppCurrentDCLCommand = pDCLTransferPacket->pNextDCLCommand;
139	*pPacketBuffer = packetBuffer;
140	*pPacketSize = packetSize;
141}
142
143
144////////////////////////////////////////////////////////////////////////////////
145//
146// FWDCLReceiveBuffer
147//
148//   This routine runs a DCL receive buffer command.
149//zzz should we include packet header?
150//zzz should we clip off end of packet when buffer is filled?
151//
152
153static void	DCLReceiveBuffer( DCLCommand** ppCurrentDCLCommand, UInt32 packetHeader,
154	UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket )
155{
156	DCLTransferBuffer*	pDCLTransferBuffer;
157	UInt8 *				buffer;
158	UInt32				bufferOffset, bufferSize;
159	UInt32				bufferSizeLeft;
160	UInt8 *				packetBuffer;
161	UInt32				packetSize;
162	UInt32				transferSize;
163
164	// Recast current DCL command.
165	pDCLTransferBuffer = (DCLTransferBuffer*) *ppCurrentDCLCommand;
166
167	// Get some parameters.
168	buffer = (UInt8 *)pDCLTransferBuffer->buffer;
169	bufferOffset = pDCLTransferBuffer->bufferOffset;
170	bufferSize = pDCLTransferBuffer->size;
171	packetBuffer = *pPacketBuffer;
172	packetSize = *pPacketSize;
173
174	// Compute size of transfer.
175	bufferSizeLeft = bufferSize - bufferOffset;
176	if (bufferSizeLeft > packetSize)
177		transferSize = packetSize;
178	else
179		transferSize = bufferSizeLeft;
180
181	// Transfer the packet data.
182	if (transferSize > 0)
183	{
184		bcopy (packetBuffer, buffer + bufferOffset, transferSize);
185
186		packetBuffer += transferSize;
187		packetSize -= transferSize;
188		bufferOffset += transferSize;
189	}
190
191	// Check if we're done with this DCL or need another packet.
192	if (bufferOffset == bufferSize)
193	{
194		*ppCurrentDCLCommand = pDCLTransferBuffer->pNextDCLCommand;
195		*pGetNextPacket = false;
196	}
197	else
198	{
199		*pGetNextPacket = true;
200	}
201
202	// Update parameters.
203	pDCLTransferBuffer->bufferOffset = bufferOffset;
204	*pPacketBuffer = packetBuffer;
205	*pPacketSize = packetSize;
206}
207
208////////////////////////////////////////////////////////////////////////////////
209//
210// DCLSendPacket
211//
212//   This routine runs a DCL send packet command.
213//
214
215static void	DCLSendPacket(
216	DCLCommand**	ppCurrentDCLCommand,
217	UInt8 *			*pPacketBuffer,
218	UInt32			*pPacketSize,
219	bool			*pGetNextPacket)
220{
221	DCLTransferPacket*	pDCLTransferPacket;
222	UInt8 *			transferBuffer;
223	UInt8 *			packetBuffer;
224	UInt32			transferSize, packetSize;
225
226	// Recast DCL command.
227	pDCLTransferPacket = (DCLTransferPacket*) *ppCurrentDCLCommand;
228
229	// Get some parameters.
230	transferBuffer = (UInt8 *)pDCLTransferPacket->buffer;
231	transferSize = pDCLTransferPacket->size;
232	packetSize = *pPacketSize;
233	packetBuffer = *pPacketBuffer + packetSize;
234
235	// Transfer the packet data.
236	bcopy (transferBuffer, packetBuffer, transferSize);
237	packetSize += transferSize;
238
239	// Check if we need another packet.
240	*pGetNextPacket = true;
241	if (pDCLTransferPacket->pNextDCLCommand != NULL)
242	{
243		if ((pDCLTransferPacket->pNextDCLCommand->opcode & ~kFWDCLOpFlagMask) ==
244			kDCLSendPacketOp)
245		{
246			*pGetNextPacket = false;
247		}
248	}
249
250	// Update parameters.
251	*ppCurrentDCLCommand = pDCLTransferPacket->pNextDCLCommand;
252	*pPacketSize = packetSize;
253}
254
255
256////////////////////////////////////////////////////////////////////////////////
257//
258// DCLSendBuffer
259//
260//   This routine runs a DCL send buffer command.
261//zzz should we clip off end of packet when buffer is emptied?
262//
263
264static void	DCLSendBuffer( DCLCommand** ppCurrentDCLCommand, UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket)
265{
266	DCLTransferBuffer*	pDCLTransferBuffer;
267	UInt8 *			buffer;
268	UInt32			bufferOffset, bufferSize;
269	UInt32			bufferSizeLeft;
270	UInt8 *			packetBuffer;
271	UInt32			packetSize;
272	UInt32			transferPacketSize;
273	UInt32			transferSize;
274
275	// Recast current DCL command.
276	pDCLTransferBuffer = (DCLTransferBuffer*) *ppCurrentDCLCommand;
277
278	// Get some parameters.
279	buffer = (UInt8 *)pDCLTransferBuffer->buffer;
280	bufferOffset = pDCLTransferBuffer->bufferOffset;
281	bufferSize = pDCLTransferBuffer->size;
282	packetSize = *pPacketSize;
283	packetBuffer = *pPacketBuffer + packetSize;
284	transferPacketSize = pDCLTransferBuffer->packetSize;
285
286	// Compute size of transfer.
287	bufferSizeLeft = bufferSize - bufferOffset;
288	if (bufferSizeLeft > transferPacketSize)
289		transferSize = transferPacketSize;
290	else
291		transferSize = bufferSizeLeft;
292
293	// Transfer the packet data.
294	if (transferSize > 0)
295	{
296		bcopy (buffer + bufferOffset, packetBuffer, transferSize);
297
298		packetSize += transferSize;
299		bufferOffset += transferSize;
300	}
301
302	// Check if we're done with this DCL or need another packet.
303	//zzz is this the best way to do this?
304	//zzz what if the next transfer command is a transfer packet command?
305	if (bufferOffset == bufferSize)
306	{
307		*ppCurrentDCLCommand = pDCLTransferBuffer->pNextDCLCommand;
308		*pGetNextPacket = false;
309	}
310	else
311	{
312		*pGetNextPacket = true;
313	}
314
315	// Update parameters.
316	pDCLTransferBuffer->bufferOffset = bufferOffset;
317	*pPacketSize = packetSize;
318}
319
320////////////////////////////////////////////////////////////////////////////////
321//
322// FWRunTranslatedDCLEngine
323//
324//   This routine runs the current DCL command using the given packet.  It will
325// update the current DCL command, packet buffer pointer, packet size, and will
326// set get next packet to true if it needs another packet.
327//zzz maybe a vector table would be nice
328//zzz implement rest of DCL commands.
329//
330
331static void	RunListeningDCLEngine( DCLCommand** ppCurrentDCLCommand, UInt32 packetHeader, UInt8** pPacketBuffer,
332		UInt32* pPacketSize, bool* pGetNextPacket)
333{
334    DCLCommand*				pCurrentDCLCommand;
335    DCLCallProc*			pDCLCallProc;
336    DCLJump*				pDCLJump;
337
338    // Run the current DCL command.
339    pCurrentDCLCommand = *ppCurrentDCLCommand;
340    switch (pCurrentDCLCommand->opcode & ~kFWDCLOpFlagMask)
341    {
342            case kDCLReceivePacketStartOp :
343                    DCLReceivePacketStart (
344                                                            &pCurrentDCLCommand,
345                                                            packetHeader,
346                                                            pPacketBuffer,
347                                                            pPacketSize,
348                                                            pGetNextPacket);
349                    break;
350
351            case kDCLReceivePacketOp :
352                    DCLReceivePacket (
353                                                            &pCurrentDCLCommand,
354                                                            packetHeader,
355                                                            pPacketBuffer,
356                                                            pPacketSize,
357                                                            pGetNextPacket);
358                    break;
359
360            case kDCLReceiveBufferOp :
361                    DCLReceiveBuffer (
362                                                            &pCurrentDCLCommand,
363                                                            packetHeader,
364                                                            pPacketBuffer,
365                                                            pPacketSize,
366                                                            pGetNextPacket);
367                    break;
368
369            case kDCLCallProcOp :
370                    pDCLCallProc = (DCLCallProc*) pCurrentDCLCommand;
371                    // Call the handler if there is one.
372                    if (pDCLCallProc->proc != NULL)
373			(*(pDCLCallProc->proc)) ((DCLCommand*) pDCLCallProc);
374
375                    pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
376                    *pGetNextPacket = false;
377                    break;
378
379            case kDCLJumpOp :
380                    pDCLJump = (DCLJump*) pCurrentDCLCommand;
381                    pCurrentDCLCommand = (DCLCommand*) pDCLJump->pJumpDCLLabel;
382                    *pGetNextPacket = false;
383                    break;
384
385            default :
386                    pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
387                    *pGetNextPacket = false;
388                    break;
389    }
390
391    // Update current DCL command.
392    *ppCurrentDCLCommand = pCurrentDCLCommand;
393}
394
395////////////////////////////////////////////////////////////////////////////////
396//
397// FWRunTranslatedTalkingDCLEngine
398//
399//   This routine runs the current DCL command using the given packet.  It will
400// update the current DCL command, packet buffer pointer, packet size, and will
401// set get next packet to true if it needs another packet.
402//zzz maybe a vector table would be nice
403//
404
405static void	RunTalkingDCLEngine( UInt32* packetHeader, DCLCommand** ppCurrentDCLCommand,
406		UInt8** pPacketBuffer, UInt32* pPacketSize, bool* pGetNextPacket)
407{
408	DCLCommand*				pCurrentDCLCommand;
409	DCLCallProc*			pDCLCallProc;
410	DCLJump*				pDCLJump;
411	DCLSetTagSyncBits*		pDCLSetTagSyncBits;
412	UInt32					host_header;
413
414	// Run the current DCL command.
415	pCurrentDCLCommand = *ppCurrentDCLCommand;
416	switch (pCurrentDCLCommand->opcode & ~kFWDCLOpFlagMask)
417	{
418		case kDCLSendPacketStartOp :
419		case kDCLSendPacketOp :
420			DCLSendPacket (
421							 &pCurrentDCLCommand,
422							 pPacketBuffer,
423							 pPacketSize,
424							 pGetNextPacket);
425			break;
426
427		case kDCLSendBufferOp :
428			DCLSendBuffer (
429							 &pCurrentDCLCommand,
430							 pPacketBuffer,
431							 pPacketSize,
432							 pGetNextPacket);
433			break;
434
435		case kDCLCallProcOp :
436                        pDCLCallProc = (DCLCallProc*) pCurrentDCLCommand;
437                        // Call the handler if there is one.
438                        if (pDCLCallProc->proc != NULL)
439                            (*(pDCLCallProc->proc)) ((DCLCommand*) pDCLCallProc);
440			pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
441			*pGetNextPacket = false;
442			break;
443
444		case kDCLJumpOp :
445			pDCLJump = (DCLJump*) pCurrentDCLCommand;
446			pCurrentDCLCommand = (DCLCommand*) pDCLJump->pJumpDCLLabel;
447			*pGetNextPacket = false;
448			break;
449
450		case kDCLLabelOp :
451			pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
452			*pGetNextPacket = false;
453			break;
454
455		case kDCLSetTagSyncBitsOp :
456			pDCLSetTagSyncBits = (DCLSetTagSyncBits*) pCurrentDCLCommand;
457			host_header = OSSwapBigToHostInt32( *packetHeader );
458			host_header &= ~(kFWIsochTag | kFWIsochSy);
459			host_header |= (pDCLSetTagSyncBits->tagBits << kFWIsochTagPhase);
460			host_header |= (pDCLSetTagSyncBits->syncBits << kFWIsochSyPhase);
461			*packetHeader = OSSwapHostToBigInt32( host_header );
462			pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
463			*pGetNextPacket = false;
464			break;
465
466		default :
467			pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
468			*pGetNextPacket = false;
469			break;
470	}
471
472	// Update current DCL command.
473	*ppCurrentDCLCommand = pCurrentDCLCommand;
474}
475
476OSDefineMetaClass( IODCLTranslator, IODCLProgram )
477OSDefineAbstractStructors(IODCLTranslator, IODCLProgram)
478
479bool IODCLTranslator::init(DCLCommand* toInterpret)
480{
481    if(!IODCLProgram::init())
482	return false;
483
484    // Allocate buffers etc. for programs
485
486    fToInterpret = toInterpret;
487    return true;
488}
489
490IOReturn
491IODCLTranslator::notify (
492	IOFWDCLNotificationType 	notificationType,
493	DCLCommand ** 				dclCommandList,
494	UInt32	 					numDCLCommands )
495{
496    return kIOReturnSuccess;	// Nothing to do, we're interpreting anyway
497}
498
499IOReturn IODCLTranslator::allocateHW(IOFWSpeed speed, UInt32 chan)
500{
501    if(!fHWProgram)
502        return kIOReturnInternalError;
503    return fHWProgram->allocateHW(speed, chan);
504}
505IOReturn IODCLTranslator::releaseHW()
506{
507    if(!fHWProgram)
508        return kIOReturnInternalError;
509    return fHWProgram->releaseHW();
510}
511
512void IODCLTranslator::stop()
513{
514    fHWProgram->stop();
515}
516
517DCLCommand*
518IODCLTranslator::getTranslatorOpcodes()
519{
520	return (DCLCommand*)&fStartLabel;
521}
522
523void
524IODCLTranslator::setHWProgram(IODCLProgram *program)
525{
526	fHWProgram = program;
527}
528
529void
530IODCLTranslator::ListeningDCLPingPongProc(DCLCommand* pDCLCommand)
531{
532    IODCLTranslator *		me;
533    DCLCommand*		pCurrentDCLCommand;
534    DCLTransferPacket*	pDCLTransferPacket;
535    UInt8 *			packetBuffer;
536    UInt32			packetHeader;
537    UInt32			packetSize;
538    UInt32			packetNum;
539    bool			getNextPacket;
540
541    me = (IODCLTranslator *)((DCLCallProc*)pDCLCommand)->procData;
542    pCurrentDCLCommand = me->fCurrentDCLCommand;
543    pDCLTransferPacket = &me->fTransfers[me->fPingCount * kNumPacketsPerPingPong];
544    // Run all packets through DCL program.
545    for (packetNum = 0;
546            ((packetNum < kNumPacketsPerPingPong) && (pCurrentDCLCommand != NULL));
547                        packetNum++) {
548        // Compute packet size.
549        packetBuffer = (UInt8 *)pDCLTransferPacket->buffer;
550        packetHeader = *((UInt32 *) packetBuffer);
551        packetBuffer += sizeof (UInt32);
552        packetSize = (OSSwapBigToHostInt32(packetHeader) & kFWIsochDataLength) >> kFWIsochDataLengthPhase;
553
554        // Run this packet through DCL program.
555        getNextPacket = false;
556        while ((!getNextPacket) && (pCurrentDCLCommand != NULL)) {
557            RunListeningDCLEngine (
558				&pCurrentDCLCommand,
559                                packetHeader,
560                                &packetBuffer,
561                                &packetSize,
562                                &getNextPacket);
563        }
564
565        // Update for next packet.
566        pDCLTransferPacket++;
567    }
568
569    // Update DCL translation data.
570    me->fCurrentDCLCommand = pCurrentDCLCommand;
571    me->fPingCount++;
572    if(me->fPingCount > kNumPingPongs)
573	me->fPingCount = 0;
574}
575
576void IODCLTranslator::TalkingDCLPingPongProc(DCLCommand* pDCLCommand)
577{
578    IODCLTranslator *		me;
579    DCLCommand*				pCurrentDCLCommand;
580    DCLTransferPacket*		pDCLTransferPacket;
581    UInt8 *					packetBuffer;
582    UInt32					packetHeader;
583    UInt32					packetSize;
584    UInt32					packetNum;
585    bool					getNextPacket;
586
587    me = (IODCLTranslator *)((DCLCallProc*)pDCLCommand)->procData;
588    pCurrentDCLCommand = me->fCurrentDCLCommand;
589    pDCLTransferPacket = &me->fTransfers[me->fPingCount * kNumPacketsPerPingPong];
590    // Run all packets through DCL program.
591    for (packetNum = 0;
592            ((packetNum < kNumPacketsPerPingPong) && (pCurrentDCLCommand != NULL));
593                        packetNum++) {
594        // Compute packet size.
595        packetBuffer = (UInt8 *)pDCLTransferPacket->buffer;
596        packetSize = sizeof (UInt32);
597
598        // Run this packet through DCL program.
599        getNextPacket = false;
600        while ((!getNextPacket) && (pCurrentDCLCommand != NULL)) {
601            RunTalkingDCLEngine (&(me->fPacketHeader),
602				&pCurrentDCLCommand,
603                                &packetBuffer,
604                                &packetSize,
605                                &getNextPacket);
606        }
607        // Update packet header.
608        packetSize -= 4;//zzz not the best way
609        packetHeader =
610                (packetSize << kFWIsochDataLengthPhase) |
611                (OSSwapBigToHostInt32(me->fPacketHeader) & ~(kFWIsochDataLength));
612        *((UInt32 *) packetBuffer) = OSSwapHostToBigInt32(packetHeader);
613
614        // Update send packet DCL.
615        packetSize += 4;//zzz really, not the best way
616	// Change the transfer packet command.
617	pDCLTransferPacket->size = packetSize;
618	// Send notification to DCL compiler.
619	me->fHWProgram->notify(kFWDCLModifyNotification,
620				(DCLCommand**) pDCLTransferPacket, 1);
621
622        // Update for next packet.
623        pDCLTransferPacket++;
624    }
625
626    // Update DCL translation data.
627    me->fCurrentDCLCommand = pCurrentDCLCommand;
628    me->fPingCount++;
629    if(me->fPingCount > kNumPingPongs)
630	me->fPingCount = 0;
631}
632
633/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
634OSDefineMetaClassAndStructors(IODCLTranslateTalk, IODCLTranslator)
635
636IOReturn IODCLTranslateTalk::compile(IOFWSpeed speed, UInt32 chan)
637{
638    int pingPongNum;
639    int packetNum;
640    DCLTransferPacket* pDCLTransferPacket = &fTransfers[0];
641    DCLCallProc* pDCLPingPongProc = &fCalls[0];
642    UInt8 *pingPongBuffer = fBuffer;
643
644    if(!fHWProgram)
645        return kIOReturnInternalError;
646
647    fPacketHeader = OSSwapHostToBigInt32( chan << kFWIsochChanNumPhase );
648
649    // Create label for start of loop.
650    fStartLabel.pNextDCLCommand = (DCLCommand*)pDCLTransferPacket;
651    fStartLabel.opcode = kDCLLabelOp;
652
653    // Create kNumPingPongs ping pong buffer lists of kNumPacketsPerPingPong
654    // packets each.
655    for (pingPongNum = 0;  pingPongNum < kNumPingPongs; pingPongNum++) {
656        // Create transfer DCL for each packet.
657        for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++) {
658            // Receive one packet up to kMaxIsochPacketSize bytes.
659            pDCLTransferPacket->pNextDCLCommand = (DCLCommand*)(pDCLTransferPacket+1);
660            pDCLTransferPacket->opcode = kDCLSendPacketWithHeaderStartOp | kFWDCLOpDynamicFlag;
661            pDCLTransferPacket->buffer = pingPongBuffer;
662            pDCLTransferPacket->size = kMaxIsochPacketSize;
663            pingPongBuffer += kMaxIsochPacketSize;
664            pDCLTransferPacket++;
665        }
666	// Correct next opcode for last transfer op.
667        (pDCLTransferPacket-1)->pNextDCLCommand = (DCLCommand*)pDCLPingPongProc;
668        // Call the ping pong proc.
669        pDCLPingPongProc->pNextDCLCommand = (DCLCommand*) pDCLTransferPacket;
670        pDCLPingPongProc->opcode = kDCLCallProcOp;
671        pDCLPingPongProc->proc = TalkingDCLPingPongProc;
672        pDCLPingPongProc->procData = (UInt32) this;
673        pDCLPingPongProc++;
674    }
675    // Correct next opcode for last call op.
676    (pDCLPingPongProc-1)->pNextDCLCommand = (DCLCommand*)&fJumpToStart;
677
678    // Loop to start of ping pong.
679    fJumpToStart.pNextDCLCommand = NULL;
680    fJumpToStart.opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
681    fJumpToStart.pJumpDCLLabel = &fStartLabel;
682
683    return fHWProgram->compile(speed, chan);
684}
685
686IOReturn IODCLTranslateTalk::start()
687{
688    int i;
689    fPingCount = 0;
690    // Prime all buffers
691    for(i=0; i<kNumPingPongs; i++) {
692        TalkingDCLPingPongProc((DCLCommand*)&fCalls[i]);
693    }
694    return fHWProgram->start();
695}
696
697/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
698OSDefineMetaClassAndStructors(IODCLTranslateListen, IODCLTranslator)
699
700IOReturn IODCLTranslateListen::compile(IOFWSpeed speed, UInt32 chan)
701{
702    int pingPongNum;
703    int packetNum;
704    DCLTransferPacket* pDCLTransferPacket = &fTransfers[0];
705    DCLCallProc* pDCLPingPongProc = &fCalls[0];
706    UInt8 *pingPongBuffer = fBuffer;
707
708    if(!fHWProgram)
709        return kIOReturnInternalError;
710
711    fPacketHeader = OSSwapHostToBigInt32( chan << kFWIsochChanNumPhase );
712
713    // Create label for start of loop.
714    fStartLabel.pNextDCLCommand = (DCLCommand*)pDCLTransferPacket;
715    fStartLabel.opcode = kDCLLabelOp;
716
717    // Create kNumPingPongs ping pong buffer lists of kNumPacketsPerPingPong
718    // packets each.
719    for (pingPongNum = 0;  pingPongNum < kNumPingPongs; pingPongNum++) {
720        // Create transfer DCL for each packet.
721        for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++) {
722            // Receive one packet up to kMaxIsochPacketSize bytes.
723            pDCLTransferPacket->pNextDCLCommand = (DCLCommand*)(pDCLTransferPacket+1);
724            pDCLTransferPacket->opcode = kDCLReceivePacketStartOp | kFWDCLOpDynamicFlag;
725            pDCLTransferPacket->buffer = pingPongBuffer;
726            pDCLTransferPacket->size = kMaxIsochPacketSize;
727            pingPongBuffer += kMaxIsochPacketSize;
728            pDCLTransferPacket++;
729        }
730	// Correct next opcode for last transfer op.
731        (pDCLTransferPacket-1)->pNextDCLCommand = (DCLCommand*)pDCLPingPongProc;
732        // Call the ping pong proc.
733        pDCLPingPongProc->pNextDCLCommand = (DCLCommand*) pDCLTransferPacket;
734        pDCLPingPongProc->opcode = kDCLCallProcOp;
735        pDCLPingPongProc->proc = ListeningDCLPingPongProc;
736        pDCLPingPongProc->procData = (UInt32) this;
737        pDCLPingPongProc++;
738    }
739    // Correct next opcode for last call op.
740    (pDCLPingPongProc-1)->pNextDCLCommand = (DCLCommand*)&fJumpToStart;
741
742    // Loop to start of ping pong.
743    fJumpToStart.pNextDCLCommand = NULL;
744    fJumpToStart.opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
745    fJumpToStart.pJumpDCLLabel = &fStartLabel;
746
747    return fHWProgram->compile(speed, chan);
748}
749
750IOReturn IODCLTranslateListen::start()
751{
752    fPingCount = 0;
753    return fHWProgram->start();
754}
755