1/*
2 * Copyright (c) 2003 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 "IOFireWireAVCLibUnit.h"
24#include <IOKit/avc/IOFireWireAVCConsts.h>
25#include "IOFireWireAVCLibConsumer.h"
26
27#include <IOKit/IOMessage.h>
28#include <unistd.h>
29
30#define FWLOGGING 0
31#define FWASSERTING 0
32
33#if FWLOGGING
34#define FWLOG(x) printf x
35#else
36#define FWLOG(x) do {} while (0)
37#endif
38
39#if FWASSERTING
40#define FWLOGASSERT(a) { if(!(a)) { printf( "File "__FILE__", line %d: assertion '%s' failed.\n", __LINE__, #a); } }
41#else
42#define FWLOGASSERT(a) do {} while (0)
43#endif
44
45#define kProducerHeartbeatTime 	5.0 	// 5.0 seconds
46#define kConsumerHeartbeatTime 	3.0 	// 3.0 seconds
47#define kReconnectTime 			10.0 	// 10.0 seconds
48
49enum
50{
51    kFWAVCStatePrivBusSuspended 	= 0,
52    kFWAVCStatePrivBusResumed 		= 1,
53    kFWAVCStatePrivPlugSuspended 	= 3,
54    kFWAVCStatePrivPlugConnected 	= 4
55};
56
57enum
58{
59    kFWAVCConsumerPlugCountMask 	= 0x00ffffff,
60    kFWAVCConsumerPlugCountPhase 	= 0,
61    kFWAVCConsumerPlugSCMask 		= 0x01000000,
62    kFWAVCConsumerPlugSCPhase		= 24,
63    kFWAVCConsumerPlugModeMask  	= 0x0E000000,
64    kFWAVCConsumerPlugModePhase		= 25,
65    kFWAVCConsumerPlugHBMask 		= 0x10000000,
66    kFWAVCConsumerPlugHBPhase		= 28
67};
68
69enum
70{
71    kFWAVCConsumerMode_FREE 		= 0,
72    kFWAVCConsumerMode_SUSPENDED 	= 2
73};
74
75enum
76{
77    kFWAVCProducerMode_FREE 		= 0,
78    kFWAVCProducerMode_SUSPEND		= 2,
79    kFWAVCProducerMode_RESUME		= 4
80};
81
82enum
83{
84    kAVCConcurrentWrites 	= 0x1,
85    kAVCMulticast 			= 0x2
86};
87
88enum
89{
90    ASYNCHRONOUS_CONNECTION	= 0x26,
91    ALLOCATE_ATTACH 		= 0x03,
92    DETACH_RELEASE 			= 0x07,
93    RESTORE_PORT 			= 0x40
94};
95
96#define AddressHi(poa) ((poa) & 0x0000ffff)
97#define AddressLo_PortBits(poa,pbits) ( ((poa) & 0xfffffffc) | ((pbits) & 0x00000003) )
98#define AddressLoToMaskedPortID(a) (0xffffffc3 | ((a) & 0x0000003c))
99#define Ex_ConnectionCount(ex,con) (((ex) << 7) | ((con) & 0x3f))
100#define WriteInterval_RetryCount(wi,rc) (((wi) << 4) | ((rc) & 0x0000000f))
101
102enum
103{
104    kAVCProducerRunBit 	= 0x00000020,
105    kAVCProducerHBBit	= 0x10000000,
106    kAVCProducerSCBit	= 0x01000000
107};
108
109#define oAPR(mode,count,flags,max) ( (flags) | (((mode) & 0x00000007) << 25) | \
110                    ((count) & 0x00ffffc0) | ((max) & 0x0000000f) )
111
112typedef struct
113{
114    UInt8	command_type;
115    UInt8	header_address;
116    UInt8	opcode;
117    UInt8	subfunction;
118    UInt8	status;
119    UInt8	plug_id;
120    UInt16	plug_offset_hi;
121    UInt32 	plug_offset_lo;
122    UInt16	connected_node_id;
123    UInt16	connected_plug_offset_hi;
124    UInt32	connected_plug_offset_lo;
125    UInt8	connected_plug_id;
126    UInt8	connection_count;
127    UInt8	write_interval_retry_count;
128    UInt8	reserved;
129} ACAVCCommand;
130
131//////////////////////////////////////////////////////////////////
132// static interface table
133//
134
135IOFireWireAVCLibConsumerInterface
136    IOFireWireAVCLibConsumer::sIOFireWireAVCLibConsumerInterface =
137{
138    0,
139	&IOFireWireAVCLibConsumer::queryInterface,
140	&IOFireWireAVCLibConsumer::comAddRef,
141	&IOFireWireAVCLibConsumer::comRelease,
142	1, 0, // version/revision
143    &IOFireWireAVCLibConsumer::setSubunit,
144    &IOFireWireAVCLibConsumer::setRemotePlug,
145    &IOFireWireAVCLibConsumer::connectToRemotePlug,
146    &IOFireWireAVCLibConsumer::disconnectFromRemotePlug,
147    &IOFireWireAVCLibConsumer::setFrameStatusHandler,
148    &IOFireWireAVCLibConsumer::frameProcessed,
149    &IOFireWireAVCLibConsumer::setMaxPayloadSize,
150    &IOFireWireAVCLibConsumer::setSegmentSize,
151    &IOFireWireAVCLibConsumer::getSegmentSize,
152    &IOFireWireAVCLibConsumer::getSegmentBuffer,
153    &IOFireWireAVCLibConsumer::setPortStateHandler,
154    &IOFireWireAVCLibConsumer::setPortFlags,
155    &IOFireWireAVCLibConsumer::clearPortFlags,
156    &IOFireWireAVCLibConsumer::getPortFlags
157};
158
159CFArrayCallBacks IOFireWireAVCLibConsumer::sArrayCallbacks =
160{
161	0,										// version
162	&IOFireWireAVCLibConsumer::cfAddRef, 	// retain
163   	&IOFireWireAVCLibConsumer::cfRelease, 	// release
164	NULL, 									// copyDescription
165    NULL,									// equal
166};
167
168//////////////////////////////////////////////////////////////////
169// creation and destruction
170//
171
172// ctor
173//
174//
175
176IOFireWireAVCLibConsumer::IOFireWireAVCLibConsumer( void )
177{
178	// create driver interface map
179	fIOFireWireAVCLibConsumerInterface.pseudoVTable = (IUnknownVTbl *) &sIOFireWireAVCLibConsumerInterface;
180	fIOFireWireAVCLibConsumerInterface.obj = this;
181
182	// init cf plugin ref counting
183	fRefCount = 0;
184
185    fAVCUnit 	= NULL;
186    fFWUnit 	= NULL;
187    fCFRunLoop	= NULL;
188    fService 	= NULL;
189
190	fGeneration	= 0;
191
192	fHeartbeatResponseSource = NULL;
193	fHeartbeatResponseSourceInfo = this;
194	fHeartbeatResponseScheduled = false;
195    fConsumerHeartbeatTimer = NULL;
196    fProducerHeartbeatTimer = NULL;
197    fReconnectTimer 		= NULL;
198
199    fFlags 				= 0;
200    fSubunit 			= 0;
201    fLocalPlugNumber	= 0;
202
203    fRemotePlugNumber 	= 0;
204    fRemotePlugAddress 	= 0;
205    fRemotePlugOptions 	= 0;
206
207    fMaxPayloadLog 		= 0x5; // min allowed by spec
208    fSegmentBitState	= true;
209    fHeartbeatBitState 	= false;
210    fMode				= 0;
211
212    fInputPlugRegisterBuffer 	= 0x00000000;
213    fOutputPlugRegisterBuffer	= 0x00000000;
214
215	fState 				= 0;
216    fStateHandlerRefcon	= 0;
217    fStateHandler 		= 0;
218
219    fSegmentSize 		= 0;
220    fSegmentBuffer		= NULL;
221    fPlugAddressSpace 	= NULL;
222
223    fFrameStatusSource = NULL;
224	fFrameStatusSourceInfo = this;
225	fFrameStatusSourceScheduled = false;
226    fFrameStatusHandler 		= NULL;
227    fFrameStatusHandlerRefcon 	= 0;
228
229	fDisconnectResponseSource = NULL;
230	fDisconnectResponseSourceInfo = this;
231	fDisconnectResponseScheduled = false;
232}
233
234// finalize
235//
236// we do the actual clean up in finalize, not in the destructor
237// this gets called before the AVCUnit calls the final CFRelease on us
238
239void IOFireWireAVCLibConsumer::finalize( void )
240{
241	//
242	// stop timers
243	//
244
245    stopReconnectTimer();
246    stopProducerHeartbeatTimer();
247	stopConsumerHeartbeatTimer();
248
249	//
250	// free the segment buffer and address space
251    //
252
253	releaseSegment();
254
255	//
256	// release our runloop sources
257	//
258
259	if( fHeartbeatResponseSource != NULL )
260	{
261		CFRunLoopSourceInvalidate( fHeartbeatResponseSource );
262		CFRelease( fHeartbeatResponseSource );
263		fHeartbeatResponseSource = NULL;
264	}
265
266	if( fFrameStatusSource != NULL )
267	{
268		CFRunLoopSourceInvalidate( fFrameStatusSource );
269		CFRelease( fFrameStatusSource );
270		fFrameStatusSource = NULL;
271	}
272
273	if( fDisconnectResponseSource != NULL )
274	{
275		CFRunLoopSourceInvalidate( fDisconnectResponseSource );
276		CFRelease( fDisconnectResponseSource );
277		fDisconnectResponseSource = NULL;
278	}
279
280	pthread_mutex_destroy( &fLock );
281
282	//
283	// release our interfaces
284	//
285
286	if( fFWUnit )
287    {
288		(*fFWUnit)->RemoveCallbackDispatcherFromRunLoop( fFWUnit );
289		(*fFWUnit)->Close( fFWUnit );
290        (*fFWUnit)->Release( fFWUnit );
291		fFWUnit = NULL;
292    }
293}
294
295// dtor
296//
297// clean up has already been done by finalize
298
299IOFireWireAVCLibConsumer::~IOFireWireAVCLibConsumer()
300{
301    if( fAVCUnit )
302    {
303        (*fAVCUnit)->Release( fAVCUnit );
304		fAVCUnit = NULL;
305    }
306}
307
308// alloc
309//
310// static allocator, called by factory method
311
312IUnknownVTbl ** IOFireWireAVCLibConsumer::alloc( IOFireWireAVCLibUnitInterface ** avcUnit,
313                                                 CFRunLoopRef cfRunLoop,
314                                                 UInt8 plugNumber )
315{
316    IOReturn					status = kIOReturnSuccess;
317	IOFireWireAVCLibConsumer *	me;
318	IUnknownVTbl ** 			interface = NULL;
319
320	if( status == kIOReturnSuccess )
321	{
322		me = new IOFireWireAVCLibConsumer();
323		if( me == NULL )
324			status = kIOReturnError;
325	}
326
327	if( status == kIOReturnSuccess )
328	{
329		status = me->init( avcUnit, cfRunLoop, plugNumber );
330	}
331
332	if( status != kIOReturnSuccess )
333		delete me;
334
335	if( status == kIOReturnSuccess )
336	{
337		// we return an interface here.
338        // queryInterface is not called in this case, so we call addRef here
339		IOFireWireAVCLibConsumer::addRef(me);
340		interface = (IUnknownVTbl **) &me->fIOFireWireAVCLibConsumerInterface.pseudoVTable;
341	}
342
343	return interface;
344}
345
346// init
347//
348// initialize our object, called by alloc()
349
350IOReturn IOFireWireAVCLibConsumer::init( IOFireWireAVCLibUnitInterface ** avcUnit,
351                                         CFRunLoopRef cfRunLoop,
352                                         UInt8 plugNumber )
353{
354	IOReturn status = kIOReturnSuccess;
355
356	if( avcUnit == NULL || cfRunLoop == NULL ||
357		plugNumber < kFWAVCAsyncPlug0 || plugNumber > kFWAVCAsyncPlug30 )
358	{
359		status = kIOReturnBadArgument;
360	}
361
362	if( status == kIOReturnSuccess )
363	{
364		fAVCUnit = avcUnit;
365		(*fAVCUnit)->AddRef( fAVCUnit );
366
367		fCFRunLoop = cfRunLoop;
368		fLocalPlugNumber = plugNumber;
369
370		pthread_mutex_init( &fLock, NULL );
371	}
372
373	if( status == kIOReturnSuccess )
374	{
375		// fDisconnectResponseSourceInfo points to "this" because CF uses the info pointer
376		// to determine if CF runloop sources are the same
377		CFRunLoopSourceContext	context = { 0, &fDisconnectResponseSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendDisconnectResponse };
378		fDisconnectResponseSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context );
379		if( fDisconnectResponseSource == NULL )
380			status = kIOReturnNoMemory;
381	}
382
383	if( status == kIOReturnSuccess )
384	{
385		CFRunLoopAddSource( fCFRunLoop, fDisconnectResponseSource, kCFRunLoopDefaultMode );
386	}
387
388    if( status == kIOReturnSuccess )
389	{
390		// fFrameStatusSourceInfo points to "this" because CF uses the info pointer
391		// to determine if CF runloop sources are the same
392		CFRunLoopSourceContext	context = { 0, &fFrameStatusSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendFrameStatusNotification };
393		fFrameStatusSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context );
394		if( fFrameStatusSource == NULL )
395			status = kIOReturnNoMemory;
396	}
397
398	if( status == kIOReturnSuccess )
399	{
400		CFRunLoopAddSource( fCFRunLoop, fFrameStatusSource, kCFRunLoopDefaultMode );
401	}
402
403	if( status == kIOReturnSuccess )
404	{
405		// fHeartbeatResponseSourceInfo points to "this" because CF uses the info pointer
406		// to determine if CF runloop sources are the same
407		CFRunLoopSourceContext	context = { 0, &fHeartbeatResponseSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendHeartbeatResponse };
408		fHeartbeatResponseSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context );
409		if( fHeartbeatResponseSource == NULL )
410			status = kIOReturnNoMemory;
411	}
412
413	if( status == kIOReturnSuccess )
414	{
415		CFRunLoopAddSource( fCFRunLoop, fHeartbeatResponseSource, kCFRunLoopDefaultMode );
416	}
417
418	if( status == kIOReturnSuccess )
419	{
420		fFWUnit = (IOFireWireDeviceInterface**)(*fAVCUnit)->getAncestorInterface( fAVCUnit,
421									(char*)"IOFireWireUnit",
422									CFUUIDGetUUIDBytes(kIOFireWireLibTypeID),
423									CFUUIDGetUUIDBytes(kIOFireWireDeviceInterfaceID) );
424		if( fFWUnit == NULL )
425			status = kIOReturnNoMemory;
426	}
427
428	if( status == kIOReturnSuccess )
429	{
430		(*fFWUnit)->AddRef( fFWUnit );
431	}
432
433	IOFireWireSessionRef sessionRef = 0;
434
435	if( status == kIOReturnSuccess )
436	{
437        sessionRef = (*fAVCUnit)->getSessionRef( fAVCUnit );
438        if( sessionRef == 0 )
439            status = kIOReturnError;
440    }
441
442    // open
443    if( status == kIOReturnSuccess )
444    {
445		status = (*fFWUnit)->OpenWithSessionRef( fFWUnit, sessionRef );
446	}
447
448	FWLOG(( "IOFireWireAVCLibConsumer::init OpenWithSessionRef return status = 0x%08x\n", status ));
449
450	if( status == kIOReturnSuccess )
451	{
452		status = (*fFWUnit)->AddCallbackDispatcherToRunLoop( fFWUnit, fCFRunLoop );
453	}
454
455	if( status == kIOReturnSuccess )
456	{
457		fService = (*fFWUnit)->GetDevice( fFWUnit );
458		if( fService == (io_object_t)NULL )
459			status = kIOReturnError;
460	}
461
462	if( status == kIOReturnSuccess )
463	{
464		if( isDeviceSuspended( fAVCUnit ) )
465		{
466			fState = kFWAVCStatePrivBusSuspended;
467		}
468		else
469		{
470			fState = kFWAVCStatePrivBusResumed;
471		}
472    }
473
474	FWLOG(( "IOFireWireAVCLibConsumer::init return status = 0x%08lx\n", (UInt32)status ));
475
476    return status;
477}
478
479// queryInterface
480//
481//
482
483HRESULT IOFireWireAVCLibConsumer::queryInterface( void * self, REFIID iid, void **ppv )
484{
485    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
486    HRESULT result = S_OK;
487    IOFireWireAVCLibConsumer * me = getThis(self);
488
489//    FWLOG(( "IOFireWireAVCLibConsumer::queryInterface start\n" ));
490
491	if( CFEqual(uuid, IUnknownUUID) ||  CFEqual(uuid, kIOFireWireAVCLibConsumerInterfaceID) )
492	{
493        *ppv = &me->fIOFireWireAVCLibConsumerInterface;
494        comAddRef(self);
495    }
496    else
497        *ppv = 0;
498
499    if( !*ppv )
500        result = E_NOINTERFACE;
501
502    CFRelease( uuid );
503
504 //   FWLOG(( "IOFireWireAVCLibConsumer::queryInterface stop\n" ));
505
506    return result;
507}
508
509//////////////////////////////////////////////////////////////////
510// reference counting
511//
512// cf and com have different reference counting methods
513// we call a shared method to actually do the work
514
515// addRef
516//
517//
518
519const void * IOFireWireAVCLibConsumer::cfAddRef( CFAllocatorRef allocator, const void *value )
520{
521    IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)value;
522    IOFireWireAVCLibConsumer::addRef( me );
523    return value;
524}
525
526UInt32 IOFireWireAVCLibConsumer::comAddRef( void * self )
527{
528    IOFireWireAVCLibConsumer * me = getThis(self);
529    return IOFireWireAVCLibConsumer::addRef( me );
530}
531
532UInt32 IOFireWireAVCLibConsumer::addRef( IOFireWireAVCLibConsumer * me )
533{
534	me->fRefCount++;
535	return me->fRefCount;
536}
537
538// release
539//
540//
541
542void IOFireWireAVCLibConsumer::cfRelease( CFAllocatorRef allocator, const void *value )
543{
544    IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)value;
545    IOFireWireAVCLibConsumer::release( me );
546}
547
548UInt32 IOFireWireAVCLibConsumer::comRelease( void * self )
549{
550    IOFireWireAVCLibConsumer * me = getThis(self);
551    return IOFireWireAVCLibConsumer::release( me );
552}
553
554UInt32 IOFireWireAVCLibConsumer::release( IOFireWireAVCLibConsumer * me )
555{
556	UInt32 retVal = me->fRefCount;
557
558    me->fRefCount--;
559
560    if( 0 == me->fRefCount  )
561	{
562        delete me;
563    }
564	else if( 1 == me->fRefCount )
565	{
566        // clean up before we tell the AVCUnit to let us go
567		me->finalize();
568
569        // unit is last reference, inform it of this fact
570        consumerPlugDestroyed( me->fAVCUnit, me );
571    }
572    else if( me->fRefCount < 0 )
573	{
574        me->fRefCount = 0;
575	}
576
577	return retVal;
578}
579
580//////////////////////////////////////////////////////////////////
581// accessors
582//
583
584// getNodeIDsAndGeneration
585//
586// returns the local and remote node ids and the generation for which they are valid
587
588IOReturn IOFireWireAVCLibConsumer::getNodeIDsAndGeneration( UInt16 * local, UInt16 * remote, UInt32 * gen )
589{
590    IOReturn status = kIOReturnSuccess;
591
592    UInt16 localNodeID;
593    UInt16 remoteNodeID;
594	UInt32 firstGen, secondGen;
595
596    // these routines only return errors if there is something wrong with the user client's
597    // connection to the kernel
598
599	// 1. get generation and remote nodeID
600    // 2. get local nodeID
601	// 3. get generation again
602	// 4. repeat if the generation has changed
603
604	do
605    {
606        if( status == kIOReturnSuccess )
607        {
608            status = (*fFWUnit)->GetGenerationAndNodeID( fFWUnit, &firstGen, &remoteNodeID );
609        }
610
611        if( status == kIOReturnSuccess )
612        {
613            status = (*fFWUnit)->GetLocalNodeID( fFWUnit, &localNodeID );
614        }
615
616        if( status == kIOReturnSuccess )
617        {
618            status = (*fFWUnit)->GetGenerationAndNodeID( fFWUnit, &secondGen, &remoteNodeID );
619        }
620
621    } while( firstGen != secondGen && status == kIOReturnSuccess );
622
623    if( status == kIOReturnSuccess )
624    {
625        *remote = remoteNodeID;
626        *local = localNodeID;
627        *gen = firstGen;
628    }
629
630    return status;
631}
632
633// setSubunit
634//
635//
636
637void IOFireWireAVCLibConsumer::setSubunit( void * self, UInt8 subunit )
638{
639    IOFireWireAVCLibConsumer * me = getThis(self);
640
641    me->fSubunit = subunit;
642}
643
644// setRemotePlug
645//
646//
647
648void IOFireWireAVCLibConsumer::setRemotePlug( void * self, UInt8 plugNumber )
649{
650    IOFireWireAVCLibConsumer * me = getThis(self);
651
652    me->fRemotePlugNumber = plugNumber;
653}
654
655// setMaxPayloadSize
656//
657//
658
659void IOFireWireAVCLibConsumer::setMaxPayloadSize( void * self, UInt32 size )
660{
661    IOFireWireAVCLibConsumer * me = getThis(self);
662    UInt32 sizeBytes = size;
663
664    me->fMaxPayloadLog = 0x0;
665    while( (sizeBytes >= 0x4) && (me->fMaxPayloadLog < 0xa) )
666    {
667        sizeBytes >>= 1;
668        me->fMaxPayloadLog++;
669    }
670
671    // spec says maxPayloadLog shall not be less than 5
672    if( me->fMaxPayloadLog < 0x5 )
673        me->fMaxPayloadLog = 0x5;
674}
675
676//////////////////////////////////////////////////////////////////
677// connection management
678//
679
680// connectToRemotePlug
681//
682// public connection method
683
684IOReturn IOFireWireAVCLibConsumer::connectToRemotePlug( void * self )
685{
686    IOFireWireAVCLibConsumer * me = getThis(self);
687    IOReturn status = kIOReturnSuccess;
688
689	pthread_mutex_lock( &me->fLock );
690
691    FWLOG(( "IOFireWireAVCLibConsumer::connectToRemotePlug\n" ));
692
693    if( me->fState != kFWAVCStatePrivBusResumed )
694    {
695        status = kIOReturnNotReady;
696    }
697
698	if( me->fRemotePlugNumber < kFWAVCAsyncPlug0 || me->fRemotePlugNumber > kFWAVCAsyncPlugAny )
699	{
700		status = kIOReturnNoResources;
701	}
702
703    if( me->fPlugAddressSpace == NULL )
704    {
705        status = kIOReturnNoResources;
706    }
707
708	if( status == kIOReturnSuccess )
709    {
710		FWLOG(( "IOFireWireAVCLibConsumer::connectToRemotePlug attempt to connect to device...\n" ));
711		UInt32 tries = 11;  // reconnect timeout is 10 seconds
712		do
713		{
714			status = me->doConnectToRemotePlug();
715			if( status != kIOReturnSuccess )
716			{
717				FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug connect to device failed with status = 0x%08lx\n", (UInt32)status ));
718				if( tries > 1 )
719				{
720					// sleep for 1 second before retrying
721					usleep( 1 * 1000000 );
722					FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug retrying connect to device...\n" ));
723				}
724			}
725		}
726		while( status != kIOReturnSuccess && --tries );
727	}
728
729	FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug return status = 0x%08lx\n", (UInt32)status ));
730
731	pthread_mutex_unlock( &me->fLock );
732
733	return status;
734}
735
736// doConnectToRemotePlug
737//
738// internal connection routine
739
740IOReturn IOFireWireAVCLibConsumer::doConnectToRemotePlug( void )
741{
742    IOReturn status = kIOReturnSuccess;
743
744    FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug\n" ));
745
746    FWAddress		address;
747
748    if( status == kIOReturnSuccess )
749    {
750        (*fPlugAddressSpace)->GetFWAddress( fPlugAddressSpace, &address );
751    }
752
753    UInt16 			localNodeID;
754    UInt16			remoteNodeID;
755    UInt32			generation;
756
757    if( status == kIOReturnSuccess )
758    {
759        status = getNodeIDsAndGeneration( &localNodeID, &remoteNodeID, &generation );
760    }
761
762    ACAVCCommand	cmd;
763    ACAVCCommand	response;
764
765    if( status == kIOReturnSuccess )
766    {
767        // send ALLOCATE_ATTACH to remote subunit
768
769        cmd.command_type 				= 0x00; 					// CT/RC = Control command
770        cmd.header_address 				= kAVCUnitAddress;  		// HA = unit
771        cmd.opcode 						= ASYNCHRONOUS_CONNECTION;	// Opcode = ASYNCHRONOUS_CONNECTION
772        cmd.subfunction 				= ALLOCATE_ATTACH;			// Subfunction = ALLOCATE_ATTACH
773        cmd.status 						= 0xff;						// status = N/A
774        cmd.plug_id 					= fRemotePlugNumber;		// plugID = plug number
775        cmd.plug_offset_hi 				= OSSwapHostToBigInt16(0xffff);
776        cmd.plug_offset_lo 				= OSSwapHostToBigInt32(0xffffffff);		// any producer port
777        cmd.connected_node_id 			= OSSwapHostToBigInt16(0xffc0 | localNodeID);
778        cmd.connected_plug_offset_hi	= OSSwapHostToBigInt16(AddressHi(address.addressHi));
779        cmd.connected_plug_offset_lo	= OSSwapHostToBigInt32(AddressLo_PortBits(address.addressLo, kAVCConcurrentWrites | kAVCMulticast ));
780        cmd.connected_plug_id			= fLocalPlugNumber;
781        cmd.connection_count			= Ex_ConnectionCount(0x1,0x3f);
782        cmd.write_interval_retry_count 	= WriteInterval_RetryCount(0x00,0x00);
783        cmd.reserved				 	= 0x00;
784    }
785
786    FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug avc command\n" ));
787
788    UInt32 responseLength = sizeof(response);
789    if( status == kIOReturnSuccess )
790    {
791        status = (*fAVCUnit)->AVCCommandInGeneration( fAVCUnit, generation, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength );
792
793		// Fix up endian issues here!
794		if (responseLength >= sizeof(ACAVCCommand))
795		{
796			response.plug_offset_hi = OSSwapBigToHostInt16(response.plug_offset_hi);
797			response.plug_offset_lo = OSSwapBigToHostInt32(response.plug_offset_lo);
798			response.connected_node_id = OSSwapBigToHostInt16(response.connected_node_id);
799			response.connected_plug_offset_hi = OSSwapBigToHostInt16(response.connected_plug_offset_hi);
800			response.connected_plug_offset_lo = OSSwapBigToHostInt32(response.connected_plug_offset_lo);
801		}
802    }
803
804    if( status == kIOReturnSuccess )
805    {
806        if( response.status != 0x03 )
807            status = kIOReturnDeviceError;
808    }
809
810    if( status == kIOReturnSuccess )
811    {
812        fRemotePlugNumber = response.plug_id;
813        fRemotePlugAddress.addressHi = response.plug_offset_hi;
814        fRemotePlugAddress.addressLo = response.plug_offset_lo & 0xfffffffc;
815        fRemotePlugOptions = response.plug_offset_lo & 0x00000003;
816    }
817
818    // set run bit in producer plug
819    UInt32 newVal = 0;
820
821    if( status == kIOReturnSuccess )
822    {
823		fOutputPlugRegisterBuffer = 0x00000000;
824		fInputPlugRegisterBuffer = 0x00000000;
825		fSegmentBitState = true;
826		fHeartbeatBitState = false;
827    }
828
829    if( status == kIOReturnSuccess )
830    {
831		FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug run bit\n" ));
832		// oAPR( mode, count, flags, maxLoad )
833		UInt32 flags = 	kAVCProducerRunBit |
834						(fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
835						(fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
836		newVal = oAPR( kFWAVCProducerMode_SEND, fSegmentSize, flags, fMaxPayloadLog );
837		status = updateProducerRegister( newVal, generation );
838	}
839
840    if( status == kIOReturnSuccess )
841    {
842        fState = kFWAVCStatePrivPlugConnected;
843        fGeneration = generation;
844        fMode = kFWAVCProducerMode_SEND;
845        startProducerHeartbeatTimer();
846    }
847
848    FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug status = 0x%08lx\n", (UInt32)status ));
849
850    return status;
851}
852
853// disconnectFromRemotePlug
854//
855//
856
857IOReturn IOFireWireAVCLibConsumer::disconnectFromRemotePlug( void * self )
858{
859    IOFireWireAVCLibConsumer * me = getThis(self);
860    IOReturn status = kIOReturnSuccess;
861
862	pthread_mutex_lock( &me->fLock );
863
864    switch( me->fState )
865    {
866        case kFWAVCStatePrivPlugSuspended:
867
868            // don't reconnect if we get a resume message
869
870            me->stopReconnectTimer();
871
872			// neither of the heartbeat timers should be running
873
874			if( me->fProducerHeartbeatTimer != NULL || me->fConsumerHeartbeatTimer != NULL )
875			{
876				printf( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug heartbeat timers set while plug is suspended!\n" );
877			}
878
879            me->fState = kFWAVCStatePrivBusSuspended;
880
881            break;
882
883        case kFWAVCStatePrivPlugConnected:
884
885            ACAVCCommand	cmd;
886            ACAVCCommand	response;
887            UInt32 			responseLength;
888
889			// the reconnect timer should not be running
890
891			if( me->fReconnectTimer != NULL )
892			{
893				printf( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug reconnect timer set while plug is resumed!\n" );
894			}
895
896            me->stopProducerHeartbeatTimer();
897            me->stopConsumerHeartbeatTimer();
898
899            if( status == kIOReturnSuccess )
900            {
901                // send DETACH_RELEASE to remote unit
902
903                cmd.command_type 				= 0x00; 					// CT/RC = Control command
904                cmd.header_address 				= kAVCUnitAddress;  		// HA = unit
905                cmd.opcode 						= ASYNCHRONOUS_CONNECTION;	// Opcode = ASYNCHRONOUS_CONNECTION
906                cmd.subfunction 				= DETACH_RELEASE;			// Subfunction = DETACH_RELEASE
907                cmd.status 						= 0xff;						// status = N/A
908                cmd.plug_id 					= me->fRemotePlugNumber;	// plugID = plug number
909                cmd.plug_offset_hi 				= OSSwapHostToBigInt16(0xffff);
910                cmd.plug_offset_lo 				= OSSwapHostToBigInt32(AddressLoToMaskedPortID(me->fRemotePlugAddress.addressLo));
911                cmd.connected_node_id 			= OSSwapHostToBigInt16(0xffff);
912                cmd.connected_plug_offset_hi	= OSSwapHostToBigInt16(0xffff);
913                cmd.connected_plug_offset_lo	= OSSwapHostToBigInt32(0xffffffff);
914                cmd.connected_plug_id			= 0xff;
915                cmd.connection_count			= Ex_ConnectionCount(0x1,0x3f);
916                cmd.write_interval_retry_count 	= WriteInterval_RetryCount(0xf,0xf);
917                cmd.reserved				 	= 0x00;
918            }
919
920            if( status == kIOReturnSuccess )
921            {
922                responseLength = sizeof(response);
923				status = (*me->fAVCUnit)->AVCCommandInGeneration( me->fAVCUnit, me->fGeneration, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength );
924
925				// Fix up endian issues here!
926				if (responseLength >= sizeof(ACAVCCommand))
927				{
928					response.plug_offset_hi = OSSwapBigToHostInt16(response.plug_offset_hi);
929					response.plug_offset_lo = OSSwapBigToHostInt32(response.plug_offset_lo);
930					response.connected_node_id = OSSwapBigToHostInt16(response.connected_node_id);
931					response.connected_plug_offset_hi = OSSwapBigToHostInt16(response.connected_plug_offset_hi);
932					response.connected_plug_offset_lo = OSSwapBigToHostInt32(response.connected_plug_offset_lo);
933				}
934            }
935
936			if( status == kIOFireWireBusReset )
937			{
938				// bus reset occured while disconnecting.
939				// as long as we don't reconnect we will be disconnected, so ignore the error
940
941				// this also means we cannot connect until the reconnect period is over
942
943				status = kIOReturnSuccess;
944			}
945			else if( status == kIOReturnSuccess )
946            {
947                if( response.status != 0x01 )
948                {
949					// if the device gave us an error on disconnect, it probably
950					// already thinks we're disconnected, so ignore the error
951
952					FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug disconnect AVCCommand returned response.status = 0x%02x\n", response.status ));
953				}
954			}
955			else
956			{
957				FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug disconnect AVCCommand status = 0x%08lx\n", (UInt32)status ));
958
959				// what do we do about this?
960				// figure we're disconnected even if we got an error!?
961
962				status = kIOReturnSuccess;
963			}
964
965			if( status == kIOReturnSuccess )
966			{
967				me->fState = kFWAVCStatePrivBusResumed;
968				me->fInputPlugRegisterBuffer = 0x00000000;
969			}
970
971            break;
972
973        default:
974
975            // we're in a state we can't disconnect from
976            status = kIOReturnNotPermitted;
977
978            break;
979
980    }
981
982	FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug status = 0x%08lx\n", (UInt32)status ));
983
984	pthread_mutex_unlock( &me->fLock );
985
986    return status;
987}
988
989// forciblyDisconnected
990//
991// notifies clients of a forced disconnection
992
993void IOFireWireAVCLibConsumer::forciblyDisconnected( void )
994{
995	fInputPlugRegisterBuffer = 0x00000000;
996
997    switch( fState )
998    {
999		case kFWAVCStatePrivPlugSuspended:
1000
1001			fState = kFWAVCStatePrivBusSuspended;
1002
1003            pthread_mutex_unlock( &fLock );
1004
1005			if( fStateHandler )
1006            {
1007                (fStateHandler)(fStateHandlerRefcon, kFWAVCStatePlugDisconnected );
1008            }
1009
1010			break;
1011
1012        case kFWAVCStatePrivPlugConnected:
1013
1014			fState = kFWAVCStatePrivBusResumed;
1015
1016            pthread_mutex_unlock( &fLock );
1017
1018            if( fStateHandler )
1019            {
1020                (fStateHandler)(fStateHandlerRefcon, kFWAVCStatePlugDisconnected );
1021            }
1022
1023			break;
1024
1025        default:
1026
1027            pthread_mutex_unlock( &fLock );
1028
1029            FWLOG(( "IOFireWireAVCLibConsumer::forciblyDisconnected we're in an unexpected state = 0x%08lx.\n", fState ));
1030            break;
1031    }
1032}
1033
1034// setPortStateHandler
1035//
1036//
1037
1038void IOFireWireAVCLibConsumer::setPortStateHandler( void * self, void * refcon, IOFireWireAVCPortStateHandler handler )
1039{
1040    IOFireWireAVCLibConsumer * me = getThis(self);
1041
1042    me->fStateHandlerRefcon = refcon;
1043    me->fStateHandler = handler;
1044}
1045
1046// deviceInterestCallback
1047//
1048//
1049
1050void IOFireWireAVCLibConsumer::deviceInterestCallback( natural_t type, void * arg )
1051{
1052    IOReturn status = kIOReturnSuccess;
1053
1054	switch( type )
1055	{
1056        case kIOMessageServiceIsSuspended:
1057
1058            FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsSuspended bus reset start\n" ));
1059
1060            pthread_mutex_lock( &fLock );
1061
1062            switch ( fState )
1063            {
1064				case kFWAVCStatePrivBusResumed:
1065
1066                    fState = kFWAVCStatePrivBusSuspended;
1067
1068                    pthread_mutex_unlock( &fLock );
1069
1070                    if( fStateHandler )
1071                    {
1072                        (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusSuspended );
1073                    }
1074
1075                    break;
1076
1077				case kFWAVCStatePrivPlugSuspended:
1078
1079					// restart reconnect timer
1080					startReconnectTimer();
1081
1082                    pthread_mutex_unlock( &fLock );
1083
1084					break;
1085
1086                case kFWAVCStatePrivPlugConnected:
1087
1088                    fState = kFWAVCStatePrivPlugSuspended;
1089
1090					// these values reset on bus resets
1091					fOutputPlugRegisterBuffer &= ~(kAVCProducerRunBit | kAVCProducerHBBit);
1092                    fInputPlugRegisterBuffer &= ~kFWAVCConsumerPlugHBMask;
1093					fHeartbeatBitState = false;
1094
1095                    stopProducerHeartbeatTimer();
1096                    stopConsumerHeartbeatTimer();
1097                    startReconnectTimer();
1098
1099                    pthread_mutex_unlock( &fLock );
1100
1101                    if( fStateHandler )
1102                    {
1103                        (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusSuspended );
1104                    }
1105
1106                    break;
1107
1108				case kFWAVCStatePrivBusSuspended:
1109                default:
1110                    pthread_mutex_unlock( &fLock );
1111					// do nothing
1112                    break;
1113
1114			}
1115
1116            break;
1117
1118        case kIOMessageServiceIsResumed:
1119
1120            FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsResumed bus reset complete\n" ));
1121
1122            pthread_mutex_lock( &fLock );
1123
1124            switch ( fState )
1125            {
1126                case kFWAVCStatePrivBusSuspended:
1127
1128                    fState = kFWAVCStatePrivBusResumed;
1129
1130                    pthread_mutex_unlock( &fLock );
1131
1132                    if( fStateHandler )
1133                    {
1134                        (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusResumed );
1135                    }
1136
1137                    break;
1138
1139                case kFWAVCStatePrivPlugSuspended:
1140
1141                    pthread_mutex_unlock( &fLock );
1142
1143                    if( fStateHandler )
1144                    {
1145                        (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusResumed );
1146                    }
1147
1148					pthread_mutex_lock( &fLock );
1149
1150					stopReconnectTimer();
1151
1152                    UInt16 			localNodeID;
1153                    UInt16			remoteNodeID;
1154                    UInt32			generation;
1155
1156                    if( status == kIOReturnSuccess )
1157                    {
1158                        status = getNodeIDsAndGeneration( &localNodeID, &remoteNodeID, &generation );
1159                    }
1160
1161                    if( status == kIOReturnSuccess )
1162                    {
1163                        if( generation == fGeneration )
1164                        {
1165                            // we've already connected on this generation, no need to reconnect
1166                            // this can happen if we get two (or more) bus rests in a row and
1167                            // while handling the first one we latched the generation of the second
1168                        }
1169                        else
1170                        {
1171                            ACAVCCommand	cmd;
1172                            ACAVCCommand	response;
1173
1174                            if( status == kIOReturnSuccess )
1175                            {
1176                                // send RESTORE_PORT to remote unit
1177
1178                                cmd.command_type 				= 0x00; 					// CT/RC = Control command
1179                                cmd.header_address 				= kAVCUnitAddress;  		// HA = unit
1180                                cmd.opcode 						= ASYNCHRONOUS_CONNECTION;	// Opcode = ASYNCHRONOUS_CONNECTION
1181                                cmd.subfunction 				= RESTORE_PORT;				// Subfunction = RESTORE_PORT
1182                                cmd.status 						= 0xff;						// status = N/A
1183                                cmd.plug_id 					= fRemotePlugNumber;		// plugID = plug number
1184                                cmd.plug_offset_hi 				= OSSwapHostToBigInt16(0xffff);
1185                                cmd.plug_offset_lo 				= OSSwapHostToBigInt32(AddressLoToMaskedPortID(fRemotePlugAddress.addressLo));
1186                                cmd.connected_node_id 			= OSSwapHostToBigInt16(0xffc0 | localNodeID);
1187                                cmd.connected_plug_offset_hi	= OSSwapHostToBigInt16(0xffff);
1188                                cmd.connected_plug_offset_lo	= OSSwapHostToBigInt32(AddressLoToMaskedPortID(0x00000000));
1189                                cmd.connected_plug_id			= 0xff;
1190                                cmd.connection_count			= Ex_ConnectionCount(0x1,0x3f);
1191                                cmd.write_interval_retry_count 	= WriteInterval_RetryCount(0xf,0xf);
1192                                cmd.reserved				 	= 0x00;
1193                            }
1194
1195                            UInt32 responseLength = sizeof(response);
1196                            if( status == kIOReturnSuccess )
1197                            {
1198                                status = (*fAVCUnit)->AVCCommandInGeneration( fAVCUnit, generation, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength );
1199
1200								// Fix up endian issues here!
1201								if (responseLength >= sizeof(ACAVCCommand))
1202								{
1203									response.plug_offset_hi = OSSwapBigToHostInt16(response.plug_offset_hi);
1204									response.plug_offset_lo = OSSwapBigToHostInt32(response.plug_offset_lo);
1205									response.connected_node_id = OSSwapBigToHostInt16(response.connected_node_id);
1206									response.connected_plug_offset_hi = OSSwapBigToHostInt16(response.connected_plug_offset_hi);
1207									response.connected_plug_offset_lo = OSSwapBigToHostInt32(response.connected_plug_offset_lo);
1208								}
1209                            }
1210
1211							if( status == kIOReturnSuccess )
1212                            {
1213                                if( response.status != 0x03 )
1214                                    status = kIOReturnDeviceError;
1215                            }
1216
1217                            if( status == kIOReturnSuccess )
1218                            {
1219                                fRemotePlugNumber = response.plug_id;
1220                                fRemotePlugAddress.addressHi = response.plug_offset_hi;
1221                                fRemotePlugAddress.addressLo = response.plug_offset_lo & 0xfffffffc;
1222                                fRemotePlugOptions = response.plug_offset_lo & 0x00000003;
1223							}
1224
1225							if( fHeartbeatBitState ||
1226								(fOutputPlugRegisterBuffer & (kAVCProducerRunBit | kAVCProducerHBBit)) ||
1227								(fInputPlugRegisterBuffer & kFWAVCConsumerPlugHBMask) )
1228							{
1229								printf( "IOFireWireAVCLibConsumer::deviceInterestCallback register values not reset!\n" );
1230							}
1231
1232                            // set run bit in producer register
1233
1234                            UInt32 newVal = 0;
1235
1236							if( status == kIOReturnSuccess )
1237							{
1238								// oAPR( mode, count, flags, maxLoad )
1239								UInt32 flags = 	kAVCProducerRunBit |
1240												(fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
1241												(fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
1242								newVal = oAPR( kFWAVCProducerMode_SEND, fSegmentSize, flags, fMaxPayloadLog );
1243								status = updateProducerRegister( newVal, generation );
1244							}
1245
1246                            if( status == kIOReturnSuccess )
1247                            {
1248                                fMode = kFWAVCProducerMode_SEND;
1249                                 startProducerHeartbeatTimer();
1250                            }
1251
1252                        } // generation if
1253
1254                    } // status if
1255
1256                    if( status == kIOReturnSuccess )
1257                    {
1258                        fState = kFWAVCStatePrivPlugConnected;
1259                        fGeneration = generation;
1260
1261					}
1262
1263					if( status == kIOReturnSuccess )
1264					{
1265                        pthread_mutex_unlock( &fLock );
1266
1267                        if( fStateHandler )
1268                        {
1269                            (fStateHandler)( fStateHandlerRefcon, kFWAVCStatePlugReconnected );
1270                        }
1271                    }
1272					else if( status == kIOFireWireBusReset )
1273					{
1274						// this means our attempt to reconnect was interupted by a bus reset
1275						// that means we will start the reconnect process over and don't need to do anything here
1276                        pthread_mutex_unlock( &fLock );
1277
1278					}
1279                    else
1280                    {
1281						FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback failed to reconnect - forciblyDisconnecting\n" ));
1282
1283						forciblyDisconnected();
1284                    }
1285
1286                    break;
1287
1288                case kIOFWMessageServiceIsRequestingClose:
1289                    FWLOG(( "IOFireWireAVCLibConsumer::kIOFWMessageServiceIsRequestingClose (device removed)\n" ));
1290
1291                    pthread_mutex_lock( &fLock );
1292
1293                    switch ( fState )
1294                    {
1295                        case kFWAVCStatePrivBusSuspended:
1296
1297                            pthread_mutex_unlock( &fLock );
1298
1299                            if( fStateHandler )
1300                            {
1301                                (fStateHandler)( fStateHandlerRefcon, kFWAVCStateDeviceRemoved );
1302                            }
1303
1304                            break;
1305
1306                        case kFWAVCStatePrivPlugSuspended:
1307
1308							FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback device unplugged - forciblyDisconnecting\n" ));
1309
1310							forciblyDisconnected();
1311
1312                            if( fStateHandler )
1313                            {
1314                                (fStateHandler)( fStateHandlerRefcon, kFWAVCStateDeviceRemoved );
1315                            }
1316
1317                            break;
1318
1319                        default:
1320                            FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback kIOFWMessageServiceIsRequestingClose in odd state, fState = 0x%08lx/n", fState ));
1321                            break;
1322                    }
1323
1324
1325                    break;
1326
1327                case kIOMessageServiceIsTerminated:
1328                    FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsTerminated (device removed)\n" ));
1329                    break;
1330
1331                default:
1332                    FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback kIOMessageServiceIsResumed in odd state, fState = 0x%08lx/n", fState ));
1333                    break;
1334            }
1335            break;
1336
1337        default:
1338			break;
1339	}
1340}
1341
1342// startReconnectTimer
1343//
1344//
1345
1346void IOFireWireAVCLibConsumer::startReconnectTimer( void  )
1347{
1348	CFRunLoopTimerContext		context;
1349	CFAbsoluteTime				time;
1350
1351    // stop if necessary
1352    stopReconnectTimer();
1353
1354    context.version             = 0;
1355    context.info                = this;
1356    context.retain              = NULL;
1357    context.release             = NULL;
1358    context.copyDescription     = NULL;
1359
1360    time = CFAbsoluteTimeGetCurrent() + kReconnectTime;
1361
1362    fReconnectTimer = CFRunLoopTimerCreate(NULL, time,
1363                                    0,
1364                                    0,
1365                                    0,
1366                                    (CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::reconnectTimeoutProc,
1367                                    &context);
1368
1369	if ( fReconnectTimer )
1370	{
1371		CFRunLoopAddTimer( fCFRunLoop, fReconnectTimer, kCFRunLoopDefaultMode );
1372	}
1373}
1374
1375// reconnectTimeoutProc
1376//
1377//
1378
1379void IOFireWireAVCLibConsumer::reconnectTimeoutProc( CFRunLoopTimerRef timer, void *data )
1380{
1381	IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data;
1382
1383    pthread_mutex_lock( &me->fLock );
1384
1385    me->stopReconnectTimer();
1386
1387	FWLOG(( "IOFireWireAVCLibConsumer::reconnectTimeoutProc reconnect timed out - forciblyDisconnecting\n" ));
1388
1389	me->forciblyDisconnected();
1390}
1391
1392// stopReconnectTimer
1393//
1394//
1395
1396void IOFireWireAVCLibConsumer::stopReconnectTimer( void )
1397{
1398	if ( fReconnectTimer )
1399	{
1400		CFRunLoopTimerInvalidate( fReconnectTimer );
1401		CFRelease( fReconnectTimer );
1402		fReconnectTimer = NULL;
1403	}
1404}
1405
1406//////////////////////////////////////////////////////////////////
1407// segment buffer allocation
1408//
1409
1410// setSegmentSize
1411//
1412//
1413
1414IOReturn IOFireWireAVCLibConsumer::setSegmentSize( void * self, UInt32 size )
1415{
1416    IOFireWireAVCLibConsumer * me = getThis(self);
1417    IOReturn status = kIOReturnSuccess;
1418
1419	if( size > 0x00ffffff || (size & 0x0000003f) != 0 )
1420	{
1421		return kIOReturnBadArgument;
1422	}
1423
1424    // free previous address space
1425	me->releaseSegment();
1426
1427    // new segment buffer
1428    me->fSegmentBuffer = (char*)malloc( size + 64 );
1429    if( me->fSegmentBuffer == NULL )
1430        status = kIOReturnNoMemory;
1431
1432    if( status == kIOReturnSuccess )
1433    {
1434        me->fSegmentSize = size;
1435
1436        // new psuedo address space
1437        me->fPlugAddressSpace = (*me->fFWUnit)->CreatePseudoAddressSpace( me->fFWUnit, me->fSegmentSize + 64,
1438                                                                          me, (me->fSegmentSize + 64) * 2,
1439                                                                          me->fSegmentBuffer,
1440                                                                          kFWAddressSpaceNoFlags,
1441											CFUUIDGetUUIDBytes(kIOFireWirePseudoAddressSpaceInterfaceID));
1442        if( me->fPlugAddressSpace == NULL )
1443            status = kIOReturnNoMemory;
1444    }
1445
1446    if( status == kIOReturnSuccess )
1447    {
1448        FWAddress	address;
1449        (*me->fPlugAddressSpace)->GetFWAddress(me->fPlugAddressSpace, &address);
1450
1451        FWLOG(("IOFireWireAVCLibConsumer::allocated address space at %04X:%08lX\n", address.addressHi, address.addressLo));
1452
1453        (*me->fPlugAddressSpace)->SetWriteHandler( me->fPlugAddressSpace,
1454                                                   &IOFireWireAVCLibConsumer::packetWriteHandler );
1455        (*me->fPlugAddressSpace)->SetSkippedPacketHandler( me->fPlugAddressSpace,
1456                                                           &IOFireWireAVCLibConsumer::skippedPacketHandler );
1457        (*me->fPlugAddressSpace)->SetReadHandler( me->fPlugAddressSpace, &IOFireWireAVCLibConsumer::packetReadHandler );
1458
1459        if( !(*me->fPlugAddressSpace)->TurnOnNotification( me->fPlugAddressSpace ) )
1460            status = kIOReturnError ;
1461
1462    }
1463
1464    return status;
1465}
1466
1467// releaseSegment
1468//
1469//
1470
1471void IOFireWireAVCLibConsumer::releaseSegment( void )
1472{
1473    // free previous address space
1474    if( fPlugAddressSpace != NULL )
1475    {
1476        (*fPlugAddressSpace)->TurnOffNotification( fPlugAddressSpace );
1477        (*fPlugAddressSpace)->Release( fPlugAddressSpace );
1478		fPlugAddressSpace = NULL;
1479    }
1480
1481    // free previous buffer
1482    if( fSegmentBuffer != NULL )
1483    {
1484        free( fSegmentBuffer );
1485		fSegmentBuffer= NULL;
1486    }
1487}
1488
1489// getSegmentSize
1490//
1491//
1492
1493UInt32 IOFireWireAVCLibConsumer::getSegmentSize( void * self )
1494{
1495    IOFireWireAVCLibConsumer * me = getThis(self);
1496
1497    return me->fSegmentSize;
1498}
1499
1500// getSegmentBuffer
1501//
1502//
1503
1504char * IOFireWireAVCLibConsumer::getSegmentBuffer( void * self )
1505{
1506    IOFireWireAVCLibConsumer * me = getThis(self);
1507
1508    return (me->fSegmentBuffer + 64);
1509}
1510
1511//////////////////////////////////////////////////////////////////
1512// segment buffer transactions
1513//
1514
1515// setFrameStatusHandler
1516//
1517//
1518
1519void IOFireWireAVCLibConsumer::setFrameStatusHandler( void * self,
1520                    void * refcon, IOFireWireAVCFrameStatusHandler handler )
1521{
1522    IOFireWireAVCLibConsumer * me = getThis(self);
1523
1524    me->fFrameStatusHandler = handler;
1525    me->fFrameStatusHandlerRefcon = refcon;
1526}
1527
1528// updateProducerRegister
1529//
1530//
1531
1532IOReturn IOFireWireAVCLibConsumer::updateProducerRegister( UInt32 newVal, UInt32 generation )
1533{
1534	IOReturn status = kIOReturnSuccess;
1535
1536	UInt32 tries = 6;
1537	bool done = false;
1538	do
1539	{
1540		FWLOG(( "IOFireWireAVCLibConsumer::updateProducerRegister sending CompareAndSwap(0x%08lx,0x%08lx) to producer\n", fOutputPlugRegisterBuffer, newVal ));
1541		status = (*fFWUnit)->CompareSwap( fFWUnit, fService, &fRemotePlugAddress, OSSwapHostToBigInt32(fOutputPlugRegisterBuffer), OSSwapHostToBigInt32(newVal), true, generation );
1542		if( status == kIOFireWireBusReset || status == kIOReturnSuccess)
1543		{
1544			done = true;
1545		}
1546		else
1547		{
1548			FWLOG(( "IOFireWireLibAVCConsumer::updateProducerRegister register update failed with status = 0x%08lx\n", (UInt32)status ));
1549
1550			if( tries > 1 )
1551			{
1552				// sleep for 25 milliseconds before reading
1553				usleep( 25 * 1000 );
1554
1555				// perhaps producer register is other than we think
1556				// try reading it
1557				UInt32 producerRegister = 0;
1558				status = (*fFWUnit)->ReadQuadlet( fFWUnit, fService, &fRemotePlugAddress, &producerRegister, true, generation );
1559				if( status == kIOReturnSuccess )
1560				{
1561					fOutputPlugRegisterBuffer = OSSwapBigToHostInt32(producerRegister);
1562				}
1563				else if( status == kIOFireWireBusReset )
1564				{
1565					done = true;
1566				}
1567
1568				if( !done )
1569				{
1570					// sleep for 25 milliseconds before retrying
1571					usleep( 25 * 1000 );
1572					FWLOG(( "IOFireWireLibAVCConsumer::updateProducerRegister retrying register update.\n" ));
1573				}
1574			}
1575		}
1576	}
1577	while( !done && --tries );
1578
1579	if( status == kIOReturnSuccess )
1580	{
1581		// if it worked store the value away the value for next time.
1582		fOutputPlugRegisterBuffer = newVal;
1583	}
1584
1585	return status;
1586}
1587
1588// packetReadHandler
1589//
1590//
1591
1592UInt32
1593IOFireWireAVCLibConsumer::packetReadHandler(
1594	IOFireWireLibPseudoAddressSpaceRef	addressSpace,
1595	FWClientCommandID					commandID,
1596	UInt32								packetLen,
1597	UInt32								packetOffset,
1598	UInt16								nodeID,			// nodeID of requester
1599	UInt32								destAddressHi,	// destination on this node
1600	UInt32								destAddressLo,
1601	void*								refcon)
1602{
1603
1604	IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)refcon;
1605
1606	UInt32 endianFixedPlugVal;
1607
1608	FWLOG(( "IOFireWireAVCLibConsumer::packetReadHandler called - destAddressLo = 0x%08lx\n", destAddressLo ));
1609
1610    UInt8 * buffer = (UInt8 *)(*addressSpace)->GetBuffer( addressSpace );
1611
1612    if( packetOffset < 4 )
1613    {
1614		endianFixedPlugVal = OSSwapHostToBigInt32(me->fInputPlugRegisterBuffer);
1615        bcopy( (void*)&endianFixedPlugVal, buffer + packetOffset, sizeof(UInt32));
1616    }
1617    else if( packetOffset < 64 )
1618    {
1619        bzero( buffer + packetOffset, packetLen );
1620    }
1621    else
1622    {
1623        bcopy( me->fSegmentBuffer + packetOffset - 64, buffer + packetOffset, packetLen);
1624	}
1625
1626	(*addressSpace)->ClientCommandIsComplete( addressSpace, commandID, kFWResponseComplete ) ;
1627
1628	return 0;
1629}
1630
1631// packetWriteHandler
1632//
1633//
1634
1635UInt32 IOFireWireAVCLibConsumer::packetWriteHandler(
1636                    IOFireWireLibPseudoAddressSpaceRef	addressSpace,
1637					FWClientCommandID					commandID,
1638					UInt32								packetLen,
1639					void*								packet,
1640					UInt16								srcNodeID,		// nodeID of sender
1641					UInt32								destAddressHi,	// destination on this node
1642					UInt32								destAddressLo,
1643					void*								refcon)
1644{
1645    IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)refcon;
1646    IOReturn 	status = kIOReturnSuccess;
1647
1648    FWAddress	plugAddress;
1649    (*addressSpace)->GetFWAddress(addressSpace, &plugAddress);
1650
1651    FWAddress 	offsetAddress;
1652    offsetAddress.addressHi = destAddressHi;
1653    offsetAddress.addressLo = destAddressLo;
1654
1655    UInt32 offset = (UInt32)subtractFWAddressFromFWAddress( plugAddress, offsetAddress );
1656
1657    if( offset < 64 )
1658    {
1659		//
1660        // in register space
1661        //
1662
1663        if( packetLen > 4 )
1664        {
1665            FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler wrote to register > 4 bytes\n" ));
1666            status = kIOReturnError;
1667        }
1668
1669        if( !((offsetAddress.addressHi == plugAddress.addressHi) &&
1670              (offsetAddress.addressLo == plugAddress.addressLo)) )
1671        {
1672            FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler offsetAddress != plugAddress\n" ));
1673            status = kIOReturnError;
1674        }
1675
1676		pthread_mutex_lock( &me->fLock );
1677		bool workScheduled = false;
1678
1679        if( status == kIOReturnSuccess )
1680        {
1681            me->fInputPlugRegisterBuffer =  OSSwapBigToHostInt32(*((UInt32*)packet));
1682			FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler received packet = 0x%08lx\n", me->fInputPlugRegisterBuffer ));
1683		}
1684
1685		if( status == kIOReturnSuccess && me->fState == kFWAVCStatePrivPlugConnected )
1686		{
1687            me->stopProducerHeartbeatTimer();
1688
1689            UInt32 count	= (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugCountMask) >> kFWAVCConsumerPlugCountPhase;
1690            UInt32 mode 	= (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugModeMask) >> kFWAVCConsumerPlugModePhase;
1691
1692            bool newHeartbeatState = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugHBMask) >> kFWAVCConsumerPlugHBPhase;
1693
1694            if( me->fHeartbeatBitState != newHeartbeatState )
1695            {
1696				//
1697				// schedule the heartbeat response
1698				//
1699
1700				if( !me->fHeartbeatResponseScheduled )
1701				{
1702					FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule heartbeat response\n" ));
1703					me->fHeartbeatResponseScheduled = true;
1704					workScheduled = true;
1705					CFRunLoopSourceSignal( me->fHeartbeatResponseSource );
1706					CFRunLoopWakeUp( me->fCFRunLoop );
1707				}
1708				else
1709				{
1710					FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler frame heartbeat response already scheduled!\n" ));
1711				}
1712			}
1713            else
1714            {
1715                switch( mode )
1716                {
1717                    case kFWAVCConsumerMode_FREE:
1718
1719                        // producer initiated shutdown request.
1720
1721                        switch( me->fState )
1722                        {
1723                            case kFWAVCStatePrivPlugConnected:
1724
1725								//
1726								// schedule disconnect response
1727								//
1728
1729								if( !me->fDisconnectResponseScheduled )
1730								{
1731									FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule disconnect response\n" ));
1732									me->fDisconnectResponseScheduled = true;
1733									workScheduled = true;
1734									CFRunLoopSourceSignal( me->fDisconnectResponseSource );
1735									CFRunLoopWakeUp( me->fCFRunLoop );
1736								}
1737								else
1738								{
1739									FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler disconnect response already scheduled!\n" ));
1740								}
1741
1742                                break;
1743
1744                            default:
1745                                FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler FREE received, but we're in an unexpected state = 0x%08lx.\n", me->fState ));
1746                                break;
1747                        }
1748
1749                        break;
1750
1751                    case kFWAVCConsumerMode_MORE:
1752                    case kFWAVCConsumerMode_LAST:
1753                    case kFWAVCConsumerMode_LESS:
1754                    case kFWAVCConsumerMode_JUNK:
1755                    case kFWAVCConsumerMode_LOST:
1756
1757						//
1758						// schedule frame status handler
1759						//
1760
1761                        me->startConsumerHeartbeatTimer();
1762
1763						me->fFrameStatusMode = mode;
1764                        me->fFrameStatusCount = count;
1765
1766						if( !me->fFrameStatusSourceScheduled )
1767						{
1768							FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule frame status handler\n" ));
1769							me->fFrameStatusSourceScheduled = true;
1770							workScheduled = true;
1771							CFRunLoopSourceSignal( me->fFrameStatusSource );
1772							CFRunLoopWakeUp( me->fCFRunLoop );
1773                        }
1774						else
1775						{
1776							FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler frame heartbeat response already scheduled!\n" ));
1777						}
1778
1779						break;
1780
1781                    default:
1782                        break;
1783                }
1784            }
1785        }
1786
1787		if( !workScheduled )
1788		{
1789			pthread_mutex_unlock( &me->fLock );
1790		}
1791    }
1792    else
1793    {
1794		//
1795        // in segment buffer space
1796        //
1797
1798        if( offset + packetLen - 64 > me->fSegmentSize )
1799        {
1800            FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler written packet size > than segment size\n" ));
1801            status = kIOReturnError;
1802        }
1803
1804        if( status == kIOReturnSuccess )
1805        {
1806            // copy the packet into the segment buffer
1807            bcopy( packet, me->fSegmentBuffer + offset, packetLen );
1808        }
1809    }
1810
1811    (*addressSpace)->ClientCommandIsComplete(addressSpace, commandID, kIOReturnSuccess) ;
1812
1813	return 0;
1814}
1815
1816// skippedPacketHandler
1817//
1818//
1819
1820void IOFireWireAVCLibConsumer::skippedPacketHandler(
1821        IOFireWireLibPseudoAddressSpaceRef	addressSpace,
1822        FWClientCommandID			commandID,
1823        UInt32						skippedPacketCount)
1824{
1825	FWLOG(("IOFireWireAVCLibConsumer::skippedPacketHandler skippedPacketCount = %ld\n", skippedPacketCount));
1826
1827	//zzz what to do ?
1828
1829	(*addressSpace)->ClientCommandIsComplete(addressSpace, commandID, kIOReturnSuccess);
1830}
1831
1832
1833// sendDisconnectResponse
1834//
1835//
1836
1837void IOFireWireAVCLibConsumer::sendDisconnectResponse( void * info )
1838{
1839	IOReturn status = kIOReturnSuccess;
1840	IOFireWireAVCLibConsumer ** meRef = (IOFireWireAVCLibConsumer **)info;
1841	IOFireWireAVCLibConsumer * me = *meRef;
1842	UInt32 newVal = 0;
1843
1844	me->fDisconnectResponseScheduled = false;
1845
1846	FWLOG(( "IOFireWireLibAVCConsumer::sendDisconnectResponse disconnect response handler called\n" ));
1847
1848	UInt32 flags = 	kAVCProducerRunBit |
1849				(me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
1850				(!me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
1851	newVal = oAPR( kFWAVCProducerMode_FREE, me->fSegmentSize, flags, me->fMaxPayloadLog );
1852	status = me->updateProducerRegister( newVal, me->fGeneration );
1853	if( status == kIOReturnSuccess )
1854	{
1855		// I guess this is unneeded as we are disconnected
1856		me->fMode = kFWAVCProducerMode_FREE;
1857		me->fState = kFWAVCStatePrivBusResumed;
1858		me->fSegmentBitState = !me->fSegmentBitState;
1859
1860		FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler FREE received - forciblyDisconnecting\n" ));
1861		me->forciblyDisconnected();
1862	}
1863	else
1864	{
1865        pthread_mutex_unlock( &me->fLock );
1866    }
1867}
1868
1869// sendHeartbeatResponse
1870//
1871//
1872
1873void IOFireWireAVCLibConsumer::sendHeartbeatResponse( void * info )
1874{
1875	IOReturn status = kIOReturnSuccess;
1876	IOFireWireAVCLibConsumer ** meRef = (IOFireWireAVCLibConsumer **)info;
1877	IOFireWireAVCLibConsumer * me = *meRef;
1878	UInt32 newVal = 0;
1879
1880	me->fHeartbeatResponseScheduled = false;
1881	FWLOG(( "IOFireWireLibAVCConsumer::sendHeartbeatResponse heartbeat response handler called\n" ));
1882	UInt32 flags = 	kAVCProducerRunBit |
1883					(!me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
1884					(me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
1885	newVal = oAPR( kFWAVCProducerMode_SEND, me->fSegmentSize, flags, me->fMaxPayloadLog );
1886	status = me->updateProducerRegister( newVal, me->fGeneration );
1887	if( status == kIOReturnSuccess )
1888	{
1889		me->fHeartbeatBitState = !me->fHeartbeatBitState;
1890		me->startProducerHeartbeatTimer();
1891        pthread_mutex_unlock( &me->fLock );
1892    }
1893	else if( status != kIOFireWireBusReset )
1894	{
1895		FWLOG(( "IOFireWireLibAVCConsumer::sendHeartbeatResponse heartbeat handshake failed with status = 0x%08lx\n", (UInt32)status ));
1896		me->forciblyDisconnected();
1897	}
1898	else
1899    {
1900        pthread_mutex_unlock( &me->fLock );
1901    }
1902
1903}
1904
1905// startConsumerHeartbeatTimer
1906//
1907//
1908
1909void IOFireWireAVCLibConsumer::startConsumerHeartbeatTimer( void  )
1910{
1911	CFRunLoopTimerContext		context;
1912	CFAbsoluteTime				time;
1913
1914	stopConsumerHeartbeatTimer(); // just in case
1915
1916    context.version             = 0;
1917    context.info                = this;
1918    context.retain              = NULL;
1919    context.release             = NULL;
1920    context.copyDescription     = NULL;
1921
1922    time = CFAbsoluteTimeGetCurrent() + kConsumerHeartbeatTime;
1923
1924    fConsumerHeartbeatTimer = CFRunLoopTimerCreate(NULL, time,
1925                                    kConsumerHeartbeatTime,
1926                                    0,
1927                                    0,
1928                                    (CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::consumerHeartbeatProc,
1929                                    &context);
1930
1931	if ( fConsumerHeartbeatTimer )
1932	{
1933		CFRunLoopAddTimer( fCFRunLoop, fConsumerHeartbeatTimer, kCFRunLoopDefaultMode );
1934	}
1935}
1936
1937// consumerHeartbeatProc
1938//
1939//
1940
1941void IOFireWireAVCLibConsumer::consumerHeartbeatProc( CFRunLoopTimerRef timer, void *data )
1942{
1943    IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data;
1944    IOReturn status = kIOReturnSuccess;
1945	UInt32 newVal = 0;
1946
1947	pthread_mutex_lock( &me->fLock );
1948
1949	me->stopConsumerHeartbeatTimer(); // necessary?
1950
1951	// oAPR( mode, count, flags, maxLoad )
1952	UInt32 flags = 	kAVCProducerRunBit |
1953					(!me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
1954					(me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
1955	newVal = oAPR( me->fMode, me->fSegmentSize, flags, me->fMaxPayloadLog );
1956	status = me->updateProducerRegister( newVal, me->fGeneration );
1957	if( status == kIOReturnSuccess )
1958	{
1959		me->fHeartbeatBitState = !me->fHeartbeatBitState;
1960	}
1961
1962	pthread_mutex_unlock( &me->fLock );
1963}
1964
1965// stopConsumerHeartbeatTimer
1966//
1967//
1968
1969void IOFireWireAVCLibConsumer::stopConsumerHeartbeatTimer( void )
1970{
1971	if ( fConsumerHeartbeatTimer )
1972	{
1973		CFRunLoopTimerInvalidate( fConsumerHeartbeatTimer );
1974		CFRelease( fConsumerHeartbeatTimer );
1975		fConsumerHeartbeatTimer = NULL;
1976	}
1977}
1978
1979// sendFrameStatusNotification
1980//
1981//
1982
1983void IOFireWireAVCLibConsumer::sendFrameStatusNotification( void * info )
1984{
1985	IOFireWireAVCLibConsumer ** meRef = (IOFireWireAVCLibConsumer **)info;
1986	IOFireWireAVCLibConsumer * me = *meRef;
1987	me->fFrameStatusSourceScheduled = false;
1988
1989	FWLOG(( "IOFireWireLibAVCConsumer::sendFrameStatusNotification frame status handler called\n" ));
1990
1991	pthread_mutex_unlock( &me->fLock );
1992
1993    if( me->fFrameStatusHandler )
1994    {
1995        (me->fFrameStatusHandler)(me->fFrameStatusHandlerRefcon, me->fFrameStatusMode, me->fFrameStatusCount);
1996    }
1997}
1998
1999// frameProcessed
2000//
2001//
2002
2003void IOFireWireAVCLibConsumer::frameProcessed( void * self, UInt32 mode )
2004{
2005    IOFireWireAVCLibConsumer * me = getThis(self);
2006    IOReturn status = kIOReturnSuccess;
2007
2008	pthread_mutex_lock( &me->fLock );
2009
2010	me->stopConsumerHeartbeatTimer();
2011
2012	UInt32 flags = 	kAVCProducerRunBit |
2013					(me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) |
2014					(!me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000);
2015
2016	// oAPR( mode, count, flags, maxLoad )
2017	UInt32 newVal = oAPR( mode, me->fSegmentSize, flags, me->fMaxPayloadLog );
2018
2019	status = me->updateProducerRegister( newVal, me->fGeneration );
2020
2021	if( status == kIOReturnSuccess )
2022	{
2023		me->fMode = mode;
2024		me->fSegmentBitState = !me->fSegmentBitState;
2025		me->startProducerHeartbeatTimer();
2026	}
2027
2028	pthread_mutex_unlock( &me->fLock );
2029}
2030
2031// startProducerHeartbeatTimer
2032//
2033//
2034
2035void IOFireWireAVCLibConsumer::startProducerHeartbeatTimer( void  )
2036{
2037	CFRunLoopTimerContext		context;
2038	CFAbsoluteTime				time;
2039
2040	stopProducerHeartbeatTimer(); // just in case
2041
2042    context.version             = 0;
2043    context.info                = this;
2044    context.retain              = NULL;
2045    context.release             = NULL;
2046    context.copyDescription     = NULL;
2047
2048    time = CFAbsoluteTimeGetCurrent() + kProducerHeartbeatTime;
2049
2050    fProducerHeartbeatTimer = CFRunLoopTimerCreate(	NULL, time,
2051                                                    0,
2052                                                    0,
2053                                                    0,
2054                                                    (CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::producerHeartbeatProc,
2055                                                    &context);
2056
2057	if ( fProducerHeartbeatTimer )
2058	{
2059		CFRunLoopAddTimer( fCFRunLoop, fProducerHeartbeatTimer, kCFRunLoopDefaultMode );
2060	}
2061}
2062
2063// producerHeartbeatProc
2064//
2065//
2066
2067void IOFireWireAVCLibConsumer::producerHeartbeatProc( CFRunLoopTimerRef timer, void *data )
2068{
2069	IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data;
2070
2071    pthread_mutex_lock( &me->fLock );
2072
2073    me->stopProducerHeartbeatTimer(); // necessary?
2074
2075	FWLOG(( "IOFireWireAVCLibConsumer::producerHeartbeatProc producer heatbeat timeout - forciblyDisconnecting\n" ));
2076
2077	me->forciblyDisconnected();
2078}
2079
2080// stopProducerHeartbeatTimer
2081//
2082//
2083
2084void IOFireWireAVCLibConsumer::stopProducerHeartbeatTimer( void )
2085{
2086	if( fProducerHeartbeatTimer )
2087	{
2088		CFRunLoopTimerInvalidate( fProducerHeartbeatTimer );
2089		CFRelease( fProducerHeartbeatTimer );
2090		fProducerHeartbeatTimer = NULL;
2091	}
2092}
2093
2094//////////////////////////////////////////////////////////////////
2095// flags
2096//
2097
2098void IOFireWireAVCLibConsumer::setPortFlags( void * self, UInt32 flags )
2099{
2100    IOFireWireAVCLibConsumer * me = getThis(self);
2101
2102    me->fFlags |= flags;
2103}
2104
2105void IOFireWireAVCLibConsumer::clearPortFlags( void * self, UInt32 flags )
2106{
2107    IOFireWireAVCLibConsumer * me = getThis(self);
2108
2109    me->fFlags &= !flags;
2110}
2111
2112UInt32 IOFireWireAVCLibConsumer::getPortFlags( void * self )
2113{
2114    IOFireWireAVCLibConsumer * me = getThis(self);
2115
2116    return me->fFlags;
2117}
2118