1/*
2 * Copyright (c) 1998-2001 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#include <IOKit/firewire/IOFireWireBus.h>
24#include <IOKit/firewire/IOFireWireNub.h>
25#include <IOKit/firewire/IOFWUtils.h>
26
27#include "IOFWAsyncStreamReceiver.h"
28#include "IOFWAsyncStreamReceivePort.h"
29#include "IOFWAsyncStreamListener.h"
30#include "FWDebugging.h"
31
32
33OSDefineMetaClassAndStructors(IOFWAsyncStreamReceiver, OSObject);
34OSMetaClassDefineReservedUnused(IOFWAsyncStreamReceiver, 0);
35OSMetaClassDefineReservedUnused(IOFWAsyncStreamReceiver, 1);
36
37//#define DCL_MODE 1  // comment this to turn on multi mode async stream receive
38
39/*!
40    @function initAll
41	Initializes the AsyncStream Recieve command object
42	@result true if successfull.
43*/
44bool IOFWAsyncStreamReceiver::initAll( IOFireWireController *control, UInt32 channel )
45{
46	IOReturn status	= kIOReturnSuccess;
47
48	fControl	= control;
49	fFWIM		= fControl->getLink();
50
51	fControl->closeGate();
52
53#ifdef DCL_MODE
54	// Create a DCL program
55	fdclProgram = CreateAsyncStreamRxDCLProgram(receiveAsyncStream, this);
56	if(fdclProgram == NULL){
57		DebugLog("IOFWAsyncStreamReceiver::initAll -> CreateAsyncStreamRxDCLProgram failed %x\n", status);
58		return false;
59	}
60
61	fChannel = channel;
62	fSpeed	 = kFWSpeedMaximum;
63
64	fActive = false;
65    fInitialized = true;
66
67	fAsyncStreamClients = OSSet::withCapacity(2);
68	if( fAsyncStreamClients )
69		fAsyncStreamClientIterator = OSCollectionIterator::withCollection( fAsyncStreamClients );
70
71	status = activate(control->getBroadcastSpeed());
72
73	if ( status == kIOReturnSuccess )
74	{
75		fIODclProgram->setForceStopProc( forceStopNotification, this, fAsyncStreamChan );
76	}
77
78#else
79
80	UInt64 mask = fControl->getFireWirePhysicalBufferMask();							// get controller mask
81	mask		&= ~((UInt64)(PAGE_SIZE-1));											// page align
82	fBufDesc	= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
83															kernel_task,				// kernel task
84															0,							// options
85															kMaxAsyncStreamReceiveBufferSize*2,	// size = 4096 * 2
86															mask );						// mask for physically addressable memory
87
88    if( fBufDesc )
89    {
90		fListener		= control->createMultiIsochReceiveListener(channel,receiveAsyncStream,this);
91
92		if ( fListener )
93		{
94			fChannel		= channel;
95			fSpeed			= kFWSpeedMaximum;
96			fActive			= false;
97			fInitialized	= true;
98
99			fAsyncStreamClients = OSSet::withCapacity(1);
100			if( fAsyncStreamClients )
101			{
102				fAsyncStreamClientIterator = OSCollectionIterator::withCollection( fAsyncStreamClients );
103			}
104			else
105			{
106				status = kIOReturnError;
107			}
108
109			status = fListener->Activate();
110		}
111		else
112		{
113			status = kIOReturnError;
114		}
115	}
116	else
117	{
118		status = kIOReturnError;
119	}
120
121#endif
122
123	fControl->openGate();
124
125	return ( status == kIOReturnSuccess );
126}
127
128void IOFWAsyncStreamReceiver::free()
129{
130	fControl->closeGate();
131
132#ifdef DCL_MODE
133
134	deactivate();
135
136	// free dcl program
137	if( fdclProgram )
138	{
139		FreeAsyncStreamRxDCLProgram(fdclProgram);
140		fdclProgram = NULL;
141	}
142
143	// free the buffer
144	if( fBufDesc )
145	{
146		fBufDesc->release();
147		fBufDesc = NULL;
148	}
149
150#else
151
152	if( fListener )
153	{
154		fListener->Deactivate();
155		fListener->release();
156		fListener = NULL;
157	}
158
159	// free the buffer
160	if( fBufDesc )
161	{
162		fBufDesc->release();
163		fBufDesc = NULL;
164	}
165
166#endif
167
168	removeAllListeners();
169
170	if ( fAsyncStreamClients )
171	{
172		fAsyncStreamClients->release();
173		fAsyncStreamClients = NULL;
174	}
175
176	if( fAsyncStreamClientIterator )
177	{
178		fAsyncStreamClientIterator->release();
179		fAsyncStreamClientIterator = NULL;
180	}
181
182	fControl->openGate();
183
184	OSObject::free();
185}
186
187void IOFWAsyncStreamReceiver::FreeAsyncStreamRxDCLProgram(DCLCommandStruct *dclProgram)
188{
189    UInt32				seg = 0;
190	DCLLabel			*startLabel;
191	DCLTransferPacket	*receivePacket;
192	DCLUpdateDCLList	*update;
193	DCLCommand			*dclCommand;
194	DCLCallProc			*callProc;
195	FWAsyncStreamReceiveRefCon		*rxProcData;
196    DCLJump				*jump;
197
198	if ( fReceiveSegmentInfoPtr )
199	{
200		for (seg=0;	seg<kMaxAsyncStreamReceiveBuffers-1;	seg++)
201		{
202			// free label
203			startLabel = fReceiveSegmentInfoPtr[seg].pSegmentLabelDCL;
204			if(startLabel == NULL)
205				break;
206
207			receivePacket = (DCLTransferPacket*)startLabel->pNextDCLCommand;
208			if(receivePacket == NULL)
209				break;
210
211			update = (DCLUpdateDCLList*)receivePacket->pNextDCLCommand;
212			if(update == NULL)
213				break;
214
215			dclCommand = (DCLCommand*)update->dclCommandList[0];
216			if(dclCommand == NULL)
217				break;
218
219			callProc = (DCLCallProc*)update->pNextDCLCommand;
220			if(callProc == NULL)
221				break;
222
223			rxProcData = (FWAsyncStreamReceiveRefCon*)callProc->procData;
224			if(rxProcData == NULL)
225				break;
226
227			jump = (DCLJump *)callProc->pNextDCLCommand;
228			if(jump == NULL)
229				break;
230
231			delete rxProcData;
232			delete dclCommand;
233			delete update->dclCommandList;
234			delete update;
235			delete startLabel;
236			delete jump;
237			delete callProc;
238		}
239
240		delete[] fReceiveSegmentInfoPtr;
241		fReceiveSegmentInfoPtr = NULL;
242	}
243
244	if ( fDCLOverrunLabelPtr )
245	{
246		receivePacket = (DCLTransferPacket*)fDCLOverrunLabelPtr->pNextDCLCommand;
247		if(receivePacket != NULL)
248		{
249			update = (DCLUpdateDCLList*)receivePacket->pNextDCLCommand;
250			if(update != NULL)
251			{
252				callProc = (DCLCallProc*)update->pNextDCLCommand;
253				if(callProc != NULL)
254					delete callProc;
255
256				delete update->dclCommandList;
257				delete update;
258			}
259			delete receivePacket;
260		}
261		delete fDCLOverrunLabelPtr;
262		fDCLOverrunLabelPtr = NULL;
263	}
264}
265
266DCLCommandStruct *IOFWAsyncStreamReceiver::CreateAsyncStreamRxDCLProgram(DCLCallCommandProc* proc, void *callbackObject)
267{
268	// Create a DCL program
269	UInt64 mask = fControl->getFireWirePhysicalBufferMask();							// get controller mask
270	UInt16 size = kMaxAsyncStreamReceiveBufferSize;
271
272	mask		&= ~((UInt64)(PAGE_SIZE-1));											// page align
273	fBufDesc	= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
274															kernel_task,				// kernel task
275															0,							// options
276															kMaxAsyncStreamReceiveBuffers*size,	// size
277															mask );						// mask for physically addressable memory
278
279    if(fBufDesc == NULL)
280        return NULL;
281
282    UInt8	*currentBuffer = (UInt8*)fBufDesc->getBytesNoCopy() ;
283
284	fReceiveSegmentInfoPtr = new FWAsyncStreamReceiveSegment[kMaxAsyncStreamReceiveBuffers-1];
285
286    // start of new way
287   	for (fSegment=0;	fSegment<kMaxAsyncStreamReceiveBuffers-1;	fSegment++)
288	{
289        DCLLabel *pLastDCL = new DCLLabel ;
290        {
291            pLastDCL->opcode = kDCLLabelOp ;
292        }
293
294        fReceiveSegmentInfoPtr[fSegment].pSegmentLabelDCL = NULL;
295        fReceiveSegmentInfoPtr[fSegment].pSegmentJumpDCL = NULL;
296
297		// Allocate the label for this segment, and save pointer in seg info
298		fReceiveSegmentInfoPtr[fSegment].pSegmentLabelDCL = (DCLLabelPtr) pLastDCL;
299
300		if (fSegment == 0)
301		{
302			fdclProgram = (DCLCommand*)pLastDCL;
303		}
304
305        DCLTransferPacket	*receivePacket = new DCLTransferPacket ;
306        {
307            receivePacket->opcode = kDCLReceivePacketStartOp ;
308            receivePacket->buffer = currentBuffer ;
309            receivePacket->size = size ;
310        }
311
312        DCLUpdateDCLList	*update = new DCLUpdateDCLList ;
313        {
314            update->opcode = kDCLUpdateDCLListOp ;
315            update->dclCommandList = new DCLCommand*[1] ;
316            update->dclCommandList[0] = (DCLCommand*)receivePacket ;
317            update->numDCLCommands = 1;		// Number of DCL commands in list.
318        }
319
320		DCLCallProc	*callProc = new DCLCallProc ;
321		{
322			callProc->opcode = kDCLCallProcOp ;
323			callProc->proc = proc ;
324			callProc->procData = (DCLCallProcDataType)new FWAsyncStreamReceiveRefCon ;
325
326			((FWAsyncStreamReceiveRefCon*)callProc->procData)->obj = callbackObject;
327			((FWAsyncStreamReceiveRefCon*)callProc->procData)->thisObj = this;
328			((FWAsyncStreamReceiveRefCon*)callProc->procData)->buffer = currentBuffer ;
329			((FWAsyncStreamReceiveRefCon*)callProc->procData)->index = fSegment ;
330		}
331
332		DCLJump	*jump = new DCLJump ;
333		{
334			jump->opcode = kDCLJumpOp ;
335			jump->pJumpDCLLabel = pLastDCL ;
336		}
337
338		pLastDCL->pNextDCLCommand = (DCLCommand*)receivePacket ;
339		receivePacket->pNextDCLCommand = (DCLCommand*)update ;
340		update->pNextDCLCommand = (DCLCommand*)callProc ;
341        callProc->pNextDCLCommand = (DCLCommand*)jump ;
342
343		currentBuffer += receivePacket->size ;
344
345        // Store the jump information.
346		fReceiveSegmentInfoPtr[fSegment].pSegmentJumpDCL = jump;
347    }
348
349	// Allocate Overrun label & callback DCL
350	fDCLOverrunLabelPtr = new DCLLabel ;
351
352    fDCLOverrunLabelPtr->opcode = kDCLLabelOp ;
353
354    DCLTransferPacket	*receivePacket = new DCLTransferPacket ;
355    {
356        receivePacket->opcode = kDCLReceivePacketStartOp ;
357        receivePacket->buffer = currentBuffer ;
358        receivePacket->size = size ;
359    }
360
361    DCLUpdateDCLList	*update = new DCLUpdateDCLList ;
362    {
363        update->opcode = kDCLUpdateDCLListOp ;
364        update->dclCommandList = new DCLCommand*[1] ;
365        update->dclCommandList[0] = (DCLCommand*)receivePacket ;
366        update->numDCLCommands = 1;		// Number of DCL commands in list.
367    }
368
369    DCLCallProc	*callProc = new DCLCallProc ;
370    {
371        callProc->opcode = kDCLCallProcOp ;
372        callProc->proc = overrunNotification;
373        callProc->procData = (DCLCallProcDataType)this;
374    }
375
376    fDCLOverrunLabelPtr->pNextDCLCommand = (DCLCommand*)receivePacket ;
377    receivePacket->pNextDCLCommand = (DCLCommand*)update ;
378    update->pNextDCLCommand = (DCLCommand*)callProc ;
379 	// Set the next pointer in the last DCL to nil
380	callProc->pNextDCLCommand = NULL ;
381
382    fixDCLJumps(false);
383
384
385	return (DCLCommand*)fdclProgram;
386}
387
388IOFWAsyncStreamReceivePort *IOFWAsyncStreamReceiver::CreateAsyncStreamPort(bool talking, DCLCommandStruct *opcodes, void *info,
389													UInt32 startEvent, UInt32 startState, UInt32 startMask,
390													UInt32 channel )
391{
392    IOFWAsyncStreamReceivePort *port;
393
394    if(fFWIM == NULL)
395    {
396		DebugLog("IOFWAsyncStreamReceiver::CreateAsyncStreamPort failed -> FWIM is NULL\n");
397		return NULL;
398    }
399
400    fIODclProgram = fFWIM->createDCLProgram(talking, opcodes, NULL, startEvent, startState, startMask);
401    if(!fIODclProgram)
402	{
403		DebugLog("IOFWAsyncStreamReceiver::CreateAsyncStreamPort failed -> fIODclProgram is NULL\n");
404		return NULL;
405	}
406
407    port = OSTypeAlloc( IOFWAsyncStreamReceivePort );
408    if(!port)
409	{
410		DebugLog("IOFWAsyncStreamReceiver::CreateAsyncStreamPort failed -> IOFWAsyncStreamReceivePort is NULL\n");
411		fIODclProgram->release();
412		fIODclProgram = NULL;
413		return NULL;
414    }
415
416    if(!port->init(fIODclProgram, fControl, channel))
417	{
418		DebugLog("IOFWAsyncStreamReceiver::CreateAsyncStreamPort failed -> IOFWAsyncStreamReceivePort::init failed\n");
419		port->release();
420		port = NULL;
421    }
422
423    return port;
424}
425
426IOReturn IOFWAsyncStreamReceiver::activate(IOFWSpeed fBroadCastSpeed)
427{
428	IOReturn status	= kIOReturnSuccess;
429
430    if(fInitialized == false)
431        return status;
432
433	if(fActive)
434		return status;
435
436	fSpeed = fBroadCastSpeed;
437
438	// Create IOFWAsyncStreamReceivePort with the required channel and DCL program
439	fAsynStreamPort = CreateAsyncStreamPort(false, fdclProgram, NULL, 0, 0, 0, fChannel);
440	if(fAsynStreamPort == NULL)
441	{
442		FreeAsyncStreamRxDCLProgram(fdclProgram);
443		DebugLog("IOFWAsyncStreamReceiver::activate -> CreateAsyncStreamPort failed %x\n", status);
444		return kIOReturnError;
445	}
446
447	// Create a IOFWIsocChannel with the created port
448	fAsyncStreamChan = fControl->createIsochChannel(false, 0, fSpeed, NULL, NULL);
449	if(fAsyncStreamChan == NULL)
450	{
451		FreeAsyncStreamRxDCLProgram(fdclProgram);
452		fAsynStreamPort->release() ;
453		fAsynStreamPort = NULL;
454		DebugLog("IOFWAsyncStreamReceiver::activate -> createIsochChannel failed %x\n", status);
455		return kIOReturnError;
456	}
457
458	status = fAsyncStreamChan->addListener(fAsynStreamPort);
459	if(status != kIOReturnSuccess)
460	{
461		FreeAsyncStreamRxDCLProgram(fdclProgram);
462		fAsyncStreamChan->stop();
463		fAsyncStreamChan->releaseChannel();
464		fAsyncStreamChan->release();
465		fAsyncStreamChan = NULL;
466		fAsynStreamPort->release() ;
467		fAsynStreamPort = NULL;
468		DebugLog("IOFWAsyncStreamReceiver::activate -> addListener failed %x\n", status);
469		return kIOReturnError;
470	}
471
472	// Allocate channel
473	status = fAsyncStreamChan->allocateChannel();
474
475    fixDCLJumps(true);
476
477	// Start channel
478	status = fAsyncStreamChan->start();
479	if(status != kIOReturnSuccess)
480	{
481		FreeAsyncStreamRxDCLProgram(fdclProgram);
482		fAsyncStreamChan->stop();
483		fAsyncStreamChan->releaseChannel();
484		fAsyncStreamChan->release();
485		fAsyncStreamChan = NULL;
486		fAsynStreamPort->release() ;
487		fAsynStreamPort = NULL;
488		DebugLog("IOFWAsyncStreamReceiver::activate -> channel start failed %x\n", status);
489		return kIOReturnError;
490	}
491
492	fActive = true;
493
494	return status;
495}
496
497IOReturn IOFWAsyncStreamReceiver::modifyDCLJumps(DCLCommandStruct *callProc)
498{
499	DCLCallProc 	*ptr = (DCLCallProc*)callProc;
500	FWAsyncStreamReceiveRefCon		*proc = (FWAsyncStreamReceiveRefCon*)ptr->procData;
501    IOReturn		status = kIOReturnError;
502
503    if(fInitialized == false)
504        return status;
505
506	if(!fActive)
507		return status;
508
509    if(proc == NULL)
510    {
511        DebugLog("IOFWAsyncStreamReceiver::modifyDCLJumps callproc data is NULL\n");
512        return status;
513    }
514
515    // Make the current segment's jump point to OverRun Label
516	UInt16 jumpIndex	= (proc->index - 1 + (kMaxAsyncStreamReceiveBuffers-1)) % (kMaxAsyncStreamReceiveBuffers-1);
517
518	fReceiveSegmentInfoPtr[proc->index].pSegmentJumpDCL->pJumpDCLLabel = fDCLOverrunLabelPtr;
519	status = fAsynStreamPort->notify(kFWDCLModifyNotification,
520									(DCLCommand**) & fReceiveSegmentInfoPtr[proc->index].pSegmentJumpDCL,
521									1);
522	if(status != kIOReturnSuccess)
523		DebugLog("IOFWAsyncStreamReceiver::modifyDCLJumps failed %x\n", status);
524
525	fReceiveSegmentInfoPtr[jumpIndex].pSegmentJumpDCL->pJumpDCLLabel = fReceiveSegmentInfoPtr[proc->index].pSegmentLabelDCL;
526	status = fAsynStreamPort->notify(kFWDCLModifyNotification,
527									(DCLCommand**) & fReceiveSegmentInfoPtr[jumpIndex].pSegmentJumpDCL,
528									1);
529	if(status != kIOReturnSuccess)
530		DebugLog("IOFWAsyncStreamReceiver::modifyDCLJumps failed %x\n", status);
531
532	return status;
533}
534
535void IOFWAsyncStreamReceiver::fixDCLJumps(bool	restart)
536{
537	UInt32 	 	i;
538    IOReturn	error;
539
540	for (i=0; i<kMaxAsyncStreamReceiveBuffers-1; i++)
541	{
542		if (i != (kMaxAsyncStreamReceiveBuffers-2))
543        {
544            fReceiveSegmentInfoPtr[i].pSegmentJumpDCL->pJumpDCLLabel = fReceiveSegmentInfoPtr[i+1].pSegmentLabelDCL;
545            fReceiveSegmentInfoPtr[i].pSegmentJumpDCL->pNextDCLCommand = (DCLCommand*)fReceiveSegmentInfoPtr[i+1].pSegmentLabelDCL;
546        }
547		else
548        {
549            fReceiveSegmentInfoPtr[i].pSegmentJumpDCL->pJumpDCLLabel = fDCLOverrunLabelPtr;
550			fReceiveSegmentInfoPtr[i].pSegmentJumpDCL->pNextDCLCommand = (DCLCommand*)fDCLOverrunLabelPtr;
551        }
552
553		// Only if fAsynStreamPort becomes valid, do it !!
554		if(restart == true && fAsynStreamPort != NULL)
555		{
556			error = fAsynStreamPort->notify(kFWDCLModifyNotification,
557											(DCLCommand**) & fReceiveSegmentInfoPtr[i].pSegmentJumpDCL,
558											1);
559			if(error != kIOReturnSuccess)
560				DebugLog("IOFWAsyncStreamReceiver::fixDCLJumps failed %x\n", error);
561		}
562	}
563}
564
565void IOFWAsyncStreamReceiver::overrunNotification(DCLCommandStruct *callProc)
566{
567	DCLCallProc 				*ptr = (DCLCallProc*)callProc;
568
569	if( ptr )
570	{
571	    IOFWAsyncStreamReceiver	*fwRxAsyncStream = OSDynamicCast( IOFWAsyncStreamReceiver, (OSObject*)ptr->procData );
572
573		if( fwRxAsyncStream )
574		{
575			fwRxAsyncStream->fIsoRxOverrun++;
576			fwRxAsyncStream->restart();
577		}
578	}
579}
580
581IOReturn IOFWAsyncStreamReceiver::forceStopNotification( void* refCon, IOFWIsochChannel* channel, UInt32 stopCondition )
582{
583    IOFWAsyncStreamReceiver	*fwRxAsyncStream = OSDynamicCast(IOFWAsyncStreamReceiver, (OSObject*)refCon);
584
585	if( fwRxAsyncStream )
586		fwRxAsyncStream->restart();
587
588	return kIOReturnSuccess;
589}
590
591void IOFWAsyncStreamReceiver::restart()
592{
593	// Stop the channel
594    fAsyncStreamChan->stop();
595
596    fixDCLJumps(true);
597
598	// Start the channel
599    fAsyncStreamChan->start();
600}
601
602IOReturn IOFWAsyncStreamReceiver::deactivate()
603{
604	IOReturn status	= kIOReturnSuccess;
605
606    if(fInitialized == false)
607        return status;
608
609	if(!fActive)
610		return status;
611
612	// Stop the channel
613	if( fAsyncStreamChan )
614		fAsyncStreamChan->stop();
615
616	// Lets release the channel
617	if( fAsyncStreamChan )
618		fAsyncStreamChan->releaseChannel();
619
620	// free the channel
621	if( fAsyncStreamChan )
622	{
623		fAsyncStreamChan->release();
624		fAsyncStreamChan = NULL;
625	}
626
627	// free the port
628	if( fAsynStreamPort )
629	{
630		fAsynStreamPort->release();
631		fAsynStreamPort = NULL;
632	}
633
634	fActive = false;
635
636	return status;
637}
638
639IOReturn IOFWAsyncStreamReceiver::receiveAsyncStream(void *refcon, IOFireWireMultiIsochReceivePacket *pPacket)
640{
641	IOFWAsyncStreamReceiver *receiver = (IOFWAsyncStreamReceiver*)refcon;
642
643	if( not receiver)
644		return kIOReturnError;
645
646	UInt16		index	= 0;
647	IOByteCount offset	= 0;
648
649	for(;;)
650	{
651		if(index ==  pPacket->numRanges)
652			break;
653
654		IOByteCount bytesWritten	=	receiver->fBufDesc->writeBytes(offset, (void*)pPacket->ranges[index].address, pPacket->ranges[index].length);
655		offset						+=	bytesWritten;
656
657		index++;
658	}
659
660	// Need to make the isoch header native endian
661	UInt32 *pHeader = (UInt32*)receiver->fBufDesc->getBytesNoCopy();
662	*pHeader = OSSwapLittleToHostInt32(*pHeader);
663
664	receiver->indicateListeners( (UInt8*)receiver->fBufDesc->getBytesNoCopy() );
665
666	pPacket->clientDone();
667
668	return kIOReturnSuccess;
669}
670
671
672void IOFWAsyncStreamReceiver::receiveAsyncStream(DCLCommandStruct *callProc)
673{
674	DCLCallProc	*ptr = (DCLCallProc*)callProc;
675
676	if( not ptr ) return;
677
678	FWAsyncStreamReceiveRefCon	*proc = (FWAsyncStreamReceiveRefCon*)ptr->procData;
679
680	if( not proc ) return;
681
682	IOFWAsyncStreamReceiver *receiver = (IOFWAsyncStreamReceiver*)proc->thisObj;
683
684	if( not receiver) return;
685
686	UInt8 *buffer = proc->buffer;
687
688	receiver->indicateListeners( buffer );
689
690    if( receiver->modifyDCLJumps( callProc ) == kIOReturnError ) return;
691}
692
693bool IOFWAsyncStreamReceiver::addListener ( IOFWAsyncStreamListener *listener )
694{
695	fControl->closeGate();
696
697	bool ret = true;
698
699    if( listener )
700	{
701		if(not fAsyncStreamClients->setObject( listener ))
702			ret = false;
703	}
704
705	fControl->openGate();
706
707	return ret;
708}
709
710void IOFWAsyncStreamReceiver::removeAllListeners()
711{
712	IOFWAsyncStreamListener * found;
713
714	fControl->closeGate();
715
716	fAsyncStreamClientIterator->reset();
717
718    while( (found = (IOFWAsyncStreamListener *) fAsyncStreamClientIterator->getNextObject()))
719		fAsyncStreamClients->removeObject(found);
720
721	fControl->openGate();
722
723	return;
724}
725
726void IOFWAsyncStreamReceiver::removeListener ( IOFWAsyncStreamListener *listener )
727{
728	fControl->closeGate();
729
730	if( listener )
731		fAsyncStreamClients->removeObject(listener);
732
733	fControl->openGate();
734
735	return;
736}
737
738void IOFWAsyncStreamReceiver::indicateListeners ( UInt8 *buffer )
739{
740	IOFWAsyncStreamListener * found;
741
742	fAsyncStreamClientIterator->reset();
743
744    while( (found = (IOFWAsyncStreamListener *) fAsyncStreamClientIterator->getNextObject() ) )
745		found->invokeClients(buffer);
746
747}
748
749UInt32	IOFWAsyncStreamReceiver::getClientsCount()
750{
751	return fAsyncStreamClients->getCount();
752}
753
754
755OSDefineMetaClassAndStructors(IOFWAsyncStreamListener, OSObject);
756OSMetaClassDefineReservedUnused(IOFWAsyncStreamListener, 0);
757OSMetaClassDefineReservedUnused(IOFWAsyncStreamListener, 1);
758
759bool IOFWAsyncStreamListener::initAll(IOFireWireController *control, UInt32 channel, FWAsyncStreamReceiveCallback proc, void *obj)
760{
761	fControl  = control;
762
763	fControl->closeGate();
764
765    fReceiver = control->getAsyncStreamReceiver( channel );
766
767	bool ret = false;
768
769	if( fReceiver == NULL )
770		fReceiver = control->allocAsyncStreamReceiver( channel, proc, obj );
771
772	if( fReceiver and fReceiver->addListener( this ) )
773	{
774		fReceiver->retain();
775		fClientProc	= proc;
776		fRefCon		= obj;
777		ret			= true;
778		TurnOffNotification();
779	}
780
781	fControl->openGate();
782
783	return ret;
784}
785
786const FWAsyncStreamReceiveCallback IOFWAsyncStreamListener::setListenerHandler( FWAsyncStreamReceiveCallback inReceiver )
787{
788	FWAsyncStreamReceiveCallback previousCallback = fClientProc;
789	fClientProc = inReceiver;
790
791	return previousCallback;
792}
793
794void IOFWAsyncStreamListener::free()
795{
796	fControl->closeGate();
797
798	if( fReceiver )
799	{
800		if( fReceiver->getClientsCount() == 0 )
801			fControl->removeAsyncStreamReceiver(fReceiver);
802
803		fReceiver->release();
804
805		fReceiver  = NULL;
806	}
807
808	fControl->openGate();
809
810	OSObject::free();
811}
812
813void IOFWAsyncStreamListener::invokeClients(UInt8 *buffer)
814{
815	if( fNotify )
816	{
817		fClientProc(fRefCon, buffer);
818	}
819}
820
821UInt32 IOFWAsyncStreamListener::getOverrunCounter()
822{
823	return fReceiver->getOverrunCounter();
824}
825
826void IOFWAsyncStreamListener::setFlags( UInt32 flags )
827{
828	fFlags = flags;
829}
830
831UInt32 IOFWAsyncStreamListener::getFlags()
832{
833	return fFlags;
834}
835
836
837