1/*
2 * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1999-2002 Apple Computer, Inc.  All rights reserved.
24 *
25 * HISTORY
26 * 27 April 99 wgulland created.
27 *
28 */
29
30// public
31#import <IOKit/firewire/IOFWUtils.h>
32#import <IOKit/firewire/IOFireWireController.h>
33#import <IOKit/firewire/IOLocalConfigDirectory.h>
34#import <IOKit/firewire/IOFireWireNub.h>
35#import <IOKit/firewire/IOFireWireDevice.h>
36#import <IOKit/firewire/IOFWLocalIsochPort.h>
37#import <IOKit/firewire/IOFWDCLProgram.h>
38#import <IOKit/firewire/IOFireWirePowerManager.h>
39#import <IOKit/firewire/IOFWSimpleContiguousPhysicalAddressSpace.h>
40#import <IOKit/pwr_mgt/RootDomain.h>
41#import <IOKit/firewire/IOFWAsyncStreamListener.h>
42#import <IOKit/firewire/IOFWPHYPacketListener.h>
43#import <IOKit/firewire/IOFWUserObjectExporter.h>
44#import <IOKit/firewire/IOFireWireMultiIsochReceive.h>
45
46#import "IOFWAsyncStreamReceiver.h"
47
48// protected
49#import <IOKit/firewire/IOFWWorkLoop.h>
50#import <IOKit/firewire/IOFireWireLink.h>
51
52// private
53#import "FWDebugging.h"
54#import "IOFireWireLocalNode.h"
55#import "IOFWQEventSource.h"
56#import "IOFireWireIRM.h"
57#include <IOKit/firewire/IOFWUtils.h>
58
59// system
60#import <IOKit/IOKitKeys.h>
61#import <IOKit/IOBufferMemoryDescriptor.h>
62#import <IOKit/IODeviceTreeSupport.h>
63#import <IOKit/IOMessage.h>
64#import <IOKit/IOTimerEventSource.h>
65#import <IOKit/IOKitKeysPrivate.h>
66
67// bsd
68#include <sys/sysctl.h>
69
70///////////////////////////////////////////////////////////////////////////////////
71// Start Tracepooint Setup
72//
73class FireWireGlobals
74{
75public:
76	FireWireGlobals ( void );			// Constructor
77	virtual ~FireWireGlobals ( void );	// Destructor
78};
79
80static int FireWireSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req );
81static FireWireGlobals gFireWireGlobals;	// needs to be declared early to register tracepoints via sysctl
82UInt32 gFireWireDebugFlags = 0;				// extern-ed in FWTracepoints.h
83SYSCTL_PROC ( _debug, OID_AUTO, FireWire, CTLFLAG_RW, 0, 0, FireWireSysctl, "FireWire", "FireWire debug interface" );
84
85static int FireWireSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req )
86{
87	int error = 0;
88	FireWireSysctlArgs fwArgs;
89
90	DEBUG_UNUSED ( oidp );
91	DEBUG_UNUSED ( arg1 );
92	DEBUG_UNUSED ( arg2 );
93
94	//IOLog( "FireWireSysctl: gFireWireDebugFlags = 0x%08X\n", ( unsigned int ) gFireWireDebugFlags );
95
96	error = SYSCTL_IN ( req, &fwArgs, sizeof ( fwArgs ) );
97	if ( ( error == 0 ) && ( fwArgs.type == kFireWireTypeDebug ) )
98	{
99		if ( fwArgs.operation == kFireWireOperationGetFlags )
100		{
101			fwArgs.debugFlags = gFireWireDebugFlags;
102			error = SYSCTL_OUT ( req, &fwArgs, sizeof ( fwArgs ) );
103		}
104
105		else if ( fwArgs.operation == kFireWireOperationSetFlags )
106		{
107			gFireWireDebugFlags = fwArgs.debugFlags;
108		}
109	}
110
111	//IOLog( "FireWireSysctl: gFireWireDebugFlags = 0x%08X error=0x%x\n", ( unsigned int ) gFireWireDebugFlags, error );
112
113	return error;
114}
115
116FireWireGlobals::FireWireGlobals ( void )
117{
118	int debugFlags;
119
120	if ( PE_parse_boot_argn ( "firewire", &debugFlags, sizeof ( debugFlags ) ) )
121	{
122		gFireWireDebugFlags = debugFlags;
123	}
124
125	// Register our sysctl interface
126	sysctl_register_oid ( &sysctl__debug_FireWire );
127}
128
129FireWireGlobals::~FireWireGlobals ( void )
130{
131	// Unregister our sysctl interface
132	sysctl_unregister_oid ( &sysctl__debug_FireWire );
133}
134
135///////////////////////////////////////////////////////////////////////////////////
136
137///////////////////////////////////////////////////////////////////////////////////
138// timing constants
139//
140
141// 100 mSec delay after bus reset before scanning bus
142// to make first generation Sony cameras happy
143#define kScanBusDelay				100
144
145// 35000 mSec delay for a bus reset to become allowed after one was requested
146#define kBusResetStartTimeout		35000
147
148// 1000 mSec delay for a bus reset to occur after one was requested
149#define kBusResetTimeout			1000
150
151// 100 mSec delay for self ids to arrive after a bus reset
152#define kSelfIDTimeout				1000
153
154// 1000 mSec delay before pruning devices
155// this will end up being kNormalDevicePruneDelay + kRepeatResetDelay because of gap count optimization
156#define kNormalDevicePruneDelay		1000
157
158// 2000 mSec delay between bus resets
159// from the 1394a spec
160#define kRepeatResetDelay			2000
161
162// 3000 mSec delay before pruning last device
163// should generally equal kNormalDevicePruneDelay + kRepeatResetDelay
164#define kOnlyNodeDevicePruneDelay	3000
165
166// 15000 mSec delay before pruning devices after wake
167// needs to be at least long enough for the iPod to reboot into disk mode
168#define kWakeDevicePruneDelay		15000
169
170// 30000 mSec delay before pruning devices after wake if any ack busies are seen
171// needs to be at least long enough for the iPod to reboot into disk mode
172// allows some slow HDs to reappear after wake if the Mac's node went away
173#define kWakeDevicePruneDelayBusy	30000
174
175// the maximum amount of time we will allow a device to exist undiscovered
176#define kDeviceMaximuPruneTime		45000
177
178///////////////////////////////////////////////////////////////////////////////////
179
180#define kFireWireGenerationID		"FireWire Generation ID"
181#define kFireWireLoggingMode		"Logging Mode Enabled"
182#define kFWBusScanInProgress		"-1"
183
184#define FWAddressToID(addr) (addr & 63)
185
186enum requestRefConBits
187{
188    kRequestLabel = kFWAsynchTTotal-1,	// 6 bits
189    kRequestExtTCodeShift = 6,
190    kRequestExtTCodeMask = 0x3fffc0,	// 16 bits
191    kRequestIsComplete = 0x20000000,	// Was write request already ack-complete?
192    kRequestIsLock = 0x40000000,
193    kRequestIsQuad = 0x80000000
194};
195
196enum
197{
198	kFWInvalidPort = 0xffffffff
199};
200
201const OSSymbol *gFireWireROM;
202const OSSymbol *gFireWireNodeID;
203const OSSymbol *gFireWireSelfIDs;
204const OSSymbol *gFireWireUnit_Spec_ID;
205const OSSymbol *gFireWireUnit_SW_Version;
206const OSSymbol *gFireWireVendor_ID;
207const OSSymbol *gFireWire_GUID;
208const OSSymbol *gFireWireSpeed;
209const OSSymbol *gFireWireVendor_Name;
210const OSSymbol *gFireWireProduct_Name;
211const OSSymbol *gFireWireModel_ID;
212const OSSymbol *gFireWireTDM;
213
214const IORegistryPlane * IOFireWireBus::gIOFireWirePlane = NULL;
215
216#if __ppc__
217
218enum
219{
220    kFWPMSleepState = 0,
221    kFWPMWakeState = 1
222};
223
224#else
225
226enum
227{
228    kFWPMSleepState = 0,
229    kFWPMWakeState = 2
230};
231
232#endif
233
234OSDefineMetaClassAndStructors(IOFireWireDuplicateGUIDList, OSObject);
235
236IOFireWireDuplicateGUIDList * IOFireWireDuplicateGUIDList::create( void )
237{
238    IOFireWireDuplicateGUIDList * me;
239
240    me = OSTypeAlloc( IOFireWireDuplicateGUIDList );
241
242	return me;
243}
244
245void IOFireWireDuplicateGUIDList::free()
246{
247	IOFWDuplicateGUIDRec		*	GUIDRec;
248	IOFWDuplicateGUIDRec		*	GUIDtoFree;
249
250	GUIDRec = fFirstGUID;
251
252	while( GUIDRec )
253	{
254		GUIDtoFree = GUIDRec;
255
256		GUIDRec = GUIDRec->fNextGUID;
257
258		IOFree( GUIDtoFree, sizeof( IOFWDuplicateGUIDRec ) );
259	}
260
261    OSObject::free();
262}
263
264void IOFireWireDuplicateGUIDList::addDuplicateGUID( CSRNodeUniqueID guid, UInt32 gen )
265{
266	IOFWDuplicateGUIDRec		* 	newGUID;
267
268	if( !guid || findDuplicateGUID( guid, gen ) )
269		return;	// Already found this one.
270
271	newGUID = (IOFWDuplicateGUIDRec *) IOMalloc( sizeof(IOFWDuplicateGUIDRec));
272
273	FWKLOG(("addDuplicateGUID adding GUID %08x %08x.\n",(unsigned int )(guid >> 32),(unsigned int )(guid & 0xffffffff)));
274
275	IOLog("FireWire Error: Devices with identical unique ID: %08x %08x cannot be used.\n",(unsigned int )(guid >> 32),(unsigned int )(guid & 0xffffffff));
276
277	newGUID->fGUID = guid;
278	newGUID->fLastGenSeen = gen;
279	newGUID->fNextGUID = fFirstGUID;
280	fFirstGUID = newGUID;
281}
282
283void IOFireWireDuplicateGUIDList::removeDuplicateGUID( CSRNodeUniqueID guid )
284{
285	IOFWDuplicateGUIDRec		*	GUIDRec;
286	IOFWDuplicateGUIDRec		*	prevGUID;
287
288	GUIDRec = fFirstGUID;
289	prevGUID = NULL;
290
291	while( GUIDRec )
292	{
293		if( GUIDRec->fGUID == guid )
294		{
295			if( prevGUID )
296				prevGUID->fNextGUID = GUIDRec->fNextGUID;
297			else
298				fFirstGUID = GUIDRec->fNextGUID;
299
300			FWKLOG(("removeDuplicateGUID removing GUID %08x %08x.\n",(unsigned int )(guid >> 32),(unsigned int )(guid & 0xffffffff)));
301
302			IOFree( GUIDRec, sizeof( IOFWDuplicateGUIDRec ) );
303
304			break;
305		}
306		prevGUID = GUIDRec;
307		GUIDRec = GUIDRec->fNextGUID;
308	}
309}
310
311bool IOFireWireDuplicateGUIDList::findDuplicateGUID( CSRNodeUniqueID guid, UInt32 gen )
312{
313	IOFWDuplicateGUIDRec		*	GUIDRec;
314
315	//FWKLOG(("findDuplicateGUID looking for GUID %08x %08x.\n",(unsigned int )(guid >> 32),(unsigned int )(guid & 0xffffffff)));
316
317	GUIDRec = fFirstGUID;
318	while( GUIDRec )
319	{
320		if( GUIDRec->fGUID == guid )
321		{
322
323			FWKLOG(("findDuplicateGUID found GUID %08x %08x.\n",(unsigned int )(guid >> 32),(unsigned int )(guid & 0xffffffff)));
324
325
326			GUIDRec->fLastGenSeen = gen;
327
328			return( true );
329		}
330		GUIDRec = GUIDRec->fNextGUID;
331	}
332
333	return( false );
334}
335
336OSDefineMetaClassAndStructors(IOFireWireControllerAux, IOFireWireBusAux);
337OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 0);
338OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 1);
339OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 2);
340OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 3);
341OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 4);
342OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 5);
343OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 6);
344OSMetaClassDefineReservedUnused(IOFireWireControllerAux, 7);
345
346#pragma mark -
347
348// init
349//
350//
351
352bool IOFireWireControllerAux::init( IOFireWireController * primary )
353{
354	bool success = true;		// assume success
355
356	success = IOFireWireBusAux::init();
357
358	fPrimary = primary;
359
360	fSessionRefExporter = IOFWUserObjectExporter::createWithOwner( this );
361	if( !fSessionRefExporter )
362		success = false ;
363
364	return success;
365}
366
367// free
368//
369//
370
371void IOFireWireControllerAux::free()
372{
373	if( fSessionRefExporter )
374	{
375		fSessionRefExporter->release();
376		fSessionRefExporter = NULL;
377	}
378
379	IOFireWireBusAux::free();
380}
381
382IOFWDCLPool *
383IOFireWireControllerAux::createDCLPool ( unsigned capacity ) const
384{
385	return fPrimary->getLink()->createDCLPool( capacity ) ;
386}
387
388// getMaxRec
389//
390//
391
392UInt8 IOFireWireControllerAux::getMaxRec( void )
393{
394	return fMaxRec;
395}
396
397// getFireWirePhysicalAddressMask
398//
399//
400
401UInt64 IOFireWireControllerAux::getFireWirePhysicalAddressMask( void )
402{
403	// all current FW hardware is 32 bit
404	return 0x00000000FFFFFFFFULL;
405}
406
407// getFireWirePhysicalAddressBits
408//
409//
410
411UInt32 IOFireWireControllerAux::getFireWirePhysicalAddressBits( void )
412{
413	// all current FW hardware is 32 bit
414	return 32;
415}
416
417// getFireWirePhysicalBufferMask
418//
419//
420
421UInt64 IOFireWireControllerAux::getFireWirePhysicalBufferMask( void )
422{
423	// all current FW hardware is 32 bit
424	return 0x00000000FFFFFFFFULL;
425}
426
427// getFireWirePhysicalBufferBits
428//
429//
430
431UInt32 IOFireWireControllerAux::getFireWirePhysicalBufferBits( void )
432{
433	// all current FW hardware is 32 bit
434	return 32;
435}
436
437// createSimpleContiguousPhysicalAddressSpace
438//
439//
440
441IOFWSimpleContiguousPhysicalAddressSpace *
442IOFireWireControllerAux::createSimpleContiguousPhysicalAddressSpace( vm_size_t size, IODirection direction )
443{
444    IOFWSimpleContiguousPhysicalAddressSpace * space;
445    space = OSTypeAlloc( IOFWSimpleContiguousPhysicalAddressSpace );
446    if( !space )
447        return NULL;
448
449	if( !space->init( fPrimary, size, direction ) )
450	{
451        space->release();
452        space = NULL;
453    }
454
455    return space;
456}
457
458// createSimplePhysicalAddressSpace
459//
460//
461
462IOFWSimplePhysicalAddressSpace *
463IOFireWireControllerAux::createSimplePhysicalAddressSpace( vm_size_t size, IODirection direction )
464{
465    IOFWSimplePhysicalAddressSpace * space;
466    space = OSTypeAlloc( IOFWSimplePhysicalAddressSpace );
467    if( !space )
468        return NULL;
469
470	if( !space->init( fPrimary, size, direction ) )
471	{
472        space->release();
473        space = NULL;
474    }
475
476    return space;
477}
478
479// getSessionRefExporter
480//
481//
482
483IOFWUserObjectExporter * IOFireWireControllerAux::getSessionRefExporter( void )
484{
485	return fSessionRefExporter;
486}
487
488#pragma mark -
489
490OSDefineMetaClassAndStructors( IOFireWireController, IOFireWireBus )
491OSMetaClassDefineReservedUnused(IOFireWireController, 0);
492OSMetaClassDefineReservedUnused(IOFireWireController, 1);
493OSMetaClassDefineReservedUnused(IOFireWireController, 2);
494OSMetaClassDefineReservedUnused(IOFireWireController, 3);
495OSMetaClassDefineReservedUnused(IOFireWireController, 4);
496OSMetaClassDefineReservedUnused(IOFireWireController, 5);
497OSMetaClassDefineReservedUnused(IOFireWireController, 6);
498OSMetaClassDefineReservedUnused(IOFireWireController, 7);
499OSMetaClassDefineReservedUnused(IOFireWireController, 8);
500
501#pragma mark -
502
503/////////////////////////////////////////////////////////////////////////////
504
505// init
506//
507//
508
509bool IOFireWireController::init( IOFireWireLink *fwim )
510{
511	bool success = true;
512
513    if( !IOFireWireBus::init() )
514    {
515		success = false;
516	}
517
518	if( success )
519	{
520		fAuxiliary = createAuxiliary();
521		if( fAuxiliary == NULL )
522		{
523			success = false;
524		}
525	}
526
527	if( success )
528	{
529
530		fwim->retain() ;
531		fFWIM = fwim;
532		fHubPort = kFWInvalidPort;	// assume no hub
533
534		fOutOfTLabels			= 0;
535		fOutOfTLabels10S		= 0;
536		fOutOfTLabelsThreshold	= 0;
537		fWaitingForSelfID		= 0;
538	}
539
540	//
541	// Create firewire symbols.
542	//
543
544	if( success )
545	{
546		gFireWireROM = OSSymbol::withCString("FireWire Device ROM");
547		if( gFireWireROM == NULL )
548			success = false;
549	}
550
551	if( success )
552	{
553		gFireWireNodeID = OSSymbol::withCString("FireWire Node ID");
554		if( gFireWireNodeID == NULL )
555			success = false;
556	}
557
558	if( success )
559	{
560		gFireWireSelfIDs = OSSymbol::withCString("FireWire Self IDs");
561		if( gFireWireSelfIDs == NULL )
562			success = false;
563	}
564
565	if( success )
566	{
567		gFireWireUnit_Spec_ID = OSSymbol::withCString("Unit_Spec_ID");
568		if( gFireWireUnit_Spec_ID == NULL )
569			success = false;
570	}
571
572	if( success )
573	{
574		gFireWireUnit_SW_Version = OSSymbol::withCString("Unit_SW_Version");
575		if( gFireWireUnit_SW_Version == NULL )
576			success = false;
577	}
578
579	if( success )
580	{
581		gFireWireVendor_ID = OSSymbol::withCString("Vendor_ID");
582		if( gFireWireVendor_ID == NULL )
583			success = false;
584	}
585
586	if( success )
587	{
588		gFireWire_GUID = OSSymbol::withCString("GUID");
589		if( gFireWire_GUID == NULL )
590			success = false;
591	}
592
593	if( success )
594	{
595		gFireWireSpeed = OSSymbol::withCString("FireWire Speed");
596		if( gFireWireSpeed == NULL )
597			success = false;
598	}
599
600	if( success )
601	{
602		gFireWireVendor_Name = OSSymbol::withCString("FireWire Vendor Name");
603		if( gFireWireVendor_Name == NULL )
604			success = false;
605	}
606
607	if( success )
608	{
609		gFireWireProduct_Name = OSSymbol::withCString("FireWire Product Name");
610		if( gFireWireProduct_Name == NULL )
611			success = false;
612	}
613
614	if( success )
615	{
616		gFireWireModel_ID = OSSymbol::withCString("Model_ID");
617		if( gFireWireModel_ID == NULL )
618			success = false;
619	}
620
621	if( success )
622	{
623		gFireWireTDM = OSSymbol::withCString("TDM");
624		if( gFireWireTDM == NULL )
625			success = false;
626	}
627
628	if( success )
629	{
630		if( gIOFireWirePlane == NULL )
631		{
632			gIOFireWirePlane = IORegistryEntry::makePlane( kIOFireWirePlane );
633		}
634
635		if( gIOFireWirePlane == NULL )
636			success = false;
637	}
638
639	//
640	// create sets
641	//
642
643	if( success )
644	{
645		fLocalAddresses = OSSet::withCapacity( 5 );	// Local ROM + CSR registers + SBP-2 ORBs + FCP + PCR
646		if( fLocalAddresses == NULL )
647			success = false;
648	}
649
650	if( success )
651	{
652		fSpaceIterator =  OSCollectionIterator::withCollection( fLocalAddresses );
653		if( fSpaceIterator == NULL )
654			success = false;
655	}
656
657	if( success )
658	{
659		fPHYPacketListeners = OSSet::withCapacity( 2 );
660		if( fPHYPacketListeners == NULL )
661			success = false;
662	}
663
664	if( success )
665	{
666		fPHYPacketListenersIterator =  OSCollectionIterator::withCollection( fPHYPacketListeners );
667		if( fPHYPacketListenersIterator == NULL )
668			success = false;
669	}
670
671	if( success )
672	{
673		fLocalAsyncStreamReceivers = OSSet::withCapacity(2);
674		if( fLocalAsyncStreamReceivers == NULL )
675			success = false;
676	}
677
678	if( success )
679	{
680		fAllocatedChannels = OSSet::withCapacity(1);	// DV channel.
681		if( fAllocatedChannels == NULL )
682			success = false;
683	}
684
685	if( success )
686	{
687		fAllocChannelIterator =  OSCollectionIterator::withCollection(fAllocatedChannels);
688		if( fAllocChannelIterator == NULL )
689			success = false;
690	}
691
692	if( success )
693	{
694		fIRMAllocations = OSSet::withCapacity(1);
695		if( fIRMAllocations == NULL )
696			success = false;
697	}
698
699	if( success )
700	{
701		fIRMAllocationsIterator =  OSCollectionIterator::withCollection(fIRMAllocations);
702		if( fIRMAllocationsIterator == NULL )
703			success = false;
704	}
705
706	if( success )
707	{
708		fIRMAllocationsAllocated = OSSet::withCapacity(1);
709		if( fIRMAllocationsAllocated == NULL )
710			success = false;
711	}
712
713	if( success )
714	{
715		fLastTrans = kMaxPendingTransfers-1;
716		fDevicePruneDelay = kNormalDevicePruneDelay;
717
718		UInt32 bad = OSSwapHostToBigInt32(0xdeadbabe);
719		fBadReadResponse = IOBufferMemoryDescriptor::withBytes(&bad, sizeof(bad), kIODirectionOutIn);
720		if( fBadReadResponse == NULL )
721			success = false;
722	}
723
724	if( success )
725	{
726		fDelayedStateChangeCmdNeedAbort = false;
727		fDelayedStateChangeCmd = createDelayedCmd(1000 * kScanBusDelay, delayedStateChange, NULL);
728		if( fDelayedStateChangeCmd == NULL )
729			success = false;
730	}
731
732	if( success )
733	{
734		fBusResetStateChangeCmd = createDelayedCmd(1000 * kRepeatResetDelay, resetStateChange, NULL);
735		if( fBusResetStateChangeCmd == NULL )
736			success = false;
737	}
738
739	if( success )
740	{
741		fGUIDDups = IOFireWireDuplicateGUIDList::create();
742		if( fGUIDDups == NULL )
743			success = false;
744	}
745
746	//
747	// create the bus power manager
748	//
749
750	if( success )
751	{
752		fBusPowerManager = IOFireWirePowerManager::createWithController( this );
753		if( fBusPowerManager == NULL )
754		{
755			IOLog( "IOFireWireController::start - failed to create bus power manager!\n" );
756			success = false;
757		}
758	}
759
760	if( success )
761	{
762		fNodeMustBeRootFlag		= false;
763		fNodeMustNotBeRootFlag	= false;
764		fForcedGapFlag			= false;
765	}
766
767	return success;
768}
769
770// createAuxiliary
771//
772// virtual method for creating auxiliary object.  subclasses needing to subclass
773// the auxiliary object can override this.
774
775IOFireWireBusAux * IOFireWireController::createAuxiliary( void )
776{
777	IOFireWireControllerAux * auxiliary;
778
779	auxiliary = OSTypeAlloc( IOFireWireControllerAux );
780
781    if( auxiliary != NULL && !auxiliary->init(this) )
782	{
783        auxiliary->release();
784        auxiliary = NULL;
785    }
786
787    return auxiliary;
788}
789
790// free
791//
792//
793
794void IOFireWireController::free()
795{
796	closeGate() ;
797
798	fInstantiated = false;
799
800    // Release everything I can think of.
801	fNodeMustBeRootFlag		= false;
802	fNodeMustNotBeRootFlag	= false;
803	fForcedGapFlag			= false;
804
805	if( fIRM != NULL )
806	{
807		fIRM->release();
808		fIRM = NULL;
809	}
810
811	if( fBusPowerManager != NULL )
812	{
813		fBusPowerManager->release();
814		fBusPowerManager = NULL;
815	}
816
817    if( fROMAddrSpace != NULL )
818	{
819        fROMAddrSpace->release();
820		fROMAddrSpace = NULL;
821	}
822
823    if( fRootDir != NULL )
824    {
825	    fRootDir->release();
826		fRootDir = NULL;
827	}
828
829    if( fBadReadResponse != NULL )
830    {
831	    fBadReadResponse->release();
832		fBadReadResponse = NULL;
833	}
834
835    if( fDelayedStateChangeCmd != NULL )
836	{
837        fDelayedStateChangeCmd->release();
838		fDelayedStateChangeCmd = NULL;
839	}
840
841    if( fBusResetStateChangeCmd != NULL )
842	{
843        fBusResetStateChangeCmd->release();
844		fBusResetStateChangeCmd = NULL;
845	}
846
847    if( fSpaceIterator != NULL )
848	{
849        fSpaceIterator->release();
850		fSpaceIterator = NULL;
851    }
852
853    if( fLocalAddresses != NULL )
854	{
855        fLocalAddresses->release();
856		fLocalAddresses = NULL;
857	}
858
859	if( fPHYPacketListenersIterator != NULL )
860	{
861        fPHYPacketListenersIterator->release();
862		fPHYPacketListenersIterator = NULL;
863    }
864
865    if( fPHYPacketListeners != NULL )
866	{
867        fPHYPacketListeners->release();
868		fPHYPacketListeners = NULL;
869	}
870
871
872	if( fLocalAsyncStreamReceivers != NULL )
873	{
874		fLocalAsyncStreamReceivers->release();
875		fLocalAsyncStreamReceivers = NULL;
876	}
877
878    if( fAllocChannelIterator != NULL )
879	{
880        fAllocChannelIterator->release();
881		fAllocChannelIterator = NULL;
882	}
883
884    if( fAllocatedChannels != NULL )
885	{
886        fAllocatedChannels->release();
887		fAllocatedChannels = NULL;
888    }
889
890	if( fIRMAllocationsIterator != NULL )
891	{
892        fIRMAllocationsIterator->release();
893		fIRMAllocationsIterator = NULL;
894	}
895
896    if( fIRMAllocations != NULL )
897	{
898        fIRMAllocations->release();
899		fIRMAllocations = NULL;
900    }
901
902	if( fIRMAllocationsAllocated != NULL )
903	{
904		fIRMAllocationsAllocated->release();
905		fIRMAllocationsAllocated = NULL;
906	}
907
908	{
909		IOFireWireLink * fwim = fFWIM ;
910		fFWIM = NULL ;
911		fwim->release() ;
912	}
913
914	openGate() ;
915
916	destroyTimeoutQ();
917	destroyPendingQ();
918
919	if( fWorkLoop != NULL )
920	{
921		fWorkLoop->release();
922		fWorkLoop = NULL;
923	}
924
925	if( fAuxiliary != NULL )
926	{
927		fAuxiliary->release();
928		fAuxiliary = NULL;
929	}
930
931	if( fGUIDDups != NULL )
932	{
933		fGUIDDups->release();
934		fGUIDDups = NULL;
935	}
936
937
938
939    IOFireWireBus::free();
940}
941
942// start
943//
944//
945
946bool IOFireWireController::start( IOService * provider )
947{
948	FWTrace_Start( kFWTController, kTPControllerStart, (uintptr_t)fFWIM, 0, 0, 0 );
949
950	fStarted = false;
951
952    if (!IOService::start(provider))
953    {
954	    return false;
955    }
956
957#ifdef __ppc__
958	// x86 device tree is different
959    // blow away device tree children from where we've taken over
960    // Note we don't add ourself to the device tree.
961    IOService *parent = this;
962    while(parent) {
963        if(parent->inPlane(gIODTPlane))
964            break;
965        parent = parent->getProvider();
966    }
967    if(parent) {
968        IORegistryEntry *    child;
969        IORegistryIterator * children;
970
971        children = IORegistryIterator::iterateOver(parent, gIODTPlane);
972        if ( children != 0 ) {
973            // Get all children before we start altering the plane!
974            OSOrderedSet * set = children->iterateAll();
975            if(set != 0) {
976                OSIterator *iter = OSCollectionIterator::withCollection(set);
977                if(iter != 0) {
978                    while ( (child = (IORegistryEntry *)iter->getNextObject()) ) {
979                        child->detachAll(gIODTPlane);
980                    }
981                    iter->release();
982                }
983                set->release();
984            }
985            children->release();
986        }
987    }
988#endif /* __ppc__ */
989
990    fWorkLoop = fFWIM->getFireWireWorkLoop();
991    fWorkLoop->retain();	// make sure workloop lives at least as long as we do.
992
993	// workloop must be set up before creating queues
994	// pending queue creates the command gate used by setPowerState()
995	createPendingQ();
996	createTimeoutQ();
997
998	// process boot-args - we may want to make this a seperate function...
999	if ( !PE_parse_boot_argn("fwdebug_ignorenode", &fDebugIgnoreNode, sizeof(fDebugIgnoreNode)) ) {
1000		// fDebugIgnoreNode can be in 0xFFCx or regular form
1001		fDebugIgnoreNode = kFWDebugIgnoreNodeNone;
1002	} else {
1003		// IOLog might not make it to sys.log, but seen in verbose mode
1004		IOLog("FireWire: Will ignore node 0x%x per boot-args.\n", (uint32_t)fDebugIgnoreNode);
1005	}
1006	// we should define "fwdebug" for debug purposes...
1007
1008	fInstantiated = true;
1009	fStartStatus = kIOReturnSuccess;
1010
1011    // register ourselves with superclass policy-maker
1012    PMinit();
1013    provider->joinPMtree(this);
1014
1015	// get power state table from FWIM
1016	unsigned long num_power_states = 0;
1017	IOPMPowerState * power_state_table = fFWIM->getPowerStateTable( &num_power_states );
1018
1019    registerPowerDriver( this, power_state_table, num_power_states );
1020
1021	FWTrace( kFWTController, kTPControllerStart, (uintptr_t)fFWIM, kFWPMWakeState, 0, 0 );
1022
1023    // No idle sleep
1024    changePowerStateTo( kFWPMWakeState );
1025
1026	// poweredStart will be called once the wake transition occurs
1027
1028	FWTrace_End( kFWTController, kTPControllerStart, (uintptr_t)fFWIM, fStartStatus, 0, 0 );
1029    return (fStartStatus == kIOReturnSuccess);
1030}
1031
1032// poweredStart
1033//
1034//
1035
1036IOReturn IOFireWireController::poweredStart( void )
1037{
1038	FWTrace_Start( kFWTController, kTPControllerPoweredStart, (uintptr_t)fFWIM, 0, 0, 0 );
1039
1040	IOReturn status = kIOReturnSuccess;
1041
1042	fStarted = true;
1043
1044    CSRNodeUniqueID guid = fFWIM->getGUID();
1045
1046	IOService * provider = getProvider();
1047    if( provider->getProperty("DelegateCycleMaster") )
1048    	fDelegateCycleMaster = true;
1049
1050	// look up the hub property
1051	OSData * hub_port_property = (OSData*)fFWIM->getProvider()->getProperty( "fwhub" );
1052	if( hub_port_property )
1053	{
1054		fHubPort = *((UInt32 *)hub_port_property->getBytesNoCopy());
1055	}
1056
1057//	IOLog( "IOFireWireController::poweredStart = hub_port_property = 0x%08lx fHubPort = %d\n", hub_port_property, fHubPort );
1058
1059	//
1060	// setup initial security mode and state change notification
1061	//
1062
1063	initSecurity();
1064
1065    // Build local device ROM
1066    // Allocate address space for Configuration ROM and fill in Bus Info
1067    // block.
1068    fROMHeader[1] = OSSwapHostToBigInt32( kFWBIBBusName );
1069
1070	UInt32 characteristics =  fFWIM->getBusCharacteristics();
1071
1072	//IOLog( "IOFireWireController:start - characteristics = 0x%08lx\n", characteristics );
1073
1074	// zero out generation and store in local rom header
1075    fROMHeader[2] = OSSwapHostToBigInt32( characteristics & ~kFWBIBGeneration );
1076
1077    // Get max speed
1078	((IOFireWireControllerAux*)fAuxiliary)->fMaxRec = ((characteristics & kFWBIBMaxRec) >> kFWBIBMaxRecPhase);
1079    fMaxRecvLog = ((characteristics & kFWBIBMaxRec) >> kFWBIBMaxRecPhase)+1;
1080    fMaxSendLog = fFWIM->getMaxSendLog();
1081    fROMHeader[3] = OSSwapHostToBigInt32( guid >> 32 );
1082    fROMHeader[4] = OSSwapHostToBigInt32( guid & 0xffffffff );
1083
1084    // Create root directory in FWIM data.//zzz should we have one for each FWIM or just one???
1085    fRootDir = IOLocalConfigDirectory::create();
1086    if(!fRootDir)
1087	{
1088		FWTrace_End( kFWTController, kTPControllerPoweredStart, (uintptr_t)fFWIM, kIOReturnError, 1, 0 );
1089        return kIOReturnError;
1090	}
1091
1092    // Set our Config ROM generation.
1093    fRootDir->addEntry(kConfigGenerationKey, (UInt32)1);
1094    // Set our module vendor ID.
1095    fRootDir->addEntry(kConfigModuleVendorIdKey, kConfigUnitSpecAppleA27, OSString::withCString("Apple Computer, Inc."));
1096    fRootDir->addEntry(kConfigModelIdKey, kConfigUnitSWVersMacintosh10, OSString::withCString("Macintosh"));
1097    // Set our capabilities.
1098    fRootDir->addEntry(kConfigNodeCapabilitiesKey, 0x000083C0);
1099
1100    // Set our node unique ID.
1101	UInt64 guid_big = OSSwapHostToBigInt64( guid );
1102    OSData *t = OSData::withBytes(&guid_big, sizeof(guid_big));
1103    fRootDir->addEntry(kConfigNodeUniqueIdKey, t);
1104
1105    fTimer->enable();
1106
1107    // Create local node
1108    IOFireWireLocalNode *localNode = OSTypeAlloc( IOFireWireLocalNode );
1109
1110	localNode->setConfigDirectory( fRootDir );
1111
1112    OSDictionary *propTable;
1113    do {
1114        OSObject * prop;
1115        propTable = OSDictionary::withCapacity(8);
1116        if (!propTable)
1117            continue;
1118
1119        prop = OSNumber::withNumber(guid, 8*sizeof(guid));
1120        if(prop) {
1121            propTable->setObject(gFireWire_GUID, prop);
1122            prop->release();
1123        }
1124
1125        localNode->init(propTable);
1126        localNode->attach(this);
1127        localNode->registerService();
1128    } while (false);
1129    if(propTable)
1130        propTable->release();	// done with it after init
1131
1132#ifdef LEGACY_SHUTDOWN
1133	// install power change handler
1134	fPowerEventNotifier = registerPrioritySleepWakeInterest( systemShutDownHandler, this );
1135	FWKLOGASSERT( fPowerEventNotifier != NULL );
1136#endif
1137
1138	fIRM = IOFireWireIRM::create(this);
1139	FWPANICASSERT( fIRM != NULL );
1140
1141	fFWIM->enableAllInterrupts();	// Enable the interrupt delivery.
1142
1143    registerService();			// Enable matching with this object
1144
1145	FWTrace_End( kFWTController, kTPControllerPoweredStart, (uintptr_t)fFWIM, status, 0, 0 );
1146	return status;
1147}
1148
1149// stop
1150//
1151//
1152
1153void IOFireWireController::stop( IOService * provider )
1154{
1155	closeGate() ;
1156
1157    // Fake up disappearance of entire bus
1158    processBusReset();
1159	suspendBus();
1160
1161	// tear down security state change notification
1162	freeSecurity();
1163
1164    PMstop();
1165
1166#ifdef LEGACY_SHUTDOWN
1167   if( fPowerEventNotifier )
1168	{
1169        fPowerEventNotifier->remove();
1170        fPowerEventNotifier = NULL;
1171    }
1172#endif
1173
1174    if(fBusState == kAsleep) {
1175        IOReturn sleepRes;
1176        sleepRes = fWorkLoop->wake(&fBusState);
1177        if(sleepRes != kIOReturnSuccess) {
1178            IOLog("IOFireWireController::stop - Can't wake FireWire workloop, error 0x%x\n", sleepRes);
1179        }
1180
1181		openGate();
1182    }
1183
1184	freeAllAsyncStreamReceiver();
1185
1186    IOService::stop(provider);
1187
1188	openGate() ;
1189}
1190
1191// finalize
1192//
1193//
1194
1195bool IOFireWireController::finalize( IOOptionBits options )
1196{
1197    bool res;
1198
1199	closeGate() ;
1200
1201    res = IOService::finalize(options);
1202
1203	openGate() ;
1204
1205    return res;
1206}
1207
1208// requestTerminate
1209//
1210// send our custom kIOFWMessageServiceIsRequestingClose to clients
1211
1212bool IOFireWireController::requestTerminate( IOService * provider, IOOptionBits options )
1213{
1214    OSIterator *childIterator;
1215
1216    childIterator = getClientIterator();
1217    if( childIterator )
1218	{
1219        OSObject *child;
1220        while( (child = childIterator->getNextObject()) )
1221		{
1222            IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
1223
1224			// don't need to sync with open/close routines when checking for kNotTerminated
1225			if(found && (found->getTerminationState() == kNotTerminated) && found->isOpen())
1226			{
1227                // send our custom requesting close message
1228                messageClient( kIOFWMessageServiceIsRequestingClose, found );
1229            }
1230        }
1231
1232        childIterator->release();
1233    }
1234
1235    // delete local node
1236    IOFireWireLocalNode *localNode = getLocalNode(this);
1237    if(localNode) {
1238        localNode->release();
1239    }
1240
1241    return IOService::requestTerminate(provider, options);
1242}
1243
1244// setPowerState
1245//
1246//
1247
1248IOReturn IOFireWireController::setPowerState( unsigned long powerStateOrdinal,
1249                                                IOService* whatDevice )
1250{
1251	FWTrace( kFWTController, kTPControllerSetPowerState, (uintptr_t)fFWIM, powerStateOrdinal, 0, 0 );
1252
1253    IOReturn res;
1254    IOReturn sleepRes;
1255
1256	if( !fStarted && (powerStateOrdinal != kFWPMWakeState) )
1257	{
1258		// if we're not started yet wait for a wake state
1259		return IOPMAckImplied;
1260	}
1261
1262	if( !fInstantiated )
1263	{
1264		// we're being torn down, bail
1265		return IOPMAckImplied;
1266	}
1267
1268    // use gate to keep other threads off the hardware,
1269    // Either close gate or wake workloop.
1270    // First time through, we aren't really asleep.
1271    if( fBusState != kAsleep )
1272	{
1273        closeGate();
1274    }
1275    else
1276	{
1277        sleepRes = fWorkLoop->wake(&fBusState);
1278        if(sleepRes != kIOReturnSuccess)
1279		{
1280            IOLog("Can't wake FireWire workloop, error 0x%x\n", sleepRes);
1281        }
1282    }
1283    // Either way, we have the gate closed against invaders/lost sheep
1284
1285	// <rdar://problem/4435647> Yellow: iChat freezes after hot unplug a FireWire iSight during system asleep.
1286	// Change condition from 'powerStateOrdinal != kFWPMSleepState' to 'powerStateOrdinal == kFWPMWakeState'
1287	// -ng
1288
1289	if( powerStateOrdinal == kFWPMWakeState )
1290    {
1291		fDevicePruneDelay = kWakeDevicePruneDelay;
1292        fBusState = kRunning;	// Will transition to a bus reset state.
1293        if( fDelayedStateChangeCmdNeedAbort )
1294        {
1295            fDelayedStateChangeCmdNeedAbort = false;
1296            fDelayedStateChangeCmd->cancel(kIOReturnAborted);
1297        }
1298    }
1299
1300    // Reset bus if we're sleeping, before turning hw off.
1301    if(powerStateOrdinal == kFWPMSleepState )
1302    {
1303        fFWIM->setContender(false);
1304		fFWIM->setRootHoldOff(false);
1305
1306		FWTrace(kFWTResetBusAction, kTPResetSetPowerState, (uintptr_t)fFWIM, powerStateOrdinal, 1, 0);
1307
1308        fFWIM->resetBus();
1309 		IOSleep(10);		// Reset bus may not be instantaneous anymore. Wait a bit to be sure
1310 							// it happened before turning off hardware.
1311 							// zzz how long to wait?
1312 	}
1313
1314    res = fFWIM->setLinkPowerState(powerStateOrdinal);
1315
1316	if( (powerStateOrdinal == kFWPMWakeState) && !fStarted )
1317	{
1318		// fStartStatus will be returned from IOFireWireController::start
1319		if( res != IOPMAckImplied )
1320		{
1321			fStartStatus = kIOReturnError;
1322			res = IOPMAckImplied;
1323		}
1324		else
1325		{
1326			fStartStatus = poweredStart();
1327		}
1328	}
1329
1330	// reset bus
1331	if( (powerStateOrdinal == kFWPMWakeState) &&
1332		(res == IOPMAckImplied) &&
1333		(fStartStatus == kIOReturnSuccess) )
1334	{
1335		if ( kIOReturnSuccess != UpdateROM() )
1336			IOLog(" %s %u: UpdateROM() got error\n", __FILE__, __LINE__ ) ;
1337
1338		FWTrace(kFWTResetBusAction, kTPResetSetPowerState, (uintptr_t)fFWIM, powerStateOrdinal, 2, 0);
1339
1340		fFWIM->resetBus();	// Don't do this on startup until Config ROM built.
1341	}
1342
1343	// Update power state, keep gate closed while we sleep.
1344	if( powerStateOrdinal == kFWPMSleepState )
1345	{
1346		// Pretend we had a bus reset - we'll have a real one when we wake up.
1347		if( delayedStateCommandInUse() )
1348		{
1349			fDelayedStateChangeCmdNeedAbort = true;
1350		}
1351
1352		if( fBusResetState == kResetStateDisabled )
1353		{
1354			// we'll cause a reset when we wake up and reset the state machine anyway
1355			fBusResetStateChangeCmd->cancel( kIOReturnAborted );
1356			fBusResetState = kResetStateResetting;
1357		}
1358
1359		fBusResetScheduled = false;
1360
1361		fBusState = kAsleep;
1362	}
1363
1364	if( (fBusState == kAsleep) && (OSSwapBigToHostInt32(fROMHeader[1]) == kFWBIBBusName) )
1365	{
1366		sleepRes = fWorkLoop->sleep(&fBusState);
1367        if(sleepRes != kIOReturnSuccess)
1368		{
1369            IOLog("Can't sleep FireWire workloop, error 0x%x\n", sleepRes);
1370        }
1371    }
1372    else
1373	{
1374        openGate();
1375    }
1376
1377    return res;
1378}
1379
1380#ifdef LEGACY_SHUTDOWN
1381
1382// systemShutDownHandler
1383//
1384//
1385
1386IOReturn IOFireWireController::systemShutDownHandler( void * target, void * refCon,
1387                                    UInt32 messageType, IOService * service,
1388                                    void * messageArgument, vm_size_t argSize )
1389{
1390
1391    IOReturn status = kIOReturnSuccess;
1392
1393	IOFireWireController * me = (IOFireWireController*)target;
1394
1395	me->closeGate();
1396
1397    switch( messageType )
1398	{
1399        case kIOMessageSystemWillPowerOff:
1400//			IOLog( "IOFireWireController::systemShutDownHandler - kIOMessageSystemWillPowerOff\n" );
1401
1402			me->fFWIM->handleSystemShutDown( messageType );
1403			status = kIOReturnSuccess;
1404			break;
1405
1406        case kIOMessageSystemWillRestart:
1407//			IOLog( "IOFireWireController::systemShutDownHandler - kIOMessageSystemWillRestart\n" );
1408
1409			me->fFWIM->handleSystemShutDown( messageType );
1410			status = kIOReturnSuccess;
1411            break;
1412
1413        default:
1414            status = kIOReturnUnsupported;
1415            break;
1416    }
1417
1418	me->openGate();
1419
1420	 // 30 second delay for debugging
1421	 // this will allow you to see IOLogs at shutdown when verbose booted
1422
1423//	IOSleep( 30000 );
1424
1425    return status;
1426}
1427
1428#else
1429
1430// systemWillShutdown
1431//
1432//
1433
1434void IOFireWireController::systemWillShutdown( IOOptionBits specifier )
1435{
1436	closeGate();
1437
1438    switch( specifier )
1439	{
1440        case kIOMessageSystemWillPowerOff:
1441//			IOLog( "IOFireWireController::systemWillShutdown - kIOMessageSystemWillPowerOff\n" );
1442
1443			fFWIM->handleSystemShutDown( specifier );
1444			break;
1445
1446        case kIOMessageSystemWillRestart:
1447//			IOLog( "IOFireWireController::systemWillShutdown - kIOMessageSystemWillRestart\n" );
1448
1449			fFWIM->handleSystemShutDown( specifier );
1450            break;
1451
1452        default:
1453            break;
1454    }
1455
1456	openGate();
1457
1458	 // 30 second delay for debugging
1459	 // this will allow you to see IOLogs at shutdown when verbose booted
1460
1461//	IOSleep( 30000 );
1462
1463	IOService::systemWillShutdown( specifier );
1464}
1465
1466#endif
1467
1468// resetBus
1469//
1470//
1471
1472IOReturn IOFireWireController::resetBus()
1473{
1474    IOReturn res = kIOReturnSuccess;
1475
1476	closeGate();
1477
1478	switch( fBusResetState )
1479	{
1480		case kResetStateDisabled:
1481			FWTrace(kFWTController, kTPControllerResetBus, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1482
1483			// always schedule resets during the first 2 seconds
1484			fBusResetScheduled = true;
1485			break;
1486
1487		case kResetStateArbitrated:
1488			if( fBusResetDisabledCount == 0 )
1489			{
1490				FWTrace(kFWTController, kTPControllerResetBus, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1491
1492				// cause a reset if no one has disabled resets
1493				doBusReset();
1494			}
1495			else if( !fBusResetScheduled )
1496			{
1497				// schedule the reset if resets are disabled
1498				fBusResetScheduled = true;
1499
1500				//
1501				// start bus reset timer
1502				//
1503
1504				if( delayedStateCommandInUse() )
1505				{
1506					fDelayedStateChangeCmd->cancel( kIOReturnAborted );
1507				}
1508
1509				fBusState = kWaitingBusResetStart;
1510				fDelayedStateChangeCmd->reinit( 1000 * kBusResetStartTimeout, delayedStateChange, NULL );
1511
1512				FWTrace(kFWTStateChangeAction, kTPStateChangeResetBus, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1513				fDelayedStateChangeCmd->submit();
1514			}
1515			break;
1516
1517		case kResetStateResetting:
1518			FWTrace(kFWTController, kTPControllerResetBus, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1519			// we're in the middle of a reset now, no sense in doing another
1520			// fBusResetScheduled would be cleared on the transition out of this state anyway
1521		default:
1522			FWTrace(kFWTController, kTPControllerResetBus, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1523			break;
1524	}
1525
1526	openGate();
1527
1528    return res;
1529}
1530
1531
1532// resetStateChange
1533//
1534// called 2 seconds after a bus reset to transition from the disabled state
1535// to the arbitrated state
1536
1537void IOFireWireController::resetStateChange(void *refcon, IOReturn status,
1538								IOFireWireBus *bus, IOFWBusCommand *fwCmd)
1539{
1540    IOFireWireController *me = (IOFireWireController *)bus;
1541
1542    if( status == kIOReturnTimeout )
1543	{
1544		// we should only transition here from the disabled state
1545#ifdef FWKLOGASSERT
1546		FWKLOGASSERT( me->fBusResetState == kResetStateDisabled );
1547#endif
1548		// transition to the arbitrated reset state
1549		me->fBusResetState = kResetStateArbitrated;
1550
1551		// reset now if we need to and no one has disabled resets
1552		if( me->fBusResetScheduled )
1553		{
1554			if( me->fBusResetDisabledCount == 0 )
1555			{
1556				FWTrace(kFWTResetBusAction, kTPResetResetStateChangeResetScheduled, (uintptr_t)(me->fFWIM), me->fBusResetState, 0, 0);
1557				me->doBusReset();
1558			}
1559			else
1560			{
1561				//
1562				// start bus reset timer
1563				//
1564
1565				if( me->delayedStateCommandInUse() )
1566				{
1567					me->fDelayedStateChangeCmd->cancel( kIOReturnAborted );
1568				}
1569
1570				me->fBusState = kWaitingBusResetStart;
1571				me->fDelayedStateChangeCmd->reinit( 1000 * kBusResetStartTimeout, delayedStateChange, NULL );
1572
1573				FWTrace(kFWTStateChangeAction, kTPStateChangeResetStateChange, (uintptr_t)(me->fFWIM), me->fBusResetState, 0, 0);
1574				me->fDelayedStateChangeCmd->submit();
1575			}
1576		}
1577	}
1578}
1579
1580// doBusReset
1581//
1582//
1583
1584void IOFireWireController::doBusReset( void )
1585{
1586	IOReturn 	status = kIOReturnSuccess;
1587	bool		useIBR = false;
1588
1589	if( fDelayedPhyPacket )
1590	{
1591		fFWIM->sendPHYPacket( fDelayedPhyPacket );
1592		fDelayedPhyPacket = 0x00000000;
1593
1594		// If the gap counts were mismatched and we're optimizing the
1595		// gap count, use in IBR instead of an ISBR
1596
1597		// This works around a problem with certain devices when they
1598		// see an ISBR followed by an IBR due to ISBR promotion.
1599
1600		// When this occurs the device is supposed to throw out the IBR.
1601		// Devices that don't do this latch the gap count with the ISBR
1602		// and then reset it with the subsequent IBR.
1603
1604		// This gets us into a loop where we keep trying to optimize the
1605		// gap count only to find it reset on the next bus generation
1606
1607		// Using an IBR avoids the problem.
1608
1609		if( fGapCountMismatch )
1610		{
1611			useIBR = true;
1612		}
1613	}
1614
1615	FWKLOG(( "IOFireWireController::doBusReset\n" ));
1616
1617	fBusResetState = kResetStateResetting;
1618
1619	//
1620	// start bus reset timer
1621	//
1622
1623	if( delayedStateCommandInUse() )
1624	{
1625		fDelayedStateChangeCmd->cancel(kIOReturnAborted);
1626	}
1627
1628	fBusState = kWaitingBusReset;
1629	fDelayedStateChangeCmd->reinit(1000 * kBusResetTimeout, delayedStateChange, NULL);
1630
1631	FWTrace(kFWTStateChangeAction, kTPStateChangeDoBusReset, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1632    fDelayedStateChangeCmd->submit();
1633
1634	status = fFWIM->resetBus( useIBR );
1635
1636	if( status == kIOReturnSuccess )
1637	{
1638		if( fWaitingForSelfID > kMaxWaitForValidSelfID )
1639		{
1640			fFWIM->notifyInvalidSelfIDs();
1641			fWaitingForSelfID = 0;
1642		}
1643	}
1644	else
1645	{
1646		fDelayedStateChangeCmd->cancel( kIOReturnAborted );
1647		fBusState = kRunning;
1648	}
1649}
1650
1651// enterBusResetDisabledState
1652//
1653//
1654
1655void IOFireWireController::enterBusResetDisabledState( )
1656{
1657	if( fBusResetState == kResetStateDisabled )
1658		fBusResetStateChangeCmd->cancel( kIOReturnAborted );
1659
1660	// start the reset disabled state
1661	fBusResetState = kResetStateDisabled;
1662	fBusResetStateChangeCmd->reinit( 1000 * kRepeatResetDelay, resetStateChange, NULL );
1663    fBusResetStateChangeCmd->submit();
1664}
1665
1666// disableSoftwareBusResets
1667//
1668//
1669
1670IOReturn IOFireWireController::disableSoftwareBusResets( void )
1671{
1672	IOReturn status = kIOReturnSuccess;
1673
1674	closeGate();
1675
1676	switch( fBusResetState )
1677	{
1678		case kResetStateDisabled:
1679			// bus resets have no priority in this state
1680			// we will always allow this call to succeed in these states
1681			fBusResetDisabledCount++;
1682			break;
1683
1684		case kResetStateResetting:
1685			// we're in the process of bus resetting, but processBusReset has
1686			// not yet been called
1687
1688			// if we allowed this call to succeed the client would receive a
1689			// bus reset notification after the disable call which is
1690			// probably not what the caller expects
1691			status = kIOFireWireBusReset;
1692			break;
1693
1694		case kResetStateArbitrated:
1695			// bus resets have an equal priority in this state
1696			// this call will fail if we need to cause a reset in this state
1697			if( !fBusResetScheduled )
1698			{
1699				fBusResetDisabledCount++;
1700			}
1701			else
1702			{
1703				// we're trying to get a bus reset out, we're not allowing
1704				// any more disable calls
1705				status = kIOFireWireBusReset;
1706			}
1707			break;
1708
1709		default:
1710			break;
1711	}
1712
1713//	IOLog( "IOFireWireController::disableSoftwareBusResets = 0x%08lx\n", (UInt32)status );
1714
1715	openGate();
1716
1717	return status;
1718}
1719
1720// enableSoftwareBusResets
1721//
1722//
1723
1724void IOFireWireController::enableSoftwareBusResets( void )
1725{
1726	closeGate();
1727
1728#ifdef FWKLOGASSERT
1729	FWKLOGASSERT( fBusResetDisabledCount != 0 );
1730#endif
1731
1732	// do this in any state
1733	if( fBusResetDisabledCount > 0 )
1734	{
1735		fBusResetDisabledCount--;
1736//		IOLog( "IOFireWireController::enableSoftwareBusResets\n" );
1737	}
1738
1739	switch( fBusResetState )
1740	{
1741		case kResetStateArbitrated:
1742			// this is the only state we're allowed to cause resets in
1743			if( fBusResetDisabledCount == 0 && fBusResetScheduled )
1744			{
1745				// reset the bus if the disabled count is down
1746				// to zero and a bus reset is scheduled
1747				doBusReset();
1748			}
1749			break;
1750
1751		case kResetStateResetting:
1752		case kResetStateDisabled:
1753		default:
1754			break;
1755	}
1756
1757	openGate();
1758}
1759
1760// beginIOCriticalSection
1761//
1762//
1763
1764IOReturn IOFireWireController::beginIOCriticalSection( void )
1765{
1766	IOReturn status = kIOReturnSuccess;
1767
1768	// disable software initiated bus resets
1769	status = disableSoftwareBusResets();
1770
1771	// check success of bus reset disabling
1772	// critical section can be denied if someone has already requested a bus reset
1773
1774	if( status == kIOReturnSuccess )
1775	{
1776		if( fIOCriticalSectionCount == 0 )
1777		{
1778			fFWIM->configureAsyncRobustness( true );
1779		}
1780
1781		fIOCriticalSectionCount++;
1782	}
1783
1784	return status;
1785}
1786
1787// endIOCriticalSection
1788//
1789//
1790
1791void IOFireWireController::endIOCriticalSection( void )
1792{
1793	if( fIOCriticalSectionCount != 0 )
1794	{
1795		enableSoftwareBusResets();
1796
1797		fIOCriticalSectionCount--;
1798
1799		if( fIOCriticalSectionCount == 0 )
1800		{
1801			fFWIM->configureAsyncRobustness( false );
1802		}
1803	}
1804}
1805
1806// delayedStateChange
1807//
1808//
1809
1810void IOFireWireController::delayedStateChange(void *refcon, IOReturn status,
1811                                IOFireWireBus *bus, IOFWBusCommand *fwCmd)
1812{
1813    IOFireWireController *me = (IOFireWireController *)bus;
1814
1815    if(status == kIOReturnTimeout) {
1816        switch (me->fBusState) {
1817		case kWaitingBusResetStart:
1818			// timed out waiting for a bus reset to be alllowed
1819			//			IOLog( "IOFireWireController::delayedStateChange - timed out waiting for a bus reset to be allowed - resetting bus\n" );
1820			FWTrace(kFWTResetBusAction, kTPResetDelayedStateChangeWaitingBusReset, (uintptr_t)me->fFWIM, me->fBusState, 1, 0);
1821			me->doBusReset();
1822			break;
1823		case kWaitingBusReset:
1824			FWTrace(kFWTController, kTPControllerDelayedStateChange, (uintptr_t)(me->fFWIM), me->fBusState, 0, 0);
1825
1826			// timed out waiting for a bus reset
1827//			IOLog( "IOFireWireController::delayedStateChange - timed out waiting for a bus reset - resetting bus\n" );
1828			me->checkProgress();
1829			me->enterBusResetDisabledState();
1830			me->fBusState = kRunning;
1831
1832			FWTrace(kFWTResetBusAction, kTPResetDelayedStateChangeWaitingBusReset, (uintptr_t)me->fFWIM, me->fBusState, 2, 0);
1833			me->resetBus();
1834			break;
1835		case kWaitingSelfIDs:
1836			FWTrace(kFWTController, kTPControllerDelayedStateChange, (uintptr_t)(me->fFWIM), me->fBusState, 0, 0);
1837
1838			// timed out waiting for self ids
1839//			IOLog( "IOFireWireController::delayedStateChange - timed out waiting for self ids - resetting bus\n" );
1840			me->fBusState = kRunning;
1841			me->fWaitingForSelfID++;
1842
1843			FWTrace(kFWTResetBusAction, kTPResetDelayedStateChangeWaitingBusReset, (uintptr_t)me->fFWIM, me->fBusState, 3, 0);
1844			me->resetBus();
1845			break;
1846		case kWaitingScan:
1847			FWTrace(kFWTController, kTPControllerDelayedStateChange, (uintptr_t)(me->fFWIM), me->fBusState, 0, 0);
1848
1849			me->fWaitingForSelfID = 0;
1850            me->fBusState = kScanning;
1851            me->startBusScan();
1852            break;
1853        case kWaitingPrune:
1854			FWTrace(kFWTController, kTPControllerDelayedStateChange, (uintptr_t)me->fFWIM, me->fBusState, 0, 0);
1855
1856            me->fBusState = kRunning;
1857            me->updatePlane();
1858            break;
1859        default:
1860			FWTrace(kFWTController, kTPControllerDelayedStateChange, (uintptr_t)(me->fFWIM), me->fBusState, 0, 0);
1861
1862            IOLog("State change timeout, state is %d\n", me->fBusState);
1863            break;
1864        }
1865    }
1866}
1867
1868// scanningBus
1869//
1870// Are we currently scanning the bus?
1871
1872bool IOFireWireController::scanningBus() const
1873{
1874	return fBusState == kWaitingSelfIDs || fBusState == kWaitingScan || fBusState == kScanning;
1875}
1876
1877// delayedStateCommandInUse
1878//
1879//
1880
1881bool IOFireWireController::delayedStateCommandInUse() const
1882{
1883	return (fBusState == kWaitingBusReset) || (fBusState == kWaitingSelfIDs) || (fBusState == kWaitingScan) || (fBusState == kWaitingPrune);
1884}
1885
1886// getResetTime
1887//
1888//
1889
1890const AbsoluteTime * IOFireWireController::getResetTime() const
1891{
1892	return &fResetTime;
1893}
1894
1895// checkProgress
1896//
1897//
1898
1899void IOFireWireController::checkProgress( void )
1900{
1901	// check progress on reset queue
1902	fAfterResetHandledQ.checkProgress();
1903
1904	// check progress on disconnected devices
1905	OSIterator * childIterator = getClientIterator();
1906    if( childIterator )
1907	{
1908        OSObject *child;
1909        while( (child = childIterator->getNextObject()))
1910		{
1911            IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
1912
1913			if( found && (found->getTerminationState() == kNotTerminated) && found->fNodeID == kFWBadNodeID )
1914			{
1915				AbsoluteTime now;
1916				UInt32 milliDelta;
1917				UInt64 nanoDelta;
1918
1919				AbsoluteTime resume_time = found->getResumeTime();
1920				IOFWGetAbsoluteTime( &now );
1921				SUB_ABSOLUTETIME( &now, &resume_time );
1922				absolutetime_to_nanoseconds( now, &nanoDelta );
1923				milliDelta = nanoDelta / 1000000;
1924
1925				if( milliDelta > kDeviceMaximuPruneTime )
1926				{
1927					// it's been too long, kill him
1928					terminateDevice( found );
1929            	}
1930			}
1931
1932        }
1933        childIterator->release();
1934    }
1935
1936}
1937
1938// processBusReset
1939//
1940// Hardware detected a bus reset.
1941// At this point we don't know what the hardware addresses are
1942
1943void IOFireWireController::processBusReset( void )
1944{
1945	FWKLOG(( "IOFireWireController::processBusReset\n" ));
1946
1947	IOFWGetAbsoluteTime(&fResetTime);	// Update even if we're already processing a reset
1948
1949	// we got our bus reset, cancel any reset work in progress
1950	fBusResetScheduled = false;
1951
1952	enterBusResetDisabledState();
1953
1954	if( delayedStateCommandInUse() )
1955	{
1956		fDelayedStateChangeCmd->cancel( kIOReturnAborted );
1957	}
1958
1959	fBusState = kWaitingSelfIDs;
1960
1961	checkProgress();
1962
1963	// set a timer
1964	fDelayedStateChangeCmd->reinit( 1000 * kSelfIDTimeout, delayedStateChange, NULL );
1965
1966	FWTrace(kFWTStateChangeAction, kTPStateChangeProcessBusReset, (uintptr_t)fFWIM, fBusResetState, 0, 0);
1967    fDelayedStateChangeCmd->submit();
1968}
1969
1970// suspendBus
1971//
1972//
1973
1974void IOFireWireController::suspendBus( void )
1975{
1976	FWKLOG(( "IOFireWireController::suspendBus\n" ));
1977
1978	// set generation property to kFWBusScanInProgress ("-1")
1979	FWKLOG(("IOFireWireController::suspendBus set generation to '%s' realGen=0x%lx\n", kFWBusScanInProgress, fBusGeneration));
1980	setProperty( kFireWireGenerationID, kFWBusScanInProgress );
1981
1982	fRequestedHalfSizePackets = false;
1983	fNodeMustNotBeRootFlag	  = false;
1984	fNodeMustBeRootFlag		  = false;
1985	fForcedGapFlag			  = false;
1986
1987	unsigned int i;
1988	UInt32 oldgen = fBusGeneration;
1989
1990	// Set all current device nodeIDs to something invalid
1991	fBusGeneration++;
1992
1993	// Reset all these information only variables
1994	fOutOfTLabels			= 0;
1995	fOutOfTLabels10S		= 0;
1996	fOutOfTLabelsThreshold	= 0;
1997
1998	OSIterator * childIterator = getClientIterator();
1999	if( childIterator )
2000	{
2001		OSObject * child;
2002		while( (child = childIterator->getNextObject()) )
2003		{
2004			IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
2005
2006			// don't need to sync with open/close routines when checking for kNotTerminated
2007			if( found && (found->getTerminationState() == kNotTerminated) )
2008			{
2009				found->setNodeROM( oldgen, kFWBadNodeID, NULL );
2010			}
2011			else if( OSDynamicCast(IOFireWireLocalNode, child) )
2012			{
2013				// forceStop  should take care of this deactivateAsyncStreamReceivers();
2014				((IOFireWireLocalNode *)child)->messageClients(kIOMessageServiceIsSuspended);
2015			}
2016		}
2017
2018		childIterator->release();
2019	}
2020
2021	// reset physical filters if necessary
2022	physicalAccessProcessBusReset();
2023
2024	// IOLog("FireWire Bus Generation now %d\n", fBusGeneration);
2025
2026	// Invalidate current topology and speed map
2027	bzero( fSpeedVector, sizeof(fSpeedVector) );
2028
2029	// Zap all outstanding async requests
2030	for( i=0; i<kMaxPendingTransfers; i++ )
2031	{
2032		AsyncPendingTrans *t = &fTrans[i];
2033		if( t->fHandler )
2034		{
2035			IOFWAsyncCommand * cmd = t->fHandler;
2036			cmd->gotPacket(kFWResponseBusResetError, NULL, 0);
2037		}
2038		else if( t->fAltHandler )
2039		{
2040			IOFWAsyncPHYCommand * cmd = OSDynamicCast( IOFWAsyncPHYCommand, t->fAltHandler );
2041			if( cmd )
2042			{
2043				cmd->gotPacket( kFWResponseBusResetError );
2044			}
2045		}
2046	}
2047
2048	// Clear out the old firewire plane
2049	if( fNodes[fRootNodeID] )
2050	{
2051		fNodes[fRootNodeID]->detachAll(gIOFireWirePlane);
2052	}
2053
2054	for( i=0; i<=fRootNodeID; i++ )
2055	{
2056		if( fScans[i] )
2057		{
2058			fScans[i]->fCmd->release();
2059			fScans[i]->fLockCmd->release();
2060			IOFree(fScans[i], sizeof(*fScans[i]));
2061			fScans[i] = NULL;
2062		}
2063
2064		if(fNodes[i])
2065		{
2066			fNodes[i]->release();
2067			fNodes[i] = NULL;
2068		}
2069	}
2070
2071	// Cancel all commands in timeout queue that want to complete on bus reset
2072	fTimeoutQ.busReset();
2073}
2074
2075// processSelfIDs
2076//
2077//
2078
2079void IOFireWireController::processSelfIDs(UInt32 *IDs, int numIDs, UInt32 *ownIDs, int numOwnIDs)
2080{
2081    int i;
2082    UInt32 id;
2083    UInt32 nodeID;
2084    UInt16 irmID;
2085    UInt16 ourID;
2086    IOFireWireLocalNode * localNode;
2087
2088	FWKLOG(( "IOFireWireController::processSelfIDs entered\n" ));
2089	FWTrace_Start(kFWTController, kTPControllerProcessSelfIDs, (uintptr_t)fFWIM, 0, 0, 0);
2090
2091#if (DEBUGGING_LEVEL > 0)
2092for(i=0; i<numIDs; i++)
2093    IOLog("ID %d: 0x%x <-> 0x%x\n", i, IDs[2*i], ~IDs[2*i+1]);
2094
2095for(i=0; i<numOwnIDs; i++)
2096    IOLog("Own ID %d: 0x%x <-> 0x%x\n", i, ownIDs[2*i], ~ownIDs[2*i+1]);
2097#endif
2098
2099	if( fBusState != kWaitingSelfIDs )
2100	{
2101		// If not processing a reset, then we should be
2102		// This can happen if we get two resets in quick successio
2103        processBusReset();
2104    }
2105
2106	suspendBus();
2107
2108	// we should now be in the kWaitingSelfIDs state
2109
2110	if( fBusState != kWaitingSelfIDs )
2111	{
2112		IOLog( "IOFireWireController::processSelfIDs - fBusState != kWaitingSelfIDs\n" );
2113	}
2114
2115	if( fBusState == kWaitingSelfIDs )
2116	{
2117		// cancel self id timeout
2118		fDelayedStateChangeCmd->cancel( kIOReturnAborted );
2119	}
2120
2121	fBusState = kWaitingScan;
2122
2123    // Initialize root node to be our node, we'll update it below to be the highest node ID.
2124    fRootNodeID = ourID = (OSSwapBigToHostInt32(*ownIDs) & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
2125    if( fRootNodeID > 0x3e )
2126		fRootNodeID = 0x3e;
2127	fLocalNodeID = ourID | (kFWLocalBusAddress>>kCSRNodeIDPhase);
2128
2129	fGapCountMismatch = false;
2130
2131    // check for mismatched gap counts
2132    UInt32 gap_count = (OSSwapBigToHostInt32(*ownIDs) & kFWSelfID0GapCnt) >> kFWSelfID0GapCntPhase;
2133    for( i = 0; i < numIDs; i++ )
2134    {
2135        UInt32 current_id = OSSwapBigToHostInt32(IDs[2*i]);
2136        if( (current_id & kFWSelfIDPacketType) == 0 &&
2137            ((current_id & kFWSelfID0GapCnt) >> kFWSelfID0GapCntPhase) != gap_count )
2138        {
2139            // set the gap counts to 0x3F, if any gap counts are mismatched
2140            fFWIM->sendPHYPacket( (kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
2141                                  (0x3f << kFWPhyConfigurationGapCntPhase) | kFWPhyConfigurationT );
2142
2143			fGapCountMismatch = true;
2144			FWKLOG(( "IOFireWireController::processSelfIDs Found Gap Count Mismatch!\n" ));
2145            break;
2146        }
2147    }
2148
2149    // Update the registry entry for our local nodeID,
2150    // which will have been updated by the device driver.
2151    // Find the local node (just avoiding adding a member variable)
2152    localNode = getLocalNode(this);
2153    if(localNode)
2154	{
2155        localNode->setNodeProperties(fBusGeneration, fLocalNodeID, ownIDs, numOwnIDs,fFWIM->getPhySpeed() );
2156        fNodes[ourID] = localNode;
2157        localNode->retain();
2158    }
2159
2160    // Copy over the selfIDs, checking validity and merging in our selfIDs if they aren't
2161    // already in the list.
2162    SInt16 prevID = -1;	// Impossible ID.
2163    UInt32 *idPtr = fSelfIDs;
2164
2165	// zero out fNodeIDs so any gaps in the received self IDs will be
2166	// apparent later...
2167	bzero( fNodeIDs, sizeof(fNodeIDs) ) ;
2168
2169	fNumSelfIDs = numIDs;
2170    for(i=0; i<numIDs; i++)
2171	{
2172        UInt32 id = OSSwapBigToHostInt32(IDs[2*i]);
2173        UInt16 currID = (id & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase;
2174
2175 		UInt32 id_inverse = ~OSSwapBigToHostInt32( IDs[2*i+1] );
2176        if(id != id_inverse)
2177		{
2178            IOLog("Bad SelfID packet %d: 0x%x != 0x%x!\n", i, (uint32_t)id, (uint32_t)id_inverse);
2179
2180			FWTrace(kFWTResetBusAction, kTPResetProcessSelfIDs, (uintptr_t)fFWIM, 1, id, 0 );
2181            resetBus();	// Could wait a bit in case somebody else spots the bad packet
2182			FWKLOG(( "IOFireWireController::processSelfIDs exited\n" ));
2183            return;
2184        }
2185
2186        if(currID != prevID)
2187		{
2188            // Check for ownids not in main list
2189            if( prevID < ourID && currID > ourID )
2190			{
2191				int j;
2192				fNodeIDs[ourID] = idPtr;
2193				for(j=0; j<numOwnIDs; j++)
2194				{
2195					*idPtr++ = ownIDs[2*j];
2196				}
2197				fNumSelfIDs += numOwnIDs;
2198			}
2199			fNodeIDs[currID] = idPtr;
2200			prevID = currID;
2201			if((fRootNodeID < currID) && (currID <= 0x3e))
2202				fRootNodeID = currID;
2203        }
2204		*idPtr++ = IDs[2*i];
2205    }
2206
2207    // Check for ownids at end & not in main list
2208    if(prevID < ourID)
2209	{
2210        int j;
2211        fNodeIDs[ourID] = idPtr;
2212        for(j=0; j<numOwnIDs; j++)
2213		{
2214            *idPtr++ = ownIDs[2*j];
2215		}
2216		fNumSelfIDs += numOwnIDs;
2217	}
2218    // Stick a known elephant at the end.
2219    fNodeIDs[fRootNodeID+1] = idPtr;
2220
2221    // Check nodeIDs are monotonically increasing from 0.
2222    for(i = 0; i<=fRootNodeID; i++)
2223	{
2224        if ( NULL == fNodeIDs[i] )
2225		{
2226			IOLog("Missing self ID for node %d!\n", i ) ;
2227			FWTrace(kFWTResetBusAction, kTPResetProcessSelfIDs, (uintptr_t)fFWIM, 2, i, 0 );
2228			resetBus();        	// Could wait a bit in case somebody else spots the bad packet
2229
2230			return;				// done.
2231		}
2232
2233		UInt32 host_id = OSSwapBigToHostInt32(*fNodeIDs[i]);
2234		if( ((host_id & kFWPhyPacketPhyID) >> kFWPhyPacketPhyIDPhase) != (UInt32)i)
2235		{
2236			IOLog("No FireWire node %d (got ID packet 0x%x)!\n", i, (uint32_t)host_id);
2237			FWTrace(kFWTResetBusAction, kTPResetProcessSelfIDs, (uintptr_t)fFWIM, 3, i, 0 );
2238			resetBus();        // Could wait a bit in case somebody else spots the bad packet
2239
2240			return;				// done.
2241		}
2242    }
2243
2244    // Store selfIDs
2245    OSObject * prop = OSData::withBytes( fSelfIDs, fNumSelfIDs * sizeof(UInt32));
2246    setProperty(gFireWireSelfIDs, prop);
2247    prop->release();
2248
2249    buildTopology(false);
2250
2251#if (DEBUGGING_LEVEL > 0)
2252    for(i=0; i<numIDs; i++) {
2253        id = IDs[2*i];
2254        if(id != ~IDs[2*i+1]) {
2255            DEBUGLOG("Bad SelfID: 0x%x <-> 0x%x\n", id, ~IDs[2*i+1]);
2256            continue;
2257        }
2258	DEBUGLOG("SelfID: 0x%x\n", id);
2259    }
2260    DEBUGLOG("Our ID: 0x%x\n", *ownIDs);
2261#endif
2262    // Find isochronous resource manager, if there is one
2263    irmID = 0;
2264    for(i=0; i<=fRootNodeID; i++) {
2265        id = OSSwapBigToHostInt32(*fNodeIDs[i]);
2266        // Get nodeID.
2267        nodeID = (id & kFWSelfIDPhyID) >> kFWSelfIDPhyIDPhase;
2268        nodeID |= kFWLocalBusAddress>>kCSRNodeIDPhase;
2269
2270        if((id & (kFWSelfID0C | kFWSelfID0L)) == (kFWSelfID0C | kFWSelfID0L)) {
2271#if (DEBUGGING_LEVEL > 0)
2272            IOLog("IRM contender: %lx\n", nodeID);
2273#endif
2274            if(nodeID > irmID)
2275		irmID = nodeID;
2276	}
2277    }
2278    if(irmID != 0)
2279        fIRMNodeID = irmID;
2280    else
2281        fIRMNodeID = kFWBadNodeID;
2282
2283    fBusMgr = false;	// Update if we find one.
2284
2285	// inform IRM of updated bus generation and node ids
2286	fIRM->processBusReset( fLocalNodeID, fIRMNodeID, fBusGeneration );
2287
2288    // OK for stuff that only needs our ID and the irmID to continue.
2289    if(localNode) {
2290        localNode->messageClients(kIOMessageServiceIsResumed);
2291		// force stop should take care of this activateAsyncStreamReceivers();
2292    }
2293
2294	FWTrace(kFWTStateChangeAction, kTPStateChangeProcessSelfIDs, (uintptr_t)fFWIM, fBusState, 0, 0);
2295
2296    fDelayedStateChangeCmd->reinit(1000 * kScanBusDelay, delayedStateChange, NULL);
2297    fDelayedStateChangeCmd->submit();
2298
2299	FWTrace_End(kFWTController, kTPControllerProcessSelfIDs, (uintptr_t)fFWIM, 0, 0, 0);
2300	FWKLOG(( "IOFireWireController::processSelfIDs exited\n" ));
2301}
2302
2303void IOFireWireController::processCycle64Int()
2304{
2305	if( fOutOfTLabels10S++ > 1 )
2306	{
2307		fOutOfTLabels10S = 0;
2308
2309		if( fOutOfTLabels > fOutOfTLabelsThreshold )
2310		{
2311			IOLog("IOFireWireController:: %d Out of Transaction Labels in last 3 minutes.\n",(int) fOutOfTLabels);
2312			fOutOfTLabelsThreshold = fOutOfTLabels;
2313		}
2314		else
2315			fOutOfTLabelsThreshold = fOutOfTLabelsThreshold >> 1; // back off by half
2316
2317		fOutOfTLabels = 0;
2318	}
2319}
2320
2321////////////////////////////////////////////////////////////////////////////////
2322//
2323// AssignCycleMaster
2324//
2325//
2326//
2327
2328bool IOFireWireController::AssignCycleMaster( )
2329{
2330	IOReturn					status = kIOReturnSuccess;
2331	int							i;
2332	UInt32						contender, linkOn, otherContenderID = 0, newRoot = 0, data1;
2333	Boolean						otherContender = false, localContender = false, needReset = false, badIRM = false;
2334
2335	if( ((fRootNodeID & 63) == (fLocalNodeID & 63)) && fNodeMustBeRootFlag )
2336	{
2337		status = fFWIM->setContender( false );
2338
2339		if(status == kIOReturnSuccess)
2340		{
2341
2342			data1 = (kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
2343						((fForcedRootNodeID & 63) << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR;
2344
2345			// Send phy packet to set root hold off bit for node
2346			status = fFWIM->sendPHYPacket(data1);
2347
2348			if(kIOReturnSuccess == status)
2349				needReset = true;
2350		}
2351	}
2352    else if( fDelegateCycleMaster || fBadIRMsKnown || fNodeMustNotBeRootFlag )
2353	{
2354		for( i = 0; i <= fRootNodeID; i++ )
2355		{
2356			contender = (OSSwapBigToHostInt32(*fNodeIDs[i]) >> 11) & 0x1;
2357			linkOn = (OSSwapBigToHostInt32(*fNodeIDs[i]) >> 22) & 0x1;
2358
2359			if (contender && linkOn )
2360			{
2361				if ( i == (fLocalNodeID & 63) )
2362				{
2363					if (contender)
2364						localContender = true;
2365				}
2366				else
2367				{
2368					if( fScans[i] )
2369					{
2370						if( (not fScans[i]->fMustNotBeRoot) && (not fScans[i]->fIRMisBad) ) // if designated as root
2371						{
2372							otherContender = true;
2373							otherContenderID = i;		// any one will do (use highest)
2374						}
2375					}
2376				}
2377			}
2378		}
2379
2380		if (otherContender)
2381		{
2382			if( (fRootNodeID & 63) == (fLocalNodeID & 63) && fDelegateCycleMaster )
2383			{
2384				// We are root, but we don't really want to be and somebody else can do the job.
2385				// We're doing this in response to self-IDs, so we have not scanned
2386				// the bus yet - presumably it is safe to use the asynch transmitter
2387				// because nobody else could be using it.
2388
2389				//zzz might want to wait for it to settle down in case it was running
2390				// when the bus reset happened
2391
2392				status = fFWIM->setContender( false );
2393
2394				if( status == kIOReturnSuccess )
2395				{
2396					// force root
2397					fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
2398								((otherContenderID & 63) << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR );
2399
2400					needReset = true;
2401				}
2402			}
2403		}
2404		else if( ((fRootNodeID & 63) != (fLocalNodeID & 63)) && (localContender) && (not fDelegateCycleMaster))
2405		{
2406			status = fFWIM->setContender( true );
2407
2408			// Set RHB for our soon to be root node and clear everyone else
2409			fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
2410						((fLocalNodeID & 63) << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR );
2411
2412			needReset = true;
2413		}
2414
2415		if( status == kIOReturnSuccess && fBadIRMsKnown )
2416		{
2417			// Check for unresponsive IRM
2418			badIRM = (!fScans[fIRMNodeID & 63]) && ((fLocalNodeID & 63) != (fIRMNodeID & 63));
2419
2420			if(  fScans[fIRMNodeID & 63] && fScans[fIRMNodeID & 63]->fIRMisBad )
2421				badIRM = true;
2422
2423			// If Bad IRM or no IRM then find somebody to do the job
2424			if( badIRM || (!localContender) && (!otherContender) )
2425			{
2426
2427				if( !fDelegateCycleMaster )
2428				{
2429					// Mac which wants to be cyclemaster gets priority
2430					newRoot = fLocalNodeID & 63;
2431					fFWIM->setContender( true );
2432					fFWIM->setRootHoldOff(true);
2433				}
2434				else if( otherContender )
2435					newRoot = otherContenderID;
2436				else
2437				{
2438					// Oh well, nobody else can do it. Make Mac root. Make sure C is set and set our RHB
2439					newRoot = fLocalNodeID & 63;
2440					fFWIM->setContender( true );
2441					fFWIM->setRootHoldOff(true);
2442				}
2443
2444				if( badIRM )
2445					IOLog("IOFireWireController unresponsive IRM at node %x, forcing root to node %x\n", (uint32_t) fIRMNodeID & 63, (uint32_t)newRoot );
2446
2447				// Set RHB for our soon to be root node and clear everyone else
2448				fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
2449							((newRoot & 63) << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR );
2450
2451				needReset = true;
2452			}
2453		}
2454	}
2455
2456	if( status == kIOReturnSuccess )
2457	{
2458		if( needReset )
2459		{
2460			//FWLogEvent ("HackAvoidBeingRoot Reset Bus\n");
2461			/* zzzzzzzzz edit comment after checking where this gets called from */
2462			//  It is important to re-enable bus reset interrupts when we issue a bus reset.
2463			//  Otherwise if the PHY->Link interface is really confused about self-ID
2464			//  streams we might never see the self ID interrupts. (LSI/Lucent problem).
2465			//  By re-enabling bus reset interrupts we see the next interrupt and
2466			//  FWProcessBusReset will queue its selfID timer. If we don't get self
2467			//  ids then FSL will reset the bus until we get real ones which should
2468			//  happen eventually.
2469			//
2470			//  Since this function is always called from the SelfIDDeferredTask we know
2471			//  that bus reset interrupts are enabled and thus don't have to do anything.
2472
2473			// Cause bus reset
2474			FWTrace(kFWTResetBusAction, kTPResetAssignCycleMaster, (uintptr_t)fFWIM, 0, 0, 0 );
2475			fFWIM->resetBus();
2476
2477			IOSleep( 10 );												// sleep for 10 ms
2478		}
2479	}
2480
2481	return( needReset );
2482}
2483
2484
2485// startBusScan
2486//
2487//
2488
2489void IOFireWireController::startBusScan()
2490{
2491    int i;
2492
2493	FWTrace( kFWTController, kTPControllerStartBusScan, (uintptr_t)fFWIM, 0, 0, 0 );
2494	FWKLOG(( "IOFireWireController::startBusScan entered\n" ));
2495
2496	OSObject * existProp = fFWIM->getProperty( "FWDSLimit" );
2497
2498	if( existProp )
2499	{
2500		fDSLimited = true;
2501	}
2502	else
2503	{
2504		fDSLimited = false;
2505	}
2506
2507    // Send global resume packet
2508	fFWIM->sendPHYPacket(((fLocalNodeID & 0x3f) << kFWPhyPacketPhyIDPhase) | 0x003c0000);
2509
2510    // Tell all active isochronous channels to re-allocate bandwidth
2511    IOFWIsochChannel *found;
2512    fAllocChannelIterator->reset();
2513    while( (found = (IOFWIsochChannel *)fAllocChannelIterator->getNextObject()) )
2514	{
2515        found->handleBusReset();
2516    }
2517
2518	IOFireWireIRMAllocation *irmAllocationfound;
2519    fIRMAllocationsIterator->reset();
2520    while( (irmAllocationfound = (IOFireWireIRMAllocation *)fIRMAllocationsIterator->getNextObject()) )
2521	{
2522        irmAllocationfound->handleBusReset(fBusGeneration);
2523    }
2524
2525    fNumROMReads = fRootNodeID+1;
2526    for(i=0; i<=fRootNodeID; i++) {
2527        UInt16 nodeID;
2528        UInt32 id;
2529        id = OSSwapBigToHostInt32(*fNodeIDs[i]);
2530        // Get nodeID.
2531        nodeID = (id & kFWSelfIDPhyID) >> kFWSelfIDPhyIDPhase;
2532        nodeID |= kFWLocalBusAddress>>kCSRNodeIDPhase;
2533        if(nodeID == fLocalNodeID)
2534 		{
2535			fNumROMReads--;
2536			continue;	// Skip ourself!
2537		}
2538
2539		// ??? maybe we should add an fwdebug bit to be strict on scanning only nodes with link bit?
2540
2541        // Read ROM header if link is active (MacOS8 turns link on, why?)
2542        if(true) { //id & kFWSelfID0L) {
2543            IOFWNodeScan *scan;
2544            scan = (IOFWNodeScan *)IOMalloc(sizeof(*scan));
2545
2546            scan->fControl = this;
2547            scan->fAddr.nodeID = nodeID;
2548            scan->fAddr.addressHi = kCSRRegisterSpaceBaseAddressHi;
2549            scan->fAddr.addressLo = kConfigBIBHeaderAddress;
2550            scan->fSelfIDs = fNodeIDs[i];
2551            scan->fNumSelfIDs = fNodeIDs[i+1] - fNodeIDs[i];
2552            scan->fRead = 0;
2553            scan->generation = fBusGeneration;
2554			scan->fRetriesBumped = 0;
2555            scan->fCmd = OSTypeAlloc( IOFWReadQuadCommand );
2556 			scan->fLockCmd = OSTypeAlloc( IOFWCompareAndSwapCommand );
2557
2558           // Read an IRM Register if node is a contender
2559            if( (id & (kFWSelfID0C | kFWSelfID0L)) == (kFWSelfID0C | kFWSelfID0L) )
2560            {
2561				// IOLog("Node 0x%x is Contender\n",nodeID);
2562            	scan->fContenderNeedsChecking = true;
2563            }
2564            else
2565				scan->fContenderNeedsChecking = false;
2566			scan->fIRMisBad = false;
2567			scan->fIRMCheckingRead = false;
2568			scan->fIRMCheckingLock = false;
2569
2570 			FWKLOG(( "IOFireWireController::startBusScan node %lx speed was %lx\n",(UInt32)nodeID,(UInt32)FWSpeed( nodeID ) ));
2571
2572			if ( fDebugIgnoreNode != kFWDebugIgnoreNodeNone && ((fDebugIgnoreNode & kFWMaxNodesPerBus ) == (nodeID & kFWMaxNodesPerBus )) )
2573			{
2574				// we do not want to speedcheck an ignored node.
2575            	scan->speedChecking = false;
2576
2577				// If current speed to node is masked (ie speedchecking necessary), set to s100.
2578				// This is because we treat an "ignored" node as a unresponsive node (eg hub)
2579				// and if we were to speedcheck it, we would step-down to s100, unmasked.
2580				if( FWSpeed( nodeID ) & kFWSpeedUnknownMask )
2581					setNodeSpeed(scan->fAddr.nodeID, kFWSpeed100MBit);
2582				// else, do not change current speed to node, which is concurrent with
2583				// the non-ignore, non-speedchecking code below.
2584
2585				// using kIOReturnNotPermitted because, simply, it's different than
2586				// success, timeout, or bus reset.
2587				scan->fControl->readDeviceROM(scan, kIOReturnNotPermitted);
2588			}
2589			else
2590			{
2591				if( FWSpeed( nodeID ) & kFWSpeedUnknownMask )
2592				{
2593					setNodeSpeed(scan->fAddr.nodeID, fLocalNodeID, (FWSpeed(scan->fAddr.nodeID, fLocalNodeID) & ~kFWSpeedUnknownMask));
2594
2595					scan->fCmd->initAll(this, fBusGeneration, scan->fAddr, scan->fBuf, 1,
2596													&readROMGlue, scan);
2597
2598					FWKLOG(( "IOFireWireController::startBusScan speedchecking\n" ));
2599					scan->speedChecking = true;	// May need to try speeds slower than s800 if this fails
2600												// zzz What about s1600?
2601				}
2602				else
2603				{
2604					scan->fCmd->initAll(this, fBusGeneration, scan->fAddr, scan->fBuf, 1,
2605													&readROMGlue, scan);
2606
2607					scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
2608					scan->speedChecking = false;
2609					FWKLOG(( "IOFireWireController::startBusScan not speedchecking\n" ));
2610				}
2611
2612				scan->fIRMBitBucketNew = 0xffffffff;
2613				scan->fIRMBitBucketOld = 0xffffffff;
2614
2615				scan->fLockCmd->initAll(this, fBusGeneration, scan->fAddr, &scan->fIRMBitBucketOld, &scan->fIRMBitBucketNew, 1, &readROMGlue, scan);
2616
2617				FWTrace( kFWTController, kTPControllerStartBusScan, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 1 );
2618
2619				scan->fCmd->setRetries(kFWCmdZeroRetries);  // don't need to bump kRetriesBumped here
2620				scan->fCmd->submit();
2621
2622			}
2623        }
2624    }
2625
2626    if(fNumROMReads == 0) {
2627		FWTrace( kFWTController, kTPControllerStartBusScan, (uintptr_t)fFWIM, 0, 0, 2 );
2628        finishedBusScan();
2629    }
2630
2631	FWKLOG(( "IOFireWireController::startBusScan exited\n" ));
2632}
2633
2634// readROMGlue
2635//
2636//
2637
2638void IOFireWireController::readROMGlue(void *refcon, IOReturn status,
2639			IOFireWireNub *device, IOFWCommand *fwCmd)
2640{
2641    IOFWNodeScan *scan = (IOFWNodeScan *)refcon;
2642    scan->fControl->readDeviceROM(scan, status);
2643}
2644
2645// readDeviceROM
2646//
2647//
2648
2649void IOFireWireController::readDeviceROM(IOFWNodeScan *scan, IOReturn status)
2650{
2651    bool done = true;
2652
2653	FWTrace( kFWTController, kTPControllerReadDeviceROM, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), status, 0 );
2654	FWKLOG(( "IOFireWireController::readDeviceROM entered\n" ));
2655
2656    if(status != kIOReturnSuccess)
2657	{
2658		// If status isn't bus reset, make a dummy registry entry.
2659
2660		if(status == kIOFireWireBusReset)
2661		{
2662            scan->fCmd->release();
2663            scan->fLockCmd->release();
2664            IOFree(scan, sizeof(*scan));
2665			FWKLOG(( "IOFireWireController::readDeviceROM exited\n" ));
2666			return;
2667        }
2668
2669        if( scan->fCmd->getAckCode() == kFWAckBusyX || scan->fCmd->getAckCode() == kFWAckBusyA || scan->fCmd->getAckCode() == kFWAckBusyB )
2670        {
2671        	// Newer Macs with only one FW port will turn off the PHY on sleep. Some hard disks go into a low-power sleep mode if they are the only
2672        	// node on the bus. Some of these are larger devices which take a long time to spin up once the Mac wakes again. These drives seem to return
2673        	// AckBusyX when spinning up. If we see this from any device on the bus and we've just woken up then we need to wait some additional time for
2674        	// the drives to spin up or else the user will get an unplug notice.
2675        	//
2676        	// rdar://problem/6190408
2677        	// rdar://problem/6237407
2678
2679			if( fDevicePruneDelay >= kWakeDevicePruneDelay && fDevicePruneDelay < kWakeDevicePruneDelayBusy )
2680				fDevicePruneDelay = kWakeDevicePruneDelayBusy;
2681        }
2682
2683        if( scan->fIRMCheckingRead || scan->fIRMCheckingLock )
2684		{
2685 			// IOLog("Bad IRM for Node 0x%x Rd %d Lk %d\n",scan->fAddr.nodeID,scan->fIRMCheckingRead,scan->fIRMCheckingLock);
2686			if( (scan->fAddr.nodeID & 63) == (fIRMNodeID & 63) )
2687				fBadIRMsKnown = true;
2688
2689			scan->fIRMisBad = true;
2690			scan->fContenderNeedsChecking = false;
2691		}
2692		else
2693		{
2694
2695			// "Naughty Camera Workaround"
2696			// If a "slow" device responds AckPending to the first attempt of the first BIB ReadQuad during
2697			// BusScan AND TIMES OUT (no ReadResp), we increase the number of times that ReadQuad may retry it's command
2698			// because we know the device is there, but not ready to respond to ConfigROM reads.
2699
2700			// This "if" should run after trying the command once, but before it retries.
2701			// Check if command timed out and we haven't increased the retries for this speed
2702			if( status == kIOReturnTimeout && scan->fRetriesBumped == 0 )
2703			{
2704				// Limit workaround to BIBHeaderAddress to avoid long delay caused by a really slow device
2705				// (e.g. hung node) ackPending any attempt to read any address. This will make sure we don't wait
2706				// "too" long while trying to collect all GUIDs, like lose our time to reconnect to an SBP2 device.
2707				if ( scan->fCmd->getAckCode() == kFWAckPending && scan->fAddr.addressLo == kConfigBIBHeaderAddress )
2708				{
2709					FWKLOG(( "IOFireWireController::readDeviceROM Node 0x%x timed out on ack %d, setting setMaxRetries = %d\n", scan->fAddr.nodeID, scan->fCmd->getAckCode(), kFWCmdIncreasedRetries));
2710
2711					// increase retries and set RetriesBumped flag
2712					scan->fCmd->setRetries(kFWCmdIncreasedRetries);
2713					scan->fRetriesBumped++;
2714
2715					FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 1 );
2716
2717					// re-submit command for increased number of retries
2718					scan->fCmd->reinit(scan->fAddr, scan->fBuf, 1, &readROMGlue, scan, true);
2719					scan->fCmd->submit();
2720					return;
2721				}
2722				else
2723				{
2724					// increase retries to normal-1 and set RetriesBumped flag
2725					scan->fCmd->setRetries(kFWCmdReducedRetries);
2726					scan->fRetriesBumped++;
2727
2728					FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 2 );
2729
2730					// re-submit command for the rest of the retries
2731					scan->fCmd->reinit(scan->fAddr, scan->fBuf, 1, &readROMGlue, scan, true);
2732					scan->fCmd->submit();
2733					return;
2734				}
2735			}
2736
2737
2738			// Speed checking for 1394b compatibility
2739			FWKLOG(( "IOFireWireController::readDeviceROM speedcheck %lx ; speed %lx\n", (UInt32)scan->speedChecking, (UInt32)FWSpeed( scan->fAddr.nodeID ) ));
2740			if( scan->speedChecking && FWSpeed( scan->fAddr.nodeID ) > kFWSpeed100MBit )
2741			{
2742				if( scan->generation == fBusGeneration )
2743				{
2744					FWKLOG(( "IOFireWireController::readDeviceROM reseting speed for node %lx from local %lx\n", (UInt32)scan->fAddr.nodeID, (UInt32)fLocalNodeID));
2745					if( fDSLimited )
2746					{
2747						setNodeSpeed(scan->fAddr.nodeID, fLocalNodeID, kFWSpeed100MBit);
2748					}
2749					else
2750					{
2751						setNodeSpeed(scan->fAddr.nodeID, fLocalNodeID, (FWSpeed(scan->fAddr.nodeID, fLocalNodeID) - 1));
2752					}
2753
2754					// Retry command at slower speed
2755					scan->fCmd->reinit(scan->fAddr, scan->fBuf, 1, &readROMGlue, scan, true);
2756
2757					if ( scan->fAddr.addressLo == kConfigBIBHeaderAddress )
2758					{
2759						// Reset to run Naughty Camera check on first try of QRead at next speed
2760						scan->fCmd->setRetries(kFWCmdZeroRetries);
2761						scan->fRetriesBumped = 0;
2762					}
2763					else
2764					{
2765						scan->fCmd->setRetries(kFWCmdDefaultRetries);
2766						scan->fRetriesBumped = 0;
2767					}
2768
2769					FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 3 );
2770
2771					scan->fCmd->submit();
2772					return;
2773				}
2774			}
2775
2776			if( (scan->fAddr.nodeID & 63) == (fIRMNodeID & 63) )
2777				fBadIRMsKnown = true;
2778
2779			UInt32 nodeID = FWAddressToID(scan->fAddr.nodeID);
2780			fNodes[nodeID] = createDummyRegistryEntry( scan );
2781
2782			fNumROMReads--;
2783			if(fNumROMReads == 0)
2784			{
2785				FWTrace( kFWTController, kTPControllerReadDeviceROM, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), status, 1 );
2786				finishedBusScan();
2787			}
2788
2789			scan->fCmd->release();
2790			scan->fLockCmd->release();
2791			IOFree(scan, sizeof(*scan));
2792			FWKLOG(( "IOFireWireController::readDeviceROM exited\n" ));
2793			return;
2794		}
2795    }
2796
2797    if( scan->fRead == 0 )
2798	{
2799		UInt32 bib_quad = OSSwapBigToHostInt32( scan->fBuf[0] );
2800		if( ((bib_quad & kConfigBusInfoBlockLength) >> kConfigBusInfoBlockLengthPhase) == 1)
2801		{
2802            // Minimal ROM
2803            scan->fROMSize = 4;
2804            done = true;
2805		}
2806		else
2807		{
2808            scan->fROMSize = 20;	// Just read bus info block
2809            scan->fRead = 8;
2810            scan->fBuf[1] = OSSwapHostToBigInt32( kFWBIBBusName );	// no point reading this!
2811            scan->fAddr.addressLo = kConfigROMBaseAddress+8;
2812            scan->fCmd->reinit(scan->fAddr, scan->fBuf+2, 1,
2813                                                        &readROMGlue, scan, true);
2814            scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
2815			scan->fCmd->setRetries( kFWCmdDefaultRetries );
2816			scan->fCmd->setPingTime( true );	// ping time second quad
2817
2818			FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 4 );
2819
2820			scan->fCmd->submit();
2821            done = false;
2822		}
2823    }
2824    else if( scan->fRead < 16 )
2825	{
2826        if(scan->fROMSize > scan->fRead)
2827		{
2828            scan->fRead += 4;
2829            scan->fAddr.addressLo = kConfigROMBaseAddress+scan->fRead;
2830            scan->fCmd->reinit(scan->fAddr, scan->fBuf+scan->fRead/4, 1,
2831                                                        &readROMGlue, scan, true);
2832            scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
2833			scan->fCmd->setRetries(kFWCmdDefaultRetries);
2834			scan->fCmd->setPingTime( false );	// only ping time on the second quad
2835
2836			FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 5 );
2837
2838			scan->fCmd->submit();
2839            done = false;
2840        }
2841        else
2842        {
2843           		done = true;
2844        }
2845    }
2846    else if( scan->fContenderNeedsChecking && (FWSpeed( scan->fAddr.nodeID ) > kFWSpeed100MBit) )
2847	{
2848		// Only do this check if node is > 100 MBit. s100 devices are nearly always camcorders and not likely to have
2849		// non-functional IRMs.
2850
2851		// Need to know if this is a capable IRM if this node is already IRM or if Mac doesn't
2852		// want to be IRM and this is a candidate.
2853
2854		if( ((scan->fAddr.nodeID & 63) == (fIRMNodeID & 63)) || fDelegateCycleMaster )
2855		{
2856			if( !scan->fIRMCheckingRead )
2857			{
2858				scan->fIRMCheckingRead = true;				// Doing the Read check this go-around
2859
2860				scan->fAddr.addressLo = kCSRChannelsAvailable63_32;
2861				scan->fCmd->reinit(scan->fAddr, &scan->fIRMBitBucketOld, 1,
2862															&readROMGlue, scan, true);
2863				scan->fCmd->setMaxSpeed( kFWSpeed100MBit );
2864				scan->fCmd->setRetries(kFWCmdDefaultRetries);
2865
2866				FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 6 );
2867				scan->fCmd->submit();
2868				done = false;
2869			}
2870			else
2871			{
2872
2873				// IOLog("Checking IRM for Node 0x%x\n",scan->fAddr.nodeID);
2874				scan->fIRMCheckingLock = true;				// Doing the Lock check this go-around
2875				scan->fContenderNeedsChecking = false;		// Don't check again
2876				scan->fAddr.addressLo = kCSRChannelsAvailable63_32;
2877
2878				scan->fLockCmd->reinit( scan->generation, scan->fAddr, &scan->fIRMBitBucketOld, &scan->fIRMBitBucketNew, 1, &readROMGlue, scan);
2879
2880				scan->fLockCmd->setMaxSpeed( kFWSpeed100MBit );
2881				scan->fLockCmd->setRetries(kFWCmdDefaultRetries);
2882
2883				FWTrace( kFWTController, kTPControllerReadDeviceROMSubmitCmd, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 7 );
2884				scan->fLockCmd->submit();
2885				done = false;
2886			}
2887		}
2888	}
2889
2890
2891
2892    if( done )
2893	{
2894		UInt32	nodeID = FWAddressToID(scan->fAddr.nodeID);
2895
2896		FWKLOG(( "IOFireWireController::readDeviceROM scan for ID %lx is %lx\n",nodeID,(long) scan ));
2897		fScans[nodeID] = scan;
2898
2899 		updateDevice( scan );
2900
2901       	fNumROMReads--;
2902        if(fNumROMReads == 0)
2903		{
2904			FWTrace( kFWTController, kTPControllerReadDeviceROM, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), status, 2 );
2905            finishedBusScan();
2906        }
2907
2908    }
2909
2910	FWKLOG(( "IOFireWireController::readDeviceROM exited\n" ));
2911}
2912
2913// checkForDuplicateGUID
2914//
2915//
2916bool IOFireWireController::checkForDuplicateGUID(IOFWNodeScan *scan, CSRNodeUniqueID *currentGUIDs )
2917{
2918	CSRNodeUniqueID guid;
2919	UInt32 nodeID;
2920	UInt32 i;
2921
2922	nodeID = FWAddressToID(scan->fAddr.nodeID);
2923
2924	if(scan->fROMSize >= 20)
2925	{
2926		UInt32 guid_hi = OSSwapBigToHostInt32( scan->fBuf[3] );
2927		UInt32 guid_lo = OSSwapBigToHostInt32( scan->fBuf[4] );
2928
2929		guid = ((CSRNodeUniqueID)guid_hi << 32) | guid_lo;
2930	}
2931	else
2932	{
2933		currentGUIDs[nodeID] = 0;
2934		return false;	// not a real ROM, don't care.
2935	}
2936
2937	currentGUIDs[nodeID] = guid;
2938
2939	if( !guid || fGUIDDups->findDuplicateGUID( guid, fBusGeneration ) )
2940		return false;	// Already found or zero, don't add it. Return false so caller doesn't reset the bus again
2941
2942	for( i = 0; i< nodeID; i++ )
2943	{
2944		if( currentGUIDs[i] == guid )
2945		{
2946			fGUIDDups->addDuplicateGUID( guid, fBusGeneration );
2947			return true;
2948		}
2949	}
2950
2951	return false;
2952}
2953
2954// updateDevice
2955//
2956//
2957
2958void IOFireWireController::updateDevice(IOFWNodeScan *scan )
2959{
2960	FWTrace( kFWTController, kTPControllerUpdateDevice, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, 0 );
2961
2962	// See if this is a bus manager
2963	UInt32 bib_quad = OSSwapBigToHostInt32( scan->fBuf[2] );
2964	if( !fBusMgr )
2965	{
2966		fBusMgr = bib_quad & kFWBIBBmc;
2967	}
2968
2969// Check if node exists, if not create it
2970#if (DEBUGGING_LEVEL > 0)
2971	IOLog("Update Device Finished reading ROM for node 0x%x\n", scan->fAddr.nodeID);
2972#endif
2973	IOFireWireDevice *	newDevice = NULL;
2974	do
2975	{
2976		CSRNodeUniqueID guid;
2977		OSIterator *childIterator;
2978		UInt32 nodeID;
2979		bool duplicate;
2980		bool minimal = false;
2981
2982		nodeID = FWAddressToID(scan->fAddr.nodeID);
2983
2984		if(scan->fROMSize >= 20)
2985        {
2986			UInt32 guid_hi = OSSwapBigToHostInt32( scan->fBuf[3] );
2987			UInt32 guid_lo = OSSwapBigToHostInt32( scan->fBuf[4] );
2988
2989		    guid = ((CSRNodeUniqueID)guid_hi << 32) | guid_lo;
2990		}
2991		else
2992		{
2993			minimal = true;
2994			guid = 0;
2995		}
2996
2997		//
2998		// GUID zero is not a valid GUID. Unfortunately some devices return this as
2999		// their GUID until they're fully powered up.
3000		//
3001		//
3002
3003		// Also check nodes for known bad GUIDs and don't bother with them
3004		//
3005
3006		duplicate = fGUIDDups->findDuplicateGUID( guid, fBusGeneration );
3007
3008		if( (guid == 0) || duplicate )
3009		{
3010			fNodes[nodeID] = createDummyRegistryEntry( scan );
3011			if( minimal )
3012			{
3013				OSObject * prop = OSData::withBytes( &scan->fBuf[0], scan->fROMSize );
3014				if( prop != NULL )
3015				{
3016					fNodes[nodeID]->setProperty( gFireWireROM, prop );
3017					prop->release();
3018				}
3019			}
3020			else
3021			{
3022				OSObject * prop = OSNumber::withNumber( guid, 64 );
3023				if( prop != NULL )
3024				{
3025					fNodes[nodeID]->setProperty( gFireWire_GUID, prop );
3026					prop->release();
3027
3028				}
3029			}
3030// 			if( duplicate )
3031// 			{
3032//
3033// 				OSString * prop = OSString::withCString("Device with illegal duplicate GUID");
3034// 				if( prop2 != NULL )
3035// 				{
3036// 					fNodes[nodeID]->setProperty( gFireWireProduct_Name, prop );
3037// 					prop->release();
3038// 				}
3039// 			}
3040			continue;
3041		}
3042
3043		childIterator = getClientIterator();
3044		if( childIterator)
3045		{
3046			OSObject *child;
3047			while( (child = childIterator->getNextObject()))
3048			{
3049				IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
3050				if( found )
3051				{
3052					// sync with open / close routines on device
3053					found->lockForArbitration();
3054
3055					if( found->fUniqueID == guid && (found->getTerminationState() != kTerminated) )
3056					{
3057						newDevice = found;
3058
3059						// arbitration lock still held
3060
3061						break;
3062					}
3063
3064					found->unlockForArbitration();
3065				}
3066			}
3067			childIterator->release();
3068		}
3069
3070		if(newDevice)
3071		{
3072			FWTrace( kFWTController, kTPControllerUpdateDeviceNewDevice, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, (uintptr_t)newDevice );
3073
3074			// Just update device properties.
3075			#if IOFIREWIREDEBUG > 0
3076				IOLog("UpdateDevice Found old device 0x%p\n", newDevice);
3077			#endif
3078
3079			// arbitration lock still held
3080
3081			if( newDevice->getTerminationState() == kNeedsTermination )
3082			{
3083				newDevice->setTerminationState( kNotTerminated );
3084			}
3085
3086			newDevice->unlockForArbitration();
3087
3088			newDevice->setNodeROM(fBusGeneration, fLocalNodeID, scan);
3089			newDevice->retain();	// match release, since not newly created.
3090		}
3091		else
3092		{
3093			newDevice = fFWIM->createDeviceNub(guid, scan);
3094			if (!newDevice)
3095				continue;
3096
3097			FWTrace( kFWTController, kTPControllerUpdateDeviceCreateDevice, (uintptr_t)fFWIM, (uintptr_t)(scan->fCmd), scan->fAddr.nodeID, (uintptr_t)newDevice );
3098
3099			#if IOFIREWIREDEBUG > 0
3100				IOLog("Update Device Creating new device 0x%p\n", newDevice);
3101			#endif
3102
3103			// In response to <rdar://7116134>. Logging here to see if we can find a reproducible case of this panic.
3104			ErrorLogCond( !newDevice, "IOFireWireController@%p::updateDevice Error creating device nub! (%p, %p)\n", this, fFWIM, newDevice );
3105
3106			// we must stay busy until we've called registerService on the device
3107			// and all of its units
3108
3109			newDevice->adjustBusy( 1 ); // device
3110			adjustBusy( 1 );  // controller
3111
3112			FWKLOG(( "IOFireWireController@%p::updateDevice adjustBusy(1)\n", this ));
3113
3114			// hook this device into the device tree now
3115
3116			// we won't rediscover this device after a bus reset if the device is
3117			// not in the registry.  if we attached later and got a bus reset before
3118			// we had attached the device we would leak the device object
3119
3120			if( !newDevice->attach(this) )
3121			{
3122				// if we failed to attach, I guess we're not busy anymore
3123				newDevice->adjustBusy( -1 );  // device
3124				adjustBusy( -1 );  // controller
3125				FWKLOG(( "IOFireWireController@%p::updateDevice adjustBusy(-1)\n", this ));
3126				continue;
3127			}
3128
3129			// we will register this service once we finish reading the config rom
3130			newDevice->setRegistrationState( IOFireWireDevice::kDeviceNeedsRegisterService );
3131
3132			// this will start the config ROM read
3133			newDevice->setNodeROM( fBusGeneration, fLocalNodeID, scan );
3134
3135		}
3136
3137		fNodes[nodeID] = newDevice;
3138		fNodes[nodeID]->retain();
3139
3140	} while (false);
3141
3142	if (newDevice)
3143		newDevice->release();
3144
3145}
3146
3147
3148
3149// createDummyRegistryEntry
3150//
3151// if we are unable to successfully read the BIB of a a device, we create
3152// a dummy registry entry by calling this routine
3153
3154IORegistryEntry * IOFireWireController::createDummyRegistryEntry( IOFWNodeScan *scan )
3155{
3156	OSDictionary *propTable;
3157	OSObject * prop;
3158	propTable = OSDictionary::withCapacity(3);
3159	prop = OSNumber::withNumber(scan->fAddr.nodeID, 16);
3160	propTable->setObject(gFireWireNodeID, prop);
3161	prop->release();
3162
3163	prop = OSNumber::withNumber((OSSwapBigToHostInt32(scan->fSelfIDs[0]) & kFWSelfID0SP) >> kFWSelfID0SPPhase, 32);
3164	propTable->setObject(gFireWireSpeed, prop);
3165	prop->release();
3166
3167	prop = OSData::withBytes(scan->fSelfIDs, scan->fNumSelfIDs*sizeof(UInt32));
3168	propTable->setObject(gFireWireSelfIDs, prop);
3169	prop->release();
3170
3171	IORegistryEntry * newPhy;
3172	newPhy = OSTypeAlloc( IORegistryEntry );
3173	if(newPhy)
3174	{
3175		if(!newPhy->init(propTable))
3176		{
3177			newPhy->release();
3178			newPhy = NULL;
3179		}
3180        if(getSecurityMode() == kIOFWSecurityModeNormal) {
3181            // enable physical access for FireBug and other debug tools without a ROM
3182            setNodeIDPhysicalFilter( scan->fAddr.nodeID & 0x3f, true );
3183        }
3184        if(propTable)
3185            propTable->release();
3186	}
3187
3188	return newPhy;
3189}
3190
3191// finishedBusScan
3192//
3193//
3194
3195void IOFireWireController::finishedBusScan()
3196{
3197	FWTrace_Start( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, 0, 0, 0 );
3198
3199    // These magic numbers come from P1394a, draft 4, table C-2.
3200    // This works for cables up to 4.5 meters and PHYs with
3201    // PHY delay up to 144 nanoseconds.  Note that P1394a PHYs
3202    // are allowed to have delay >144nS; we don't cope yet.
3203    static UInt32 gaps[26] = {63, 5, 7, 8, 10, 13, 16, 18, 21,
3204                            24, 26, 29, 32, 35, 37, 40, 43,
3205                            46, 48, 51, 54, 57, 59, 62, 63};
3206  	int		i;
3207
3208	if(	AssignCycleMaster() )
3209	{
3210		FWTrace_End( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, 0, 0, 1 );
3211		return;
3212    }
3213
3214    fBadIRMsKnown = false; 	// If we got here we're happy with the IRM/CycleMaster. No need to read the IRM registers for all nodes
3215
3216    // Go update all the devices now that we've read their ROMs.
3217    {
3218 		CSRNodeUniqueID			currentGUIDs[kFWMaxNodesPerBus];
3219
3220 		// First check for duplicate GUIDs
3221		for( i=0; i<=fRootNodeID; i++ )
3222		{
3223			if( fScans[i] )
3224			{
3225				if( checkForDuplicateGUID( fScans[i], currentGUIDs ) )
3226				{
3227					// Whoops, duplicate GUID! Reset Bus and bail.
3228					// From now on if UpdateDevice is called with this GUID we won't
3229					// reconnect to it.
3230
3231					FWTrace(kFWTResetBusAction, kTPResetFinishedBusScan, (uintptr_t)fFWIM, fScans[i]->fAddr.nodeID, 1, 0 );
3232                	resetBus();
3233
3234					FWTrace_End( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, 0, 0, 2 );
3235					return;			// We'll be right back after these messages from our sponsor
3236				}
3237
3238				fScans[i]->fCmd->release();
3239				fScans[i]->fLockCmd->release();
3240				IOFree(fScans[i], sizeof(*fScans[i]));
3241				fScans[i] = NULL;
3242
3243			}
3244  			else
3245  			{
3246  				currentGUIDs[i] = 0;
3247  			}
3248  		}
3249  	}
3250
3251    // Now do simple bus manager stuff, if there isn't a better candidate.
3252    // This might cause us to issue a bus reset...
3253    // Skip if we're about to reset anyway, since we might be in the process of setting
3254    // another node to root.
3255    if( !fBusResetScheduled && !fBusMgr && fLocalNodeID == fIRMNodeID)
3256	{
3257  		UInt32 * pingTimes;
3258        int maxHops;
3259  	 	UInt32	maxPing = 0;
3260 		UInt32	pingGap=0, hopGap=0, newGap=0;
3261 		bool	retoolGap = false;
3262
3263		if ( not fForcedGapFlag )
3264		{
3265			// Set the gap count based on maximum ping time. This assumes the Mac is not in the middle
3266			// of a star with long haul's going out in two different directions from the Mac. To obtain
3267			// the gap cound we use the following algorithm:
3268			//
3269			// 		Gap = GapTable[ (MaxPing - 20) / 9 ]
3270
3271			// This result is then compared to the value arrived at with the standard hop count based
3272			// table lookup. The higher value is used for the new gap.
3273
3274			// If we don't have ping time information (such as with a Lynx FWIM that doesn't support
3275			// ping timimg) then we use the maximum hop count to index into the table.
3276
3277			// Do lazy gap count optimization.  Assume the bus is a daisy-chain (worst
3278			// case) so hop count == root ID.
3279
3280			// a little note on the gap count optimization - all I do is set an internal field to our optimal
3281			// gap count and then reset the bus. my new soft bus reset code sets the gap count before resetting
3282			// the bus (for another reason) and I just rely on that fact.
3283
3284			pingTimes = fFWIM->getPingTimes();
3285
3286			for( i=0; i<=fRootNodeID; i++ )
3287			{
3288				//IOLog("IOFireWireController node 0x%lx ping 0x%lx\n",i,pingTimes[i]);
3289
3290				if( pingTimes[i] > maxPing )
3291					maxPing = pingTimes[i];
3292			}
3293
3294			maxHops = fRootNodeID;
3295			if (maxHops > 25)
3296				maxHops = 25;
3297
3298			if( maxPing > 245 )
3299				maxPing = 245;
3300
3301			if( maxPing >= 29 )
3302				pingGap = gaps [(maxPing - 20) / 9];	// Assumes Mac is NOT in the middle of 2 long haul subnets
3303			else
3304				pingGap = 5;
3305
3306			hopGap = gaps[maxHops];
3307
3308			if( hopGap > pingGap )
3309				newGap = hopGap;
3310			else
3311				newGap = pingGap;
3312
3313			// IOLog("IOFireWireController MaxPingTime: 0x%lx PingGap: 0x%lx HopGap: 0x%lx Setting Gap to 0x%lx\n",maxPing, pingGap, hopGap, newGap);
3314			fGapCount = newGap << kFWPhyConfigurationGapCntPhase;
3315		}
3316		else
3317		{
3318			if( fPreviousGap != (fForcedGapCount << kFWPhyConfigurationGapCntPhase)  )
3319			{
3320				fGapCount = fForcedGapCount << kFWPhyConfigurationGapCntPhase;
3321				retoolGap = true;
3322				IOLog( "IOFireWireController::finishedBusScan retoold GAP %d\n", __LINE__ );
3323			}
3324		}
3325
3326       	FWKLOG(("IOFireWireController MaxPingTime: 0x%lx PingGap: 0x%lx HopGap: 0x%lx Setting Gap to 0x%lx\n",maxPing, pingGap, hopGap, newGap));
3327		FWTrace( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, pingGap, hopGap, newGap );
3328
3329		fGapCount = ( fForcedGapFlag ) ? fForcedGapCount << kFWPhyConfigurationGapCntPhase : newGap << kFWPhyConfigurationGapCntPhase;
3330
3331
3332        if(fRootNodeID == 0)
3333        {
3334            // If we're the only node, clear root hold off.
3335            fFWIM->setRootHoldOff(false);
3336        }
3337        else
3338        {
3339            // Send phy packet to get rid of other root hold off nodes
3340            // Set gap count too.
3341            fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
3342                        ((fLocalNodeID & 63) << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR );
3343            fFWIM->setRootHoldOff(true);
3344
3345            // If we aren't root, issue a bus reset so that we will be.
3346            if(fRootNodeID != (fLocalNodeID & 63))
3347            {
3348				// IOLog( "IOFireWireController::finishedBusScan - make us root\n" );
3349				FWTrace(kFWTResetBusAction, kTPResetFinishedBusScan, (uintptr_t)fFWIM, 0, 2, 0 );
3350
3351                resetBus();
3352
3353				FWKLOG(( "IOFireWireController::finishedBusScan exited\n" ));
3354				FWTrace_End( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, 0, 0, 3 );
3355				return;			// We'll be back...
3356            }
3357        }
3358
3359        // If we got here we're root, so turn on cycle master
3360        fFWIM->setCycleMaster(true);
3361
3362        // Finally set gap count if any nodes don't have the right gap.
3363        // Only bother if we aren't the only node on the bus.
3364        // To avoid changing the gap due to ping time jitter we check to see that the gaps
3365        // are both consistent and either the same as we last set it or the same as the new gap.
3366
3367
3368        if(fRootNodeID != 0)
3369        {
3370           	// is the gap count consistent?
3371            for( i = 1; i <= fRootNodeID; i++ )
3372            {
3373                if( (OSSwapBigToHostInt32(*fNodeIDs[i]) & kFWSelfID0GapCnt) != (OSSwapBigToHostInt32(*fNodeIDs[i - 1]) & kFWSelfID0GapCnt) )
3374				{
3375                	//IOLog( "IOFireWireController::finishedBusScan inconsistent gaps!\n");
3376                	retoolGap = true;
3377                	break;
3378                }
3379            }
3380
3381            if( !retoolGap && !fDSLimited )
3382            {
3383				// is the gap something we set?
3384				for( i = 0; i <= fRootNodeID; i++ )
3385				{
3386					if( ((OSSwapBigToHostInt32(*fNodeIDs[i]) & kFWSelfID0GapCnt) != fPreviousGap
3387									&& (OSSwapBigToHostInt32(*fNodeIDs[i]) & kFWSelfID0GapCnt) != fGapCount)
3388							|| ((OSSwapBigToHostInt32(*fNodeIDs[i]) & kFWSelfID0GapCnt) == 0) )
3389					{
3390                		//IOLog( "IOFireWireController::finishedBusScan need new gap count\n");
3391						retoolGap = true;
3392						break;
3393					}
3394				}
3395			}
3396
3397            if( retoolGap )
3398            {
3399
3400            	//IOLog( "IOFireWireController::finishedBusScan prev: %08lx new: %08lx node: %08lx\n",fPreviousGap, fGapCount, (*fNodeIDs[i] & kFWSelfID0GapCnt) );
3401
3402            	fPreviousGap = fGapCount;
3403
3404				// send phy config packet and do bus reset.
3405				fDelayedPhyPacket = (kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
3406									((fLocalNodeID & 63) << kFWPhyPacketPhyIDPhase) |
3407									kFWPhyConfigurationR | fGapCount | kFWPhyConfigurationT;
3408				//	IOLog( "IOFireWireController::finishedBusScan - set gap count\n" );
3409
3410				FWTrace(kFWTResetBusAction, kTPResetFinishedBusScan, (uintptr_t)fFWIM, fGapCount, 3, 0 );
3411
3412				resetBus();
3413
3414				FWKLOG(( "IOFireWireController::finishedBusScan exited\n" ));
3415				FWTrace_End( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, 0, 0, 4 );
3416				return;			// We'll be back...
3417            }
3418        }
3419    }
3420
3421
3422	//
3423    // Don't change to the waiting prune state if we're about to bus reset again anyway.
3424    //
3425
3426	if(fBusState == kScanning)
3427	{
3428		bool 			wouldTerminateDevice = false;
3429		OSIterator *	childIterator;
3430
3431		//
3432		// check if we would terminate a device if the prune timer ran right now
3433		//
3434
3435		childIterator = getClientIterator();
3436		if( childIterator )
3437		{
3438			OSObject *child;
3439			while( (child = childIterator->getNextObject()))
3440			{
3441				IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
3442
3443				// don't need to sync with open/close routines when checking for kNotTerminated
3444				if( found && (found->getTerminationState() == kNotTerminated) && found->fNodeID == kFWBadNodeID )
3445				{
3446					wouldTerminateDevice = true;
3447				}
3448			}
3449			childIterator->release();
3450		}
3451
3452		//
3453		// if we found all of our devices, set the prune delay to normal
3454		//
3455
3456		if( (fRootNodeID == 0) && (fDevicePruneDelay < kOnlyNodeDevicePruneDelay) )
3457		{
3458			// if we're the only node increase the prune delay
3459			// because we won't be causing a bus reset for gap
3460			// count optimization.
3461
3462			fDevicePruneDelay = kOnlyNodeDevicePruneDelay;
3463		}
3464
3465		if( !wouldTerminateDevice )
3466		{
3467			fDevicePruneDelay = kNormalDevicePruneDelay;
3468		}
3469
3470        fBusState = kWaitingPrune; 	// Indicate end of bus scan
3471        fDelayedStateChangeCmd->reinit(1000 * fDevicePruneDelay, delayedStateChange, NULL); // One second
3472		FWTrace(kFWTStateChangeAction, kTPStateChangeFinishedBusScan, (uintptr_t)fFWIM, fBusState, 0, 0 );
3473        fDelayedStateChangeCmd->submit();
3474    }
3475
3476    // Run all the commands that are waiting for reset processing to end
3477    IOFWCmdQ &resetQ(getAfterResetHandledQ());
3478    resetQ.executeQueue(true);
3479
3480    // Anything on queue now is associated with a device not on the bus, I think...
3481    IOFWCommand *cmd;
3482    while( (cmd = resetQ.fHead) )
3483	{
3484        cmd->cancel(kIOReturnTimeout);
3485    }
3486
3487	FWKLOG(( "IOFireWireController::finishedBusScan exited\n" ));
3488	FWTrace_End( kFWTController, kTPControllerFinishedBusScan, (uintptr_t)fFWIM, 0, 0, 0 );
3489}
3490
3491// countNodeIDChildren
3492//
3493//
3494
3495UInt32 IOFireWireController::countNodeIDChildren( UInt16 nodeID, int hub_port, int * hubChildRemainder, bool * hubParentFlag )
3496{
3497	UInt32 id0, idn;
3498	UInt32 *idPtr;
3499	int i;
3500	int children = 0;
3501	int ports;
3502	UInt32 port;
3503	int mask, shift;
3504
3505	if( hub_port > 2 )
3506	{
3507		// we currently only look at self id type 0 since we don't currently ship >3 port phys
3508		IOLog( "IOFireWireController::countNodeIDChildren - hub_port = %d out of range.\n", hub_port );
3509	}
3510
3511	// get type 0 self id
3512	i = nodeID & 63;
3513	idPtr = fNodeIDs[i];
3514	id0 = OSSwapBigToHostInt32(*idPtr++);
3515	mask = kFWSelfID0P0;
3516	shift = kFWSelfID0P0Phase;
3517
3518	// count children
3519	// 3 ports in type 0 self id
3520	for(ports=0; ports<3; ports++)
3521	{
3522		port = (id0 & mask) >> shift;
3523		if(port == kFWSelfIDPortStatusChild)
3524		{
3525			children++;
3526		}
3527
3528		if( ports == hub_port )
3529		{
3530			if( port == kFWSelfIDPortStatusChild )
3531			{
3532				// when the topology builder gets down to the current child count
3533				// then we are at our hub
3534				if( hubChildRemainder != NULL )
3535					*hubChildRemainder = children;
3536			}
3537			else if( port == kFWSelfIDPortStatusParent )
3538			{
3539				// the hub us our parent
3540				if( hubParentFlag != NULL )
3541					*hubParentFlag = true;
3542			}
3543		}
3544
3545		mask >>= 2;
3546		shift -= 2;
3547	}
3548
3549	// any more self ids for this node?
3550	if(fNodeIDs[i+1] > idPtr)
3551	{
3552		// get type 1 self id
3553		idn = OSSwapBigToHostInt32(*idPtr++);
3554		mask = kFWSelfIDNPa;
3555		shift = kFWSelfIDNPaPhase;
3556
3557		// count children
3558		// 8 ports in type 1 self id
3559		for(ports=0; ports<8; ports++)
3560		{
3561			port = (idn & mask) >> shift;
3562			if(port == kFWSelfIDPortStatusChild)
3563				children++;
3564			mask >>= 2;
3565			shift -= 2;
3566		}
3567
3568		// any more self ids for this node?
3569		if(fNodeIDs[i+1] > idPtr)
3570		{
3571			// get type 2 self id
3572			idn = OSSwapBigToHostInt32(*idPtr++);
3573			mask = kFWSelfIDNPa;
3574			shift = kFWSelfIDNPaPhase;
3575
3576			// count children
3577			// 5 ports in type 2 self id
3578			for(ports=0; ports<5; ports++)
3579			{
3580				port = (idn & mask) >> shift;
3581				if(port == kFWSelfIDPortStatusChild)
3582					children++;
3583				mask >>= 2;
3584				shift -= 2;
3585			}
3586		}
3587	}
3588
3589	return children;
3590}
3591
3592// getPortNumberFromIndex
3593//
3594//
3595
3596UInt32 IOFireWireController::getPortNumberFromIndex( UInt16 index )
3597{
3598	UInt32 id0, idn;
3599	UInt32 *idPtr;
3600	int i;
3601	int children = 0;
3602	int ports;
3603	UInt32 port;
3604	int mask, shift;
3605
3606	// get type 0 self id
3607	i = fLocalNodeID & 63;
3608	idPtr = fNodeIDs[i];
3609	id0 = OSSwapBigToHostInt32(*idPtr++);
3610	mask = kFWSelfID0P0;
3611	shift = kFWSelfID0P0Phase;
3612
3613	// count children
3614	// 3 ports in type 0 self id
3615	for(ports=0; ports<3; ports++)
3616	{
3617		port = (id0 & mask) >> shift;
3618		if(port == kFWSelfIDPortStatusChild)
3619		{
3620			if( index == children )
3621				return ports;
3622			children++;
3623		}
3624		mask >>= 2;
3625		shift -= 2;
3626	}
3627
3628	// any more self ids for this node?
3629	if(fNodeIDs[i+1] > idPtr)
3630	{
3631		// get type 1 self id
3632		idn = OSSwapBigToHostInt32(*idPtr++);
3633		mask = kFWSelfIDNPa;
3634		shift = kFWSelfIDNPaPhase;
3635
3636		// count children
3637		// 8 ports in type 1 self id
3638		for(ports=0; ports<8; ports++)
3639		{
3640		if(port == kFWSelfIDPortStatusChild)
3641			{
3642				//zzz shouldn't ports be returned + 3?
3643				if( index == children )
3644					return ports;
3645				children++;
3646			}
3647			mask >>= 2;
3648			shift -= 2;
3649		}
3650	}
3651
3652	return 0xFFFFFFFF;
3653}
3654
3655// buildTopology
3656//
3657//
3658
3659void IOFireWireController::buildTopology(bool doFWPlane)
3660{
3661	FWTrace_Start( kFWTController, kTPControllerBuildTopology, (uintptr_t)fFWIM, (uintptr_t)doFWPlane, 0, 0 );
3662
3663    int  i, maxDepth;
3664    IORegistryEntry *root;
3665    struct FWNodeScan
3666    {
3667        int nodeID;
3668        int childrenRemaining;
3669		int hubChildRemainder;
3670		bool hubParentFlag;
3671        IORegistryEntry *node;
3672    };
3673    FWNodeScan scanList[kFWMaxNodesPerBus];
3674    FWNodeScan *level;
3675    maxDepth = 0;
3676    root = fNodes[fRootNodeID];
3677    level = scanList;
3678
3679    // First build the topology.
3680
3681	// iterate over all self ids starting with root id
3682	for(i=fRootNodeID; i>=0; i--)
3683	{
3684        UInt32 id0;
3685        UInt8 speedCode;
3686        IORegistryEntry *node = fNodes[i];
3687        int children = 0;
3688
3689		// count the children for this self id
3690		if( (i == (fLocalNodeID & 63)) && (fHubPort != kFWInvalidPort) )
3691		{
3692			// we use hubChildRemainder here to find the port connected to the builtin hub.
3693			// eg. if childrenRemaining is 3 and the hub is the 3rd child, hubChildRemainder will be 1.
3694			// obvious, no? it's weird like this because at this point in the project I don't want
3695			// to disturb the underlying enumeration algorithm which uses childrenRemaining for iteration.
3696
3697			bool hubParent = false;
3698			int hubChildRemainder = 0;
3699
3700			children = countNodeIDChildren( i, fHubPort, &hubChildRemainder, &hubParent );
3701
3702//			IOLog( "FireWire - buildtopology - node = %d, children = %d, hubPort = %d, hubChildRem = %d, hubParent = %d\n", i, children, fHubPort, hubChildRemainder, hubParent );
3703
3704			// Add node to bottom of tree
3705			level->nodeID = i;
3706			level->childrenRemaining = children;
3707			level->hubChildRemainder = hubChildRemainder;
3708			level->hubParentFlag = hubParent;
3709			level->node = node;
3710		}
3711		else
3712		{
3713			children = countNodeIDChildren( i );
3714
3715			// Add node to bottom of tree
3716			level->nodeID = i;
3717			level->childrenRemaining = children;
3718			level->hubChildRemainder = 0;
3719			level->hubParentFlag = false;
3720			level->node = node;
3721		}
3722
3723        // Add node's self speed to speedmap
3724		id0 = OSSwapBigToHostInt32(*fNodeIDs[i]);
3725		speedCode = (id0 & kFWSelfID0SP) >> kFWSelfID0SPPhase;
3726
3727        if( !doFWPlane )
3728        {
3729        	if( speedCode == kFWSpeedReserved )
3730        		speedCode = kFWSpeed800MBit | kFWSpeedUnknownMask;	// Remember that we don't know how fast it is
3731        }
3732
3733		if( fDSLimited && !(speedCode & kFWSpeedUnknownMask) )
3734      	{
3735			speedCode = kFWSpeed100MBit;
3736		}
3737
3738        setNodeSpeed(i, i, speedCode);
3739
3740        // Add to parent
3741        // Compute rest of this node's speed map entries unless it's the root.
3742        // We only need to compute speeds between this node and all higher node numbers.
3743        // These speeds will be the minimum of this node's speed and the speed between
3744        // this node's parent and the other higher numbered nodes.
3745        if (i != fRootNodeID)
3746		{
3747            int parentNodeNum, scanNodeNum;
3748            parentNodeNum = (level-1)->nodeID;
3749            if(doFWPlane)
3750            {
3751				FWNodeScan * parent_level = (level-1);
3752
3753				if( parent_level->hubChildRemainder == parent_level->childrenRemaining )
3754				{
3755					if( parent_level->childrenRemaining == 0 )
3756					{
3757						// this should be impossible
3758						IOLog( "IOFireWireController::buildTopology - parent child count is 0!\n" );
3759					}
3760					else
3761					{
3762						// we are the hub
3763						node->setProperty( "Built-in Hub", true );
3764					}
3765				}
3766				else if( level->hubParentFlag )
3767				{
3768					// our parent is the hub
3769					parent_level->node->setProperty( "Built-in Hub", true );
3770				}
3771
3772				if( (node != NULL) && (parent_level->node != NULL) )
3773				{
3774					node->attachToParent( parent_level->node, gIOFireWirePlane );
3775				}
3776
3777			}
3778           	else
3779           	{
3780				for (scanNodeNum = i + 1; scanNodeNum <= fRootNodeID; scanNodeNum++)
3781				{
3782					// Get speed code between parent and scan node.
3783					IOFWSpeed fwspeed = FWSpeed(parentNodeNum, scanNodeNum);
3784					if ( fwspeed > 0xFF )
3785						ErrorLog("Found oversized speed map entry during speed checking\n");
3786
3787					UInt8 scanSpeedCode = (UInt8)fwspeed;
3788
3789					UInt8 calcSpeedCode = scanSpeedCode;
3790					// Set speed map entry to minimum of scan speed and node's speed.
3791					if ( (speedCode & ~kFWSpeedUnknownMask) < (scanSpeedCode & ~kFWSpeedUnknownMask) )
3792					{
3793						calcSpeedCode = speedCode;
3794					}
3795
3796					if( (speedCode & kFWSpeedUnknownMask) || (scanSpeedCode & kFWSpeedUnknownMask) )
3797					{
3798						calcSpeedCode |= kFWSpeedUnknownMask;
3799					}
3800
3801					setNodeSpeed(i, scanNodeNum, calcSpeedCode);
3802				}
3803			}
3804        }
3805
3806        // Find next child port.
3807        if (i > 0)
3808		{
3809            while (level->childrenRemaining == 0)
3810			{
3811                // Go up one level in tree.
3812                level--;
3813                if(level < scanList)
3814				{
3815                    IOLog("SelfIDs don't build a proper tree (missing selfIDS?)!!\n");
3816                    return;
3817                }
3818                // One less child to scan.
3819                level->childrenRemaining--;
3820            }
3821            // Go down one level in tree.
3822            level++;
3823            if(level - scanList > maxDepth)
3824			{
3825                maxDepth = level - scanList;
3826            }
3827        }
3828    }
3829
3830	// Clear out the unknown speed mask for the local node. Not needed once we get here.
3831	// Other nodes with this flag will get cleared once we've decided to speed scan them.
3832	// We never speed scan the local node which means we'll never clear it otherwise.
3833	setNodeSpeed(fLocalNodeID, fLocalNodeID, (FWSpeed(fLocalNodeID, fLocalNodeID) & ~kFWSpeedUnknownMask));
3834
3835#if (DEBUGGING_LEVEL > 0)
3836	IOLog("MaxDepth:%d LocalNodeID:%x\n", maxDepth, fLocalNodeID);
3837	IOLog("FireWire Speed map:\n");
3838	for(i=0; i <= fRootNodeID; i++) {
3839		int j;
3840		for(j=0; j <= fRootNodeID; j++) {
3841			IOLog("%-2x ", (unsigned int)FWSpeed(i, j) );
3842		}
3843		IOLog("\n");
3844	}
3845#endif
3846#if 0
3847    if( doFWPlane )
3848	{
3849        IOLog( "FireWire Hop Counts:\n" );
3850        for( i=0; i <= fRootNodeID; i++ )
3851		{
3852            int j;
3853            for( j=0; j <= fRootNodeID; j++ )
3854			{
3855				if ( j < i )
3856					IOLog("_ ");
3857				else
3858					IOLog("%-2lu ", hopCount(i,j));
3859            }
3860            IOLog( "\n" );
3861        }
3862    }
3863#endif
3864
3865    // Finally attach the full topology into the IOKit registry
3866    if(doFWPlane && (root != NULL))
3867        root->attachToParent(IORegistryEntry::getRegistryRoot(), gIOFireWirePlane);
3868
3869	FWTrace_End( kFWTController, kTPControllerBuildTopology, (uintptr_t)fFWIM, (uintptr_t)doFWPlane, 0, 0 );
3870}
3871
3872// updatePlane
3873//
3874//
3875
3876void IOFireWireController::updatePlane()
3877{
3878	FWTrace( kFWTController, kTPControllerUpdatePlane, (uintptr_t)fFWIM, 0, 0, 0 );
3879
3880    OSIterator *childIterator;
3881	 bool foundTDM = false;
3882
3883	fDevicePruneDelay = kNormalDevicePruneDelay;
3884
3885    childIterator = getClientIterator();
3886    if( childIterator )
3887	{
3888        OSObject *child;
3889        while( (child = childIterator->getNextObject()))
3890		{
3891            IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
3892
3893			// don't need to sync with open/close routines when checking for kNotTerminated
3894			if( found && (found->getTerminationState() == kNotTerminated) )
3895            {
3896				if( found->fNodeID == kFWBadNodeID )
3897				{
3898					FWTrace( kFWTController, kTPControllerUpdatePlane, (uintptr_t)fFWIM, (uintptr_t)found, 1, 0 );
3899					terminateDevice( found );
3900				}
3901				else
3902				{
3903					OSString * tdm_string = OSDynamicCast( OSString, found->getProperty( gFireWireTDM ) );
3904
3905					if( (tdm_string != NULL) &&
3906						(strncmp( "PPC", tdm_string->getCStringNoCopy(), 4 ) == 0) )
3907					{
3908						foundTDM = true;
3909					}
3910				}
3911			}
3912        }
3913        childIterator->release();
3914    }
3915
3916	OSObject * existProp = fFWIM->getProperty( "FWDSLimit" );
3917
3918	if( existProp && !foundTDM )
3919	{
3920		fFWIM->setLinkMode( kIOFWSetDSLimit, 0 );
3921
3922		// Make sure medicine takes effect
3923		FWTrace(kFWTResetBusAction, kTPResetUpdatePlane, (uintptr_t)fFWIM, 0, 0, 0 );
3924		resetBus();
3925	}
3926
3927    buildTopology(true);
3928
3929	messageClients( kIOFWMessageTopologyChanged );
3930
3931	// reset generation property to current FireWire Generation
3932	char busGenerationStr[32];
3933	snprintf(busGenerationStr, sizeof(busGenerationStr), "%x", (uint32_t)fBusGeneration);
3934	setProperty( kFireWireGenerationID, busGenerationStr);
3935	FWKLOG(("IOFireWireController::updatePlane reset generation to '%s'\n", busGenerationStr));
3936
3937	fUseHalfSizePackets = fRequestedHalfSizePackets;
3938}
3939
3940// terminateDevice
3941//
3942//
3943
3944void IOFireWireController::terminateDevice( IOFireWireDevice * device )
3945{
3946	if( device->isOpen() )
3947	{
3948		//IOLog( "IOFireWireController : message request close device object %p\n", found);
3949		// send our custom requesting close message
3950		device->lockForArbitration();
3951		device->setTerminationState( kNeedsTermination );
3952		device->unlockForArbitration();
3953		messageClient( kIOFWMessageServiceIsRequestingClose, device );
3954	}
3955	else
3956	{
3957		device->lockForArbitration();
3958		device->setTerminationState( kTerminated );
3959		device->unlockForArbitration();
3960		IOFireWireDevice::terminateDevice( device );
3961	}
3962}
3963
3964#pragma mark -
3965/////////////////////////////////////////////////////////////////////////////
3966// physical access
3967//
3968
3969// setPhysicalAccessMode
3970//
3971//
3972
3973void IOFireWireController::setPhysicalAccessMode( IOFWPhysicalAccessMode mode )
3974{
3975	closeGate();
3976
3977	//
3978	// enable physical access in normal security mode
3979	//
3980
3981	if( mode == kIOFWPhysicalAccessEnabled &&
3982		getSecurityMode() == kIOFWSecurityModeNormal )
3983	{
3984		fPhysicalAccessMode = kIOFWPhysicalAccessEnabled;
3985
3986		FWKLOG(( "IOFireWireController::setPhysicalAccessMode - enable physical access\n" ));
3987
3988		//
3989		// disabling physical accesses will have cleared all previous filter state
3990		//
3991		// when physical access is enabled we mimic the filter configuration process
3992		// after a bus reset. we let each node enable its physical filter if desired
3993		//
3994
3995		OSIterator * iterator = getClientIterator();
3996		OSObject * child = NULL;
3997		while( (child = iterator->getNextObject()) )
3998		{
3999			IOFireWireDevice * found = OSDynamicCast(IOFireWireDevice, child);
4000
4001			// don't need to sync with open/close routines when checking for kNotTerminated
4002			if( found && (found->getTerminationState() == kNotTerminated) )
4003			{
4004				// if we found an active device, ask it to reconfigure it's
4005				// physical filter settings
4006				found->configurePhysicalFilter();
4007			}
4008		}
4009
4010		iterator->release();
4011	}
4012
4013	//
4014	// disable physical access
4015	//
4016
4017	if( mode == kIOFWPhysicalAccessDisabled )
4018	{
4019		fPhysicalAccessMode = kIOFWPhysicalAccessDisabled;
4020
4021		FWKLOG(( "IOFireWireController::setPhysicalAccessMode - disable physical access\n" ));
4022
4023		// shut them all down!
4024		fFWIM->setNodeIDPhysicalFilter( kIOFWAllPhysicalFilters, false );
4025	}
4026
4027	//
4028	// disable physical access for this bus generation if physical access
4029	// is not already permanently disabled
4030	//
4031
4032	if( mode == kIOFWPhysicalAccessDisabledForGeneration &&
4033		fPhysicalAccessMode != kIOFWPhysicalAccessDisabled )
4034	{
4035		fPhysicalAccessMode = kIOFWPhysicalAccessDisabledForGeneration;
4036
4037		FWKLOG(( "IOFireWireController::setPhysicalAccessMode - disable physical access for this bus generation\n" ));
4038
4039		// shut them all down!
4040		fFWIM->setNodeIDPhysicalFilter( kIOFWAllPhysicalFilters, false );
4041	}
4042
4043	openGate();
4044}
4045
4046// getPhysicalAccessMode
4047//
4048//
4049
4050IOFWPhysicalAccessMode IOFireWireController::getPhysicalAccessMode( void )
4051{
4052	return fPhysicalAccessMode;
4053}
4054
4055// physicalAccessProcessBusReset
4056//
4057//
4058
4059void IOFireWireController::physicalAccessProcessBusReset( void )
4060{
4061	//
4062	// reenable physical access if it was only disabled for a generation
4063	// and we're in normal security mode
4064	//
4065
4066	if( fPhysicalAccessMode == kIOFWPhysicalAccessDisabledForGeneration &&
4067		getSecurityMode() == kIOFWSecurityModeNormal )
4068	{
4069		fPhysicalAccessMode = kIOFWPhysicalAccessEnabled;
4070
4071		FWKLOG(( "IOFireWireController::physicalAccessProcessBusReset - re-enable physical access because of bus reset\n" ));
4072
4073		// we don't reconfigure the physical filters here because :
4074		// 1. a bus reset has just occured and all node ids are set to kFWBadNodeID
4075		// 2. reconfiguring filters is done automatically after receiving self-ids
4076	}
4077}
4078
4079// setNodeIDPhysicalFilter
4080//
4081//
4082
4083void IOFireWireController::setNodeIDPhysicalFilter( UInt16 nodeID, bool state )
4084{
4085	// only configure node filters if the family is allowing physical access
4086	if( fPhysicalAccessMode == kIOFWPhysicalAccessEnabled )
4087	{
4088		FWKLOG(( "IOFireWireController::setNodeIDPhysicalFilter - set physical access for node 0x%x to %d\n", nodeID, state ));
4089
4090		fFWIM->setNodeIDPhysicalFilter( nodeID, state );
4091	}
4092}
4093
4094// isPhysicalAccessEnabledForNodeID
4095//
4096//
4097
4098bool IOFireWireController::isPhysicalAccessEnabledForNodeID( UInt16 nodeID )
4099{
4100	return fFWIM->isPhysicalAccessEnabledForNodeID( nodeID );
4101}
4102
4103#pragma mark -
4104/////////////////////////////////////////////////////////////////////////////
4105// security
4106//
4107
4108// findKeyswitchDevice
4109//
4110//
4111
4112IOService *IOFireWireController::findKeyswitchDevice( void )
4113{
4114    IORegistryIterator * iter;
4115    IORegistryEntry *    entry = 0;
4116
4117    iter = IORegistryIterator::iterateOver( gIODTPlane,
4118                                            kIORegistryIterateRecursively );
4119
4120    if ( iter )
4121    {
4122        while (( entry = iter->getNextObject() ))
4123		{
4124			if (( strncmp( entry->getName(), "keySwitch-gpio", 16 ) == 0 ) or
4125				( strncmp( entry->getName(), "keySwitch", 11  ) == 0 ) or
4126				( strncmp( entry->getName(), "KYLK", 5 ) == 0 ) )
4127                break;
4128		}
4129        iter->release();
4130    }
4131
4132    return OSDynamicCast( IOService, entry );
4133}
4134
4135// initSecurity
4136//
4137//
4138void IOFireWireController::initSecurity( void )
4139{
4140    #ifdef kIOConsoleSecurityInterest
4141	{
4142        const OSSymbol * console_security_interest 	= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
4143		fConsoleLockNotifier = IOService::getServiceRoot()->registerInterest( console_security_interest, &IOFireWireController::consoleLockInterestHandler, this, NULL );
4144		if( fConsoleLockNotifier == NULL )
4145		{
4146			fConsoleLockNotifier->enable(true);
4147		}
4148	}
4149    #endif
4150
4151	bool	waitForKeyswitch	= false;
4152
4153	if( findKeyswitchDevice() )
4154		waitForKeyswitch = true;
4155
4156	//
4157	// assume security mode is normal
4158	//
4159
4160	IOFWSecurityMode mode = kIOFWSecurityModeNormal;
4161
4162    #ifdef kIOConsoleSecurityInterest
4163	{
4164        IORegistryEntry * root = IORegistryEntry::getRegistryRoot();
4165        OSObject * console_lock_property = NULL;
4166        if( root )
4167        {
4168            console_lock_property = root->getProperty( kIOConsoleLockedKey );
4169        }
4170
4171        OSBoolean * console_locked = NULL;
4172        if( console_lock_property )
4173        {
4174            console_locked = OSDynamicCast( OSBoolean, console_lock_property );
4175        }
4176
4177        if( console_locked && console_locked->isTrue() )
4178		{
4179			mode = kIOFWSecurityModeSecure;
4180		}
4181	}
4182    #endif
4183
4184	//
4185	// check OpenFirmware security mode
4186	//
4187
4188	{
4189		char matchPath[32];	// IODeviceTree:/:options
4190		OSDictionary * optionsMatchDictionary = IOOFPathMatching( "/options", matchPath, 32 ); // need to release
4191
4192		mach_timespec_t t = { 10, 0 };	//wait 10 secs
4193		IOService * options = IOService::waitForService( optionsMatchDictionary, &t );	// consumes dict ref, don't release options
4194
4195		if( options != NULL )
4196		{
4197			OSString * securityModeProperty = OSDynamicCast( OSString, options->getProperty("security-mode") );
4198
4199			if( securityModeProperty != NULL && strncmp( "none", securityModeProperty->getCStringNoCopy(), 5 ) != 0 )
4200			{
4201				// set security mode to secure/permanent
4202				mode = kIOFWSecurityModeSecurePermanent;
4203			}
4204		}
4205		else
4206		{
4207			ErrorLog("FireWire unable to determine security-mode; defaulting to full-secure.\n");
4208			// turn security on because we can't determine security-mode
4209			mode = kIOFWSecurityModeSecurePermanent;
4210		}
4211	}
4212
4213	//
4214	// handle security keyswitch
4215	//
4216
4217	if( mode != kIOFWSecurityModeSecurePermanent )
4218	{
4219
4220		//
4221		// check state of secruity keyswitch
4222		//
4223		UInt8	retryCount = 5;
4224
4225		do
4226		{
4227			OSIterator *	iterator		= NULL;
4228			OSBoolean *		keyswitchState	= NULL;
4229
4230			iterator = getMatchingServices( nameMatching("AppleKeyswitch") );
4231			if( iterator != NULL )
4232			{
4233				OSObject * obj = NULL;
4234				waitForKeyswitch = false;
4235
4236				if( (obj = iterator->getNextObject()) )
4237				{
4238					IOService *	service = (IOService*)obj;
4239					keyswitchState = OSDynamicCast( OSBoolean, service->getProperty( "Keyswitch" ) );
4240
4241					if( keyswitchState->isTrue() )
4242					{
4243						// set security mode to secure
4244						mode = kIOFWSecurityModeSecure;
4245					}
4246				}
4247
4248				iterator->release();
4249				iterator = NULL;
4250			}
4251
4252			if( retryCount == 0 )
4253				waitForKeyswitch = false;
4254
4255			retryCount--;
4256
4257			if( waitForKeyswitch )
4258			{
4259				IOLog("Waiting for AppleKeyswitch ...\n");
4260				IOSleep(1000);
4261			}
4262
4263		}while( waitForKeyswitch );
4264
4265		//
4266		// add notification for changes to secruity keyswitch
4267		//
4268
4269
4270		fKeyswitchNotifier = addMatchingNotification( gIOMatchedNotification, nameMatching( "AppleKeyswitch" ),
4271											  (IOServiceMatchingNotificationHandler)&IOFireWireController::serverKeyswitchCallback,
4272											  this, 0 );
4273
4274	}
4275
4276	//
4277	// now that we've determined our security mode, set it
4278	//
4279
4280	setSecurityMode( mode );
4281
4282}
4283
4284// freeSecurity
4285//
4286//
4287
4288void IOFireWireController::freeSecurity( void )
4289{
4290	// remove notification
4291
4292	if( fConsoleLockNotifier )
4293	{
4294		fConsoleLockNotifier->remove();
4295		fConsoleLockNotifier = NULL;
4296	}
4297
4298	if( fKeyswitchNotifier != NULL )
4299	{
4300		fKeyswitchNotifier->remove();
4301		fKeyswitchNotifier = NULL;
4302	}
4303}
4304
4305IOReturn IOFireWireController::consoleLockInterestHandler( void * target, void * refCon,
4306                                         UInt32 messageType, IOService * provider,
4307                                         void * messageArgument, vm_size_t argSize )
4308{
4309	IOFireWireController * me = OSDynamicCast( IOFireWireController, (OSObject *)target );
4310
4311    if ( me != NULL )
4312    {
4313        if( me->getSecurityMode() != kIOFWSecurityModeSecurePermanent )
4314        {
4315            IORegistryEntry * root = IORegistryEntry::getRegistryRoot();
4316            OSObject * console_lock_property = NULL;
4317            if( root )
4318            {
4319                console_lock_property = root->getProperty( kIOConsoleLockedKey );
4320            }
4321
4322            OSBoolean * console_locked = NULL;
4323            if( console_lock_property )
4324            {
4325                console_locked = OSDynamicCast( OSBoolean, console_lock_property );
4326            }
4327
4328            if( console_locked && console_locked->isTrue() )
4329            {
4330                // Key is locked, set security mode to secure
4331            //    IOLog( "IOFireWireController::consoleLockInterestHandler lock: value true\n" );
4332                me->setSecurityMode( kIOFWSecurityModeSecure );
4333            }
4334            else
4335            {
4336                // Key is unlocked, set security mode to normal
4337             //   IOLog( "IOFireWireController::consoleLockInterestHandler lock: value false\n" );
4338                me->setSecurityMode( kIOFWSecurityModeNormal );
4339            }
4340        }
4341    }
4342
4343	return kIOReturnSuccess;
4344}
4345
4346// serverKeyswitchCallback
4347//
4348//
4349
4350bool IOFireWireController::serverKeyswitchCallback( void * target, void * refCon, IOService * service, IONotifier * notifier )
4351{
4352	OSBoolean *				keyswitchState	= NULL;
4353	IOFireWireController *	me				= NULL;
4354
4355	if( me != NULL )
4356    {
4357        me = OSDynamicCast( IOFireWireController, (OSObject *)target );
4358
4359        if ( me->getSecurityMode() != kIOFWSecurityModeSecurePermanent )
4360        {
4361            keyswitchState = OSDynamicCast( OSBoolean, service->getProperty( "Keyswitch" ) );
4362            if( keyswitchState != NULL )
4363            {
4364                // Is the key unlocked?
4365
4366                if( keyswitchState->isFalse() )
4367                {
4368                    // Key is unlocked, set security mode to normal
4369
4370                    me->setSecurityMode( kIOFWSecurityModeNormal );
4371                }
4372                else if( keyswitchState->isTrue() )
4373                {
4374                    // Key is locked, set security mode to secure
4375
4376                    me->setSecurityMode( kIOFWSecurityModeSecure );
4377                }
4378            }
4379        }
4380    }
4381
4382	return true;
4383}
4384
4385// setSecurityMode
4386//
4387//
4388
4389void IOFireWireController::setSecurityMode( IOFWSecurityMode mode )
4390{
4391	closeGate();
4392
4393	fSecurityMode = mode;
4394
4395	switch( fSecurityMode )
4396	{
4397		case kIOFWSecurityModeNormal:
4398
4399			FWKLOG(( "IOFireWireController::setSecurityMode - set mode to normal\n" ));
4400
4401			// enable physical access
4402			fFWIM->setSecurityMode( mode );
4403			setPhysicalAccessMode( kIOFWPhysicalAccessEnabled );
4404			break;
4405
4406		case kIOFWSecurityModeSecure:
4407		case kIOFWSecurityModeSecurePermanent:
4408
4409			FWKLOG(( "IOFireWireController::setSecurityMode - set mode to secure\n" ));
4410
4411			// disable physical access
4412			fFWIM->setSecurityMode( mode );
4413			setPhysicalAccessMode( kIOFWPhysicalAccessDisabled );
4414			break;
4415
4416		default:
4417			IOLog( "IOFireWireController::setSecurityMode - illegal security mode = 0x%x\n", fSecurityMode );
4418			break;
4419	}
4420
4421	openGate();
4422}
4423
4424// getSecurityMode
4425//
4426//
4427
4428IOFWSecurityMode IOFireWireController::getSecurityMode( void )
4429{
4430	return fSecurityMode;
4431}
4432
4433#pragma mark -
4434
4435/////////////////////////////////////////////////////////////////////////////
4436// local config rom
4437//
4438
4439// getRootDir
4440//
4441//
4442
4443IOLocalConfigDirectory * IOFireWireController::getRootDir() const
4444{
4445	return fRootDir;
4446}
4447
4448// AddUnitDirectory
4449//
4450//
4451
4452IOReturn IOFireWireController::AddUnitDirectory(IOLocalConfigDirectory *unitDir)
4453{
4454    IOReturn res;
4455
4456	closeGate();
4457
4458	if ( isInactive() )
4459	{
4460		openGate() ;
4461		return kIOReturnOffline ;
4462	}
4463
4464	getRootDir()->addEntry(kConfigUnitDirectoryKey, unitDir);
4465
4466    res = UpdateROM();
4467    if(res == kIOReturnSuccess)
4468	{
4469		FWTrace(kFWTResetBusAction, kTPResetAddUnitDirectory, (uintptr_t)fFWIM, 0, 0, 0 );
4470        res = resetBus();
4471    }
4472	openGate();
4473
4474	return res;
4475}
4476
4477// RemoveUnitDirectory
4478//
4479//
4480
4481IOReturn IOFireWireController::RemoveUnitDirectory(IOLocalConfigDirectory *unitDir)
4482{
4483    IOReturn res;
4484
4485	closeGate();
4486
4487	getRootDir()->removeSubDir(unitDir);
4488
4489    res = UpdateROM();
4490    if(res == kIOReturnSuccess)
4491	{
4492		FWTrace(kFWTResetBusAction, kTPResetRemoveUnitDirectory, (uintptr_t)fFWIM, 0, 0, 0 );
4493		res = resetBus();
4494    }
4495
4496	openGate();
4497
4498	return res;
4499}
4500
4501// UpdateROM()
4502//
4503//   Instantiate the local Config ROM.
4504//   Always causes at least one bus reset.
4505
4506IOReturn IOFireWireController::UpdateROM()
4507{
4508    UInt32 *				hack;
4509    UInt32 					crc;
4510    unsigned int 			numQuads;
4511    OSData *				rom;
4512    IOReturn				ret;
4513    UInt32					generation;
4514    IOFireWireLocalNode *	localNode;
4515
4516    // Increment the 4 bit generation field, make sure it is at least two.
4517	UInt32 bib_quad = OSSwapBigToHostInt32( fROMHeader[2] );
4518    generation = bib_quad & kFWBIBGeneration;
4519    generation += (1 << kFWBIBGenerationPhase);
4520    generation &= kFWBIBGeneration;
4521    if(generation < (2 << kFWBIBGenerationPhase))
4522        generation = (2 << kFWBIBGenerationPhase);
4523
4524    fROMHeader[2] = OSSwapHostToBigInt32((bib_quad & ~kFWBIBGeneration) | generation);
4525
4526    rom = OSData::withBytes(&fROMHeader, sizeof(fROMHeader));
4527	fRootDir->incrementGeneration();
4528	fRootDir->compile(rom);
4529
4530    // Now hack in correct CRC and length.
4531    hack = (UInt32 *)rom->getBytesNoCopy();
4532    UInt32 bibQuads = sizeof(fROMHeader)/sizeof(UInt32) - 1;
4533    crc = FWComputeCRC16 (hack + 1, bibQuads);
4534    *hack = OSSwapHostToBigInt32(
4535				(((sizeof(fROMHeader)/sizeof(UInt32)-1) << kConfigBusInfoBlockLengthPhase) & kConfigBusInfoBlockLength) |
4536		        ((bibQuads << kConfigROMCRCLengthPhase) & kConfigROMCRCLength) |
4537				((crc << kConfigROMCRCValuePhase) & kConfigROMCRCValue) );
4538
4539    localNode = getLocalNode(this);
4540    if(localNode)
4541        localNode->setProperty(gFireWireROM, rom);
4542
4543    numQuads = rom->getLength()/sizeof(UInt32) - 1;
4544
4545#if 0
4546    {
4547        unsigned int i;
4548        IOLog("--------- FW Local ROM: --------\n");
4549        for(i=0; i<numQuads+1; i++)
4550            IOLog("ROM[%d] = 0x%x\n", i, OSSwapBigToHostInt32(hack[i]));
4551    }
4552#endif
4553
4554    if(fROMAddrSpace)
4555	{
4556        freeAddress( fROMAddrSpace );
4557        fROMAddrSpace->release();
4558        fROMAddrSpace = NULL;
4559    }
4560
4561    fROMAddrSpace = IOFWPseudoAddressSpace::simpleReadFixed( this,
4562        FWAddress(kCSRRegisterSpaceBaseAddressHi, kConfigROMBaseAddress),
4563        (numQuads+1)*sizeof(UInt32), rom->getBytesNoCopy());
4564    ret = allocAddress(fROMAddrSpace);
4565    if(kIOReturnSuccess == ret)
4566	{
4567        ret = fFWIM->updateROM(rom);
4568    }
4569    rom->release();
4570    return ret ;
4571}
4572
4573#pragma mark -
4574/////////////////////////////////////////////////////////////////////////////
4575// async request transmit
4576//
4577
4578// allocTrans
4579//
4580//
4581
4582AsyncPendingTrans *IOFireWireController::allocTrans(IOFWAsyncCommand *cmd)
4583{
4584    return allocTrans( cmd, NULL );
4585}
4586
4587// allocTrans
4588//
4589//
4590
4591AsyncPendingTrans *IOFireWireController::allocTrans( IOFWAsyncCommand * cmd, IOFWCommand * altcmd )
4592{
4593    unsigned int i;
4594    unsigned int tran;
4595
4596    tran = fLastTrans;
4597    for(i=0; i<kMaxPendingTransfers; i++) {
4598        AsyncPendingTrans *t;
4599        tran++;
4600        if(tran >= kMaxPendingTransfers)
4601            tran = 0;
4602        t = &fTrans[tran];
4603        if(!t->fInUse) {
4604            t->fHandler = cmd;
4605			t->fAltHandler = altcmd;
4606            t->fInUse = true;
4607            t->fTCode = tran;
4608            fLastTrans = tran;
4609            return t;
4610        }
4611    }
4612
4613	// Print only if its a first time
4614	if ( fOutOfTLabels == 0 && fOutOfTLabelsThreshold == 0 )
4615		IOLog("IOFireWireController:: Out of Transaction Labels\n");
4616
4617	// Out of TLabels counter (Information Only)
4618	fOutOfTLabels++;
4619
4620    return NULL;
4621}
4622
4623// freeTrans
4624//
4625//
4626
4627void IOFireWireController::freeTrans(AsyncPendingTrans *trans)
4628{
4629    // No lock needed - can't have two users of a tcode.
4630    trans->fHandler = NULL;
4631	trans->fAltHandler = NULL;
4632    trans->fInUse = false;
4633}
4634
4635// asyncRead
4636//
4637//
4638
4639IOReturn IOFireWireController::asyncRead(	UInt32 				generation,
4640											UInt16 				nodeID,
4641											UInt16 				addrHi,
4642											UInt32 				addrLo,
4643											int 				speed,
4644											int 				label,
4645											int 				size,
4646											IOFWAsyncCommand *	cmd)
4647{
4648	return asyncRead(	generation,
4649						nodeID,
4650						addrHi,
4651						addrLo,
4652						speed,
4653						label,
4654						size,
4655						cmd,
4656						kIOFWReadFlagsNone );
4657}
4658
4659// asyncRead
4660//
4661//
4662
4663// Route packet sending to FWIM if checks out OK
4664IOReturn IOFireWireController::asyncRead(	UInt32 				generation,
4665											UInt16 				nodeID,
4666											UInt16 				addrHi,
4667											UInt32 				addrLo,
4668											int 				speed,
4669											int 				label,
4670											int 				size,
4671											IOFWAsyncCommand *	cmd,
4672											IOFWReadFlags		flags )
4673{
4674	FWTrace_Start(kFWTController, kTPControllerAsyncRead, (uintptr_t)fFWIM, (uintptr_t)cmd, (uintptr_t)((nodeID << 16) | addrHi), addrLo );
4675
4676    if( !checkGeneration(generation) )
4677	{
4678		FWTrace_End(kFWTController, kTPControllerAsyncRead, (uintptr_t)fFWIM, (uintptr_t)cmd, kIOFireWireBusReset, 1 );
4679        return kIOFireWireBusReset;
4680    }
4681
4682    // Check if local node
4683
4684    if( nodeID == fLocalNodeID )
4685	{
4686        UInt32 rcode;
4687        IOMemoryDescriptor *buf;
4688        IOByteCount offset;
4689        IOFWSpeed temp = (IOFWSpeed)speed;
4690
4691		rcode = doReadSpace(	nodeID,
4692								temp,
4693								FWAddress(addrHi, addrLo),
4694								size,
4695								&buf,
4696								&offset,
4697								NULL,
4698								(IOFWRequestRefCon)label );
4699
4700        if(rcode == kFWResponseComplete)
4701		{
4702			void * bytes = IOMalloc( size );
4703
4704			buf->readBytes( offset, bytes, size );
4705
4706			cmd->gotPacket( rcode, bytes, size );
4707
4708			IOFree( bytes, size );
4709        }
4710		else
4711        {
4712		    cmd->gotPacket( rcode, NULL, 0 );
4713        }
4714
4715		FWTrace_End(kFWTController, kTPControllerAsyncRead, (uintptr_t)fFWIM, (uintptr_t)cmd, kIOReturnSuccess, 2 );
4716		return kIOReturnSuccess;
4717    }
4718    else
4719	{
4720		// reliabilty is more important than speed for IRM access
4721		// perform IRM access at s100
4722
4723		int actual_speed = speed;
4724		if( addrHi == kCSRRegisterSpaceBaseAddressHi )
4725        {
4726			if( (addrLo == kCSRBandwidthAvailable) ||
4727				(addrLo == kCSRChannelsAvailable31_0) ||
4728				(addrLo == kCSRChannelsAvailable63_32) ||
4729				(addrLo == kCSRBusManagerID) )
4730			{
4731				actual_speed = kFWSpeed100MBit;
4732			}
4733		}
4734
4735		IOReturn status = fFWIM->asyncRead( nodeID, addrHi, addrLo, actual_speed, label, size, cmd, flags );
4736
4737		FWTrace_End(kFWTController, kTPControllerAsyncRead, (uintptr_t)fFWIM, (uintptr_t)cmd, status, 3 );
4738        return status;
4739	}
4740}
4741
4742// asyncWrite
4743//
4744// DEPRECATED
4745
4746IOReturn IOFireWireController::asyncWrite(	UInt32 				generation,
4747											UInt16 				nodeID,
4748											UInt16 				addrHi,
4749											UInt32 				addrLo,
4750											int 				speed,
4751											int 				label,
4752											void *				data,
4753											int 				size,
4754											IOFWAsyncCommand *	cmd)
4755{
4756	IOLog( "IOFireWireController::asyncWrite : DEPRECATED API\n" );
4757	return kIOReturnUnsupported;
4758}
4759
4760// asyncWrite
4761//
4762//
4763
4764IOReturn IOFireWireController::asyncWrite(	UInt32 					generation,
4765											UInt16 					nodeID,
4766											UInt16 					addrHi,
4767											UInt32 					addrLo,
4768											int 					speed,
4769											int 					label,
4770											IOMemoryDescriptor *	buf,
4771											IOByteCount 			offset,
4772											int 					size,
4773											IOFWAsyncCommand *		cmd )
4774{
4775	return asyncWrite(	generation,
4776						nodeID,
4777						addrHi,
4778						addrLo,
4779						speed,
4780						label,
4781						buf,
4782						offset,
4783						size,
4784						cmd,
4785						kIOFWWriteFlagsNone );
4786}
4787
4788// asyncWrite
4789//
4790//
4791
4792IOReturn IOFireWireController::asyncWrite(	UInt32 					generation,
4793											UInt16 					nodeID,
4794											UInt16 					addrHi,
4795											UInt32 					addrLo,
4796											int 					speed,
4797											int 					label,
4798											IOMemoryDescriptor *	buf,
4799											IOByteCount 			offset,
4800											int 					size,
4801											IOFWAsyncCommand *		cmd,
4802											IOFWWriteFlags 			flags )
4803{
4804	FWTrace_Start(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, (uintptr_t)((nodeID << 16) | addrHi), addrLo );
4805
4806//	IOLog( "IOFireWireController::asyncWrite\n" );
4807
4808    if( !checkGeneration(generation) )
4809	{
4810		FWTrace_End(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, kIOFireWireBusReset, 1 );
4811        return kIOFireWireBusReset;
4812    }
4813
4814    // Check if local node
4815    if( nodeID == fLocalNodeID )
4816	{
4817        UInt32 rcode;
4818        IOFWSpeed temp = (IOFWSpeed)speed;
4819
4820		void * bytes = IOMalloc( size );
4821
4822		buf->readBytes( offset, bytes, size );
4823
4824		rcode = doWriteSpace(	nodeID,
4825								temp,
4826								FWAddress( addrHi, addrLo ),
4827								size,
4828								bytes,
4829								(IOFWRequestRefCon)label );
4830
4831		IOFree( bytes, size );
4832
4833		cmd->gotPacket(rcode, NULL, 0);
4834
4835		FWTrace_End(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, kIOReturnSuccess, 2 );
4836		return kIOReturnSuccess;
4837    }
4838    else
4839	{
4840		// reliabilty is more important than speed for IRM access
4841		// perform IRM access at s100
4842
4843		// actually writes to the IRM are not allowed, so we are doing
4844		// this more for consistency than necessity
4845
4846		int actual_speed = speed;
4847		if( addrHi == kCSRRegisterSpaceBaseAddressHi )
4848        {
4849			if( (addrLo == kCSRBandwidthAvailable) ||
4850				(addrLo == kCSRChannelsAvailable31_0) ||
4851				(addrLo == kCSRChannelsAvailable63_32) ||
4852				(addrLo == kCSRBusManagerID) )
4853			{
4854				actual_speed = kFWSpeed100MBit;
4855			}
4856		}
4857
4858		IOReturn status = fFWIM->asyncWrite( 	nodeID,
4859											addrHi,
4860											addrLo,
4861											actual_speed,
4862											label,
4863											buf,
4864											offset,
4865											size,
4866											cmd,
4867											flags );
4868
4869		FWTrace_End(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, status, 3 );
4870        return status;
4871	}
4872}
4873
4874// asyncPHYPacket
4875//
4876//
4877
4878IOReturn IOFireWireController::asyncPHYPacket( UInt32 generation, UInt32 data, UInt32 data2, IOFWAsyncPHYCommand * cmd )
4879{
4880	IOReturn status = kIOReturnSuccess;
4881
4882    if( !checkGeneration(generation) )
4883	{
4884        status = kIOFireWireBusReset;
4885    }
4886
4887	if( status == kIOReturnSuccess )
4888	{
4889		if( !(data & 0x40000000) )
4890		{
4891			// not VersaPHY
4892			status = kIOReturnBadArgument;
4893		}
4894	}
4895
4896	if( status == kIOReturnSuccess )
4897	{
4898		status = fFWIM->asyncPHYPacket( data, data2, cmd );
4899	}
4900
4901	return status;
4902}
4903
4904// asyncLock
4905//
4906// DEPRECATED
4907
4908IOReturn IOFireWireController::asyncLock(	UInt32 				generation,
4909											UInt16 				nodeID,
4910											UInt16 				addrHi,
4911											UInt32 				addrLo,
4912											int 				speed,
4913											int 				label,
4914											int 				type,
4915											void *				data,
4916											int 				size,
4917											IOFWAsyncCommand *	cmd )
4918{
4919	IOLog( "IOFireWireController::asyncLock : DEPRECATED API\n" );
4920	return kIOReturnUnsupported;
4921}
4922
4923// asyncLock
4924//
4925//
4926
4927IOReturn IOFireWireController::asyncLock(	UInt32 					generation,
4928											UInt16 					nodeID,
4929											UInt16 					addrHi,
4930											UInt32 					addrLo,
4931											int 					speed,
4932											int 					label,
4933											int 					type,
4934											IOMemoryDescriptor *	buf,
4935											IOByteCount 			offset,
4936											int 					size,
4937											IOFWAsyncCommand *		cmd )
4938
4939{
4940	FWTrace_Start(kFWTController, kTPControllerAsyncLock, (uintptr_t)fFWIM, (uintptr_t)cmd, (uintptr_t)((nodeID << 16) | addrHi), addrLo );
4941
4942    if( !checkGeneration(generation) )
4943	{
4944		FWTrace_End(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, kIOFireWireBusReset, 1 );
4945        return kIOFireWireBusReset;
4946    }
4947
4948    // Check if local node
4949    if( nodeID == fLocalNodeID )
4950	{
4951        UInt32 rcode;
4952        UInt32 retVals[2];
4953        UInt32 retSize = size / 2;
4954
4955		IOFWSpeed temp = (IOFWSpeed)speed;
4956        IOFWRequestRefCon refcon = (IOFWRequestRefCon)(label | kRequestIsLock | (type << kRequestExtTCodeShift));
4957
4958		void * bytes = IOMalloc( size );
4959
4960		buf->readBytes( offset, bytes, size );
4961
4962		rcode = doLockSpace(	nodeID,
4963								temp,
4964								FWAddress(addrHi, addrLo),
4965								size,
4966								(const UInt32*)bytes,
4967								retSize,
4968								retVals,
4969								type,
4970								refcon );
4971
4972		IOFree( bytes, size );
4973
4974        cmd->gotPacket( rcode, retVals, retSize );
4975
4976		FWTrace_End(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, kIOReturnSuccess, 2 );
4977		return kIOReturnSuccess;
4978    }
4979    else
4980	{
4981		// reliabilty is more important than speed for IRM access
4982		// perform IRM access at s100
4983
4984		int actual_speed = speed;
4985		if( addrHi == kCSRRegisterSpaceBaseAddressHi )
4986        {
4987			if( (addrLo == kCSRBandwidthAvailable) ||
4988				(addrLo == kCSRChannelsAvailable31_0) ||
4989				(addrLo == kCSRChannelsAvailable63_32) ||
4990				(addrLo == kCSRBusManagerID) )
4991			{
4992				actual_speed = kFWSpeed100MBit;
4993			}
4994		}
4995
4996		IOReturn status = fFWIM->asyncLock(	nodeID,
4997										   addrHi,
4998										   addrLo,
4999										   actual_speed,
5000										   label,
5001										   type,
5002										   buf,
5003										   offset,
5004										   size,
5005										   cmd );
5006
5007		FWTrace_End(kFWTController, kTPControllerAsyncWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, status, 3 );
5008		return status;
5009	}
5010}
5011
5012// handleAsyncTimeout
5013//
5014//
5015
5016IOReturn IOFireWireController::handleAsyncTimeout(IOFWAsyncCommand *cmd)
5017{
5018    return fFWIM->handleAsyncTimeout(cmd);
5019}
5020
5021
5022// handleAsyncCompletion
5023//
5024//
5025
5026IOReturn IOFireWireController::handleAsyncCompletion( IOFWCommand *cmd, IOReturn status )
5027{
5028    return fFWIM->handleAsyncCompletion( cmd, status );
5029}
5030
5031// asyncStreamWrite
5032//
5033//
5034
5035IOReturn IOFireWireController::asyncStreamWrite(UInt32 generation,
5036                    int speed, int tag, int sync, int channel,
5037                    IOMemoryDescriptor *buf, IOByteCount offset,
5038                	int size, IOFWAsyncStreamCommand *cmd)
5039{
5040	FWTrace_Start(kFWTController, kTPControllerAsyncStreamWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, channel, 0);
5041
5042    if(!checkGeneration(generation))
5043	{
5044		FWTrace_End(kFWTController, kTPControllerAsyncStreamWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, channel, kIOFireWireBusReset);
5045        return (kIOFireWireBusReset);
5046    }
5047
5048	IOReturn status = fFWIM->asyncStreamTransmit((UInt32)channel, speed, (UInt32) sync, (UInt32) tag, buf, offset, size, cmd);
5049
5050	FWTrace_End(kFWTController, kTPControllerAsyncStreamWrite, (uintptr_t)fFWIM, (uintptr_t)cmd, channel, status);
5051	return status;
5052}
5053
5054// createAsyncStreamCommand
5055//
5056//
5057
5058IOFWAsyncStreamCommand * IOFireWireController::createAsyncStreamCommand( UInt32 generation,
5059    			UInt32 channel, UInt32 sync, UInt32 tag, IOMemoryDescriptor *hostMem,
5060    			UInt32 size, int speed, FWAsyncStreamCallback completion, void *refcon)
5061{
5062    return createAsyncStreamCommand(generation, channel, sync, tag, hostMem, size, speed, completion, refcon, true);
5063}
5064
5065IOFWAsyncStreamCommand * IOFireWireController::createAsyncStreamCommand( UInt32 generation,
5066				UInt32 channel, UInt32 sync, UInt32 tag, IOMemoryDescriptor *hostMem,
5067				UInt32 size, int speed,FWAsyncStreamCallback completion, void *refcon, bool	failOnReset)
5068{
5069    IOFWAsyncStreamCommand * cmd;
5070
5071    cmd = OSTypeAlloc( IOFWAsyncStreamCommand );
5072    if(cmd) {
5073        if(!cmd->initAll(this, generation, channel, sync, tag, hostMem,size,speed, completion, refcon, failOnReset)) {
5074            cmd->release();
5075            cmd = NULL;
5076		}
5077    }
5078    return cmd;
5079}
5080
5081// createAsyncPHYCommand
5082//
5083//
5084
5085IOFWAsyncPHYCommand * IOFireWireController::createAsyncPHYCommand(	UInt32				generation,
5086																	UInt32				data1,
5087																	UInt32				data2,
5088																	FWAsyncPHYCallback	completion,
5089																	void *				refcon,
5090																	bool 				failOnReset )
5091
5092{
5093    IOFWAsyncPHYCommand * cmd;
5094
5095    cmd = OSTypeAlloc( IOFWAsyncPHYCommand );
5096    if( cmd )
5097	{
5098        if( !cmd->initAll( this, generation, data1, data2, completion, refcon, failOnReset ) )
5099		{
5100            cmd->release();
5101            cmd = NULL;
5102		}
5103    }
5104
5105    return cmd;
5106}
5107
5108/////////////////////////////////////////////////////////////////////////////
5109// async receive
5110//
5111
5112// processRcvPacket
5113//
5114// dispatch received Async packet based on tCode.
5115
5116void IOFireWireController::processRcvPacket(UInt32 *data, int size, IOFWSpeed speed )
5117{
5118#if 0
5119    int i;
5120kprintf("Received packet 0x%x size %d\n", data, size);
5121    for(i=0; i<size; i++) {
5122	kprintf("0x%x ", OSSwapBigToHostInt32(data[i]));
5123    }
5124    kprintf("\n");
5125#endif
5126    UInt32	tCode, tLabel;
5127    UInt32	quad0;
5128    UInt16	sourceID;
5129    UInt16	destID;
5130
5131    // Get first quad.
5132    quad0 = *data;
5133
5134    tCode = (quad0 & kFWPacketTCode) >> kFWPacketTCodePhase;
5135    tLabel = (quad0 & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
5136    sourceID = (data[1] & kFWAsynchSourceID) >> kFWAsynchSourceIDPhase;
5137	destID = (data[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase;
5138
5139	FWTrace(kFWTController, kTPControllerProcessRcvPacket, (uintptr_t)fFWIM, sourceID, tCode, 0);
5140
5141    // Dispatch processing based on tCode.
5142    switch (tCode)
5143    {
5144        case kFWTCodeWriteQuadlet :
5145#if (DEBUGGING_LEVEL > 0)
5146            DEBUGLOG("WriteQuadlet: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
5147		(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
5148#endif
5149            processWriteRequest(sourceID, tLabel, data, &data[3], 4, speed);
5150            break;
5151
5152		case kFWTCodePHYPacket:
5153#if (DEBUGGING_LEVEL > 0)
5154            DEBUGLOG( "PHY Packet: 0x%08lx %08lx\n", data[1], data[2] );
5155#endif
5156			processPHYPacket( data[1], data[2] );
5157			break;
5158
5159        case kFWTCodeWriteBlock :
5160#if (DEBUGGING_LEVEL > 0)
5161            DEBUGLOG("WriteBlock: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
5162		(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
5163#endif
5164            processWriteRequest(sourceID, tLabel, data, &data[4],
5165			(data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase, speed);
5166            break;
5167
5168        case kFWTCodeWriteResponse :
5169            if(fTrans[tLabel].fHandler) {
5170                IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
5171				FWAddress commandAddress = cmd->getAddress();
5172
5173            	if( sourceID == commandAddress.nodeID ){
5174            		cmd->setResponseSpeed( speed );
5175
5176					FWTrace(kFWTController, kTPControllerProcessRcvPacketWR, (uintptr_t)fFWIM, (uintptr_t)cmd, ((commandAddress.nodeID << 16) | commandAddress.addressHi), commandAddress.addressLo);
5177					cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase, 0, 0);
5178				}
5179				else{
5180#if (DEBUGGING_LEVEL > 0)
5181					DEBUGLOG( "Response from wrong node ID!\n" );
5182#endif
5183				}
5184            }
5185            else {
5186#if (DEBUGGING_LEVEL > 0)
5187            DEBUGLOG("WriteResponse: label %d isn't in use!!, data1 = 0x%x\n",
5188                     tLabel, data[1]);
5189#endif
5190            }
5191            break;
5192
5193        case kFWTCodeReadQuadlet :
5194#if (DEBUGGING_LEVEL > 0)
5195            DEBUGLOG("ReadQuadlet: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
5196		(data[1] & kFWAsynchDestinationOffsetHigh) >>
5197                     kFWAsynchDestinationOffsetHighPhase, data[2]);
5198#endif
5199            {
5200                UInt32 ret;
5201                FWAddress addr((data[1] & kFWAsynchDestinationOffsetHigh) >>  kFWAsynchDestinationOffsetHighPhase, data[2]);
5202                IOMemoryDescriptor *buf = NULL;
5203				IOByteCount offset;
5204
5205				ret = doReadSpace(sourceID, speed, addr, 4,
5206                                    &buf, &offset, NULL, (IOFWRequestRefCon)(tLabel | kRequestIsQuad));
5207
5208				FWTrace(kFWTController, kTPControllerProcessRcvPacketRQ, (uintptr_t)fFWIM, ret, ((addr.nodeID << 16) | addr.addressHi), addr.addressLo);
5209
5210                if(ret == kFWResponsePending)
5211                    break;
5212
5213				if( NULL != buf )
5214				{
5215					UInt32 quad = OSSwapHostToBigInt32(0xdeadbeef);
5216
5217					buf->readBytes( offset, &quad, 4 );
5218
5219					if ( destID != 0xffff )	// we should not respond to broadcast reads
5220						fFWIM->asyncReadQuadResponse(sourceID, speed, tLabel, ret, quad );
5221					else
5222						DebugLog("Skipped asyncReadQuadResponse because destID=0x%x\n", destID);
5223                }
5224                else
5225				{
5226                    if ( destID != 0xffff )	// we should not respond to broadcast reads
5227						fFWIM->asyncReadQuadResponse(sourceID, speed, tLabel, ret, OSSwapHostToBigInt32(0xdeadbeef));
5228					else
5229						DebugLog("Skipped asyncReadQuadResponse because destID=0x%x\n", destID);
5230                }
5231            }
5232            break;
5233
5234        case kFWTCodeReadBlock :
5235#if (DEBUGGING_LEVEL > 0)
5236            DEBUGLOG("ReadBlock: addr 0x%x -> 0x%x:0x%x:0x%x\n", sourceID, destID,
5237		(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2],
5238		(data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase);
5239#endif
5240            {
5241                IOReturn ret;
5242                int 					length = (data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase ;
5243                FWAddress 	addr((data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, data[2]);
5244                IOMemoryDescriptor *	buf = NULL;
5245				IODMACommand * dma_command = NULL;
5246				IOByteCount offset;
5247
5248                ret = doReadSpace(sourceID, speed, addr, length, &buf, &offset, &dma_command, (IOFWRequestRefCon)(tLabel));
5249
5250				FWTrace(kFWTController, kTPControllerProcessRcvPacketRB, (uintptr_t)fFWIM, ret, ((addr.nodeID << 16) | addr.addressHi), addr.addressLo);
5251
5252                if(ret == kFWResponsePending)
5253                    break;
5254
5255				if(NULL != buf) {
5256                    if ( destID != 0xffff )	// we should not respond to broadcast reads
5257						fFWIM->asyncReadResponse(sourceID, speed, tLabel, ret, buf, offset, length, dma_command );
5258					else
5259						DebugLog("Skipped asyncReadResponse because destID=0x%x\n", destID);
5260                }
5261                else {
5262                    if ( destID != 0xffff )	// we should not respond to broadcast reads
5263						fFWIM->asyncReadResponse(sourceID, speed, tLabel, ret, fBadReadResponse, 0, 4, NULL);
5264					else
5265						DebugLog("Skipped asyncReadResponse because destID=0x%x\n", destID);
5266                }
5267            }
5268            break;
5269
5270        case kFWTCodeReadQuadletResponse :
5271            if(fTrans[tLabel].fHandler) {
5272                IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
5273				FWAddress commandAddress = cmd->getAddress();
5274
5275            	if( sourceID == commandAddress.nodeID )
5276            	{
5277            		cmd->setResponseSpeed( speed );
5278
5279					FWTrace(kFWTController, kTPControllerProcessRcvPacketRQR, (uintptr_t)fFWIM, (uintptr_t)cmd, ((commandAddress.nodeID << 16) | commandAddress.addressHi), commandAddress.addressLo);
5280
5281					cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase,
5282										(const void*)(data+3), 4);
5283				}
5284				else
5285				{
5286#if (DEBUGGING_LEVEL > 0)
5287					DEBUGLOG( "Response from wrong node ID!\n" );
5288#endif
5289				}
5290
5291            }
5292            else {
5293#if (DEBUGGING_LEVEL > 0)
5294		DEBUGLOG("ReadQuadletResponse: label %d isn't in use!!\n", tLabel);
5295#endif
5296            }
5297            break;
5298
5299        case kFWTCodeReadBlockResponse :
5300        case kFWTCodeLockResponse :
5301            if(fTrans[tLabel].fHandler) {
5302
5303				IOFWAsyncCommand * cmd = fTrans[tLabel].fHandler;
5304				FWAddress commandAddress = cmd->getAddress();
5305
5306            	if( sourceID == commandAddress.nodeID )
5307            	{
5308            		cmd->setResponseSpeed( speed );
5309
5310					FWTrace(kFWTController, kTPControllerProcessRcvPacketRBR, (uintptr_t)fFWIM, (uintptr_t)cmd, ((commandAddress.nodeID << 16) | commandAddress.addressHi), commandAddress.addressLo);
5311
5312					cmd->gotPacket((data[1] & kFWAsynchRCode)>>kFWAsynchRCodePhase,
5313					(const void*)(data+4), (data[3] & kFWAsynchDataLength)>>kFWAsynchDataLengthPhase);
5314				}
5315				else
5316				{
5317#if (DEBUGGING_LEVEL > 0)
5318					DEBUGLOG( "Response from wrong node ID!\n" );
5319#endif
5320				}
5321            }
5322            else {
5323#if (DEBUGGING_LEVEL > 0)
5324				DEBUGLOG("ReadBlock/LockResponse: label %d isn't in use!!\n", tLabel);
5325#endif
5326            }
5327            break;
5328
5329        case kFWTCodeLock :
5330#if (DEBUGGING_LEVEL > 0)
5331            DEBUGLOG("Lock type %d: addr 0x%x -> 0x%x:0x%x:0x%x\n",
5332		(data[3] & kFWAsynchExtendedTCode) >> kFWAsynchExtendedTCodePhase, sourceID, destID,
5333		(data[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase,
5334		data[2]);
5335#endif
5336            processLockRequest(sourceID, tLabel, data, &data[4],
5337			(data[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase, speed);
5338
5339            break;
5340
5341        case kFWTCodeIsochronousBlock :
5342#if (DEBUGGING_LEVEL > 0)
5343            DEBUGLOG("Async Stream Packet\n");
5344#endif
5345            break;
5346
5347        default :
5348#if (DEBUGGING_LEVEL > 0)
5349            DEBUGLOG("Unexpected tcode in Asyncrecv: %d\n", tCode);
5350#endif
5351            break;
5352    }
5353}
5354
5355/////////////////////////////////////////////////////////////////////////////
5356// async request receive
5357//
5358
5359// createPhysicalAddressSpace
5360//
5361//
5362
5363IOFWPhysicalAddressSpace *
5364IOFireWireController::createPhysicalAddressSpace(IOMemoryDescriptor *mem)
5365{
5366    IOFWPhysicalAddressSpace *space;
5367    space = OSTypeAlloc( IOFWPhysicalAddressSpace );
5368    if(!space)
5369        return NULL;
5370    if(!space->initWithDesc(this, mem)) {
5371        space->release();
5372        space = NULL;
5373    }
5374    return space;
5375}
5376
5377// createAsyncStreamListener
5378//
5379//
5380
5381IOFWAsyncStreamListener *
5382IOFireWireController::createAsyncStreamListener( UInt32 channel, FWAsyncStreamReceiveCallback proc, void *refcon )
5383{
5384    IOFWAsyncStreamListener * listener = OSTypeAlloc( IOFWAsyncStreamListener );
5385
5386    if( listener )
5387	{
5388	    if(not listener->initAll( this, channel, proc, refcon ))
5389		{
5390			listener->release();
5391			listener = NULL;
5392		}
5393	}
5394
5395    return listener;
5396}
5397
5398void
5399IOFireWireController::removeAsyncStreamListener(IOFWAsyncStreamListener *listener)
5400{
5401	IOFWAsyncStreamReceiver *receiver = listener->getReceiver();
5402
5403	receiver->removeListener(listener);
5404}
5405
5406// createPseudoAddressSpace
5407//
5408//
5409
5410IOFWPseudoAddressSpace *
5411IOFireWireController::createPseudoAddressSpace(FWAddress *addr, UInt32 len,
5412                            FWReadCallback reader, FWWriteCallback writer, void *refcon)
5413{
5414    IOFWPseudoAddressSpace *space;
5415    space = OSTypeAlloc( IOFWPseudoAddressSpace );
5416    if(!space)
5417        return NULL;
5418    if(!space->initAll(this, addr, len, reader, writer, refcon)) {
5419        space->release();
5420        space = NULL;
5421    }
5422    return space;
5423}
5424
5425// createInitialAddressSpace
5426//
5427//
5428
5429IOFWPseudoAddressSpace *
5430IOFireWireController::createInitialAddressSpace(UInt32 addressLo, UInt32 len,
5431                            FWReadCallback reader, FWWriteCallback writer, void *refcon)
5432{
5433    IOFWPseudoAddressSpace *space;
5434    space = OSTypeAlloc( IOFWPseudoAddressSpace );
5435    if(!space)
5436        return NULL;
5437    if(!space->initFixed(this, FWAddress(kCSRRegisterSpaceBaseAddressHi, addressLo),
5438            len, reader, writer, refcon)) {
5439        space->release();
5440        space = NULL;
5441    }
5442    return space;
5443}
5444
5445// getAddressSpace
5446//
5447//
5448
5449IOFWAddressSpace *
5450IOFireWireController::getAddressSpace(FWAddress address)
5451{
5452    closeGate();
5453
5454	IOFWAddressSpace * found;
5455    fSpaceIterator->reset();
5456    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
5457        if(found->contains(address))
5458            break;
5459    }
5460
5461	openGate();
5462
5463	return found;
5464}
5465
5466
5467// allocAsyncStreamReceiver
5468//
5469//
5470IOFWAsyncStreamReceiver *
5471IOFireWireController::allocAsyncStreamReceiver(UInt32	channel, FWAsyncStreamReceiveCallback clientProc, void	*refcon)
5472{
5473	closeGate();
5474
5475    IOFWAsyncStreamReceiver * receiver = OSTypeAlloc( IOFWAsyncStreamReceiver );
5476
5477    if( receiver )
5478	{
5479		if( receiver->initAll( this, channel ) )
5480		{
5481			if( fLocalAsyncStreamReceivers->setObject( receiver ))
5482				receiver->release();
5483		}
5484		else
5485		{
5486			receiver->release();
5487			receiver = NULL;
5488		}
5489	}
5490
5491	openGate();
5492
5493	return receiver;
5494}
5495
5496// getAsyncStreamReceiver
5497//
5498//
5499IOFWAsyncStreamReceiver *
5500IOFireWireController::getAsyncStreamReceiver( UInt32 channel )
5501{
5502    closeGate();
5503
5504	IOFWAsyncStreamReceiver * found = NULL;
5505	OSIterator *iterator = OSCollectionIterator::withCollection(fLocalAsyncStreamReceivers);
5506	if( iterator != NULL )
5507	{
5508		found = NULL;
5509		while( (found = OSDynamicCast(IOFWAsyncStreamReceiver, iterator->getNextObject())) )
5510		{
5511			if( found and found->listens(channel) )
5512				break;
5513		}
5514		iterator->release();
5515	}
5516
5517	openGate();
5518
5519	return found;
5520}
5521
5522// removeAsyncStreamReceiver
5523//
5524//
5525void
5526IOFireWireController::removeAsyncStreamReceiver( IOFWAsyncStreamReceiver *receiver )
5527{
5528    closeGate();
5529
5530	fLocalAsyncStreamReceivers->removeObject(receiver);
5531
5532	openGate();
5533}
5534
5535// activateAsyncStreamReceivers
5536//
5537//
5538void
5539IOFireWireController::activateAsyncStreamReceivers( )
5540{
5541    closeGate();
5542
5543	OSIterator *iterator = OSCollectionIterator::withCollection(fLocalAsyncStreamReceivers);
5544	if( iterator != NULL )
5545	{
5546		IOFWAsyncStreamReceiver * found = NULL;
5547		while( (found = OSDynamicCast(IOFWAsyncStreamReceiver, iterator->getNextObject())) )
5548		{
5549			if( found )
5550				found->activate( getBroadcastSpeed() );
5551		}
5552		iterator->release();
5553	}
5554
5555	openGate();
5556}
5557
5558// deactivateAsyncStreamReceivers
5559//
5560//
5561void
5562IOFireWireController::deactivateAsyncStreamReceivers( )
5563{
5564    closeGate();
5565
5566	OSIterator *iterator = OSCollectionIterator::withCollection(fLocalAsyncStreamReceivers);
5567	if( iterator != NULL )
5568	{
5569		IOFWAsyncStreamReceiver * found = NULL;
5570		while( (found =  OSDynamicCast(IOFWAsyncStreamReceiver, iterator->getNextObject())) )
5571		{
5572			if( found )
5573				found->deactivate();
5574		}
5575		iterator->release();
5576	}
5577
5578	openGate();
5579}
5580
5581// freeAllAsyncStreamReceiver
5582//
5583//
5584void
5585IOFireWireController::freeAllAsyncStreamReceiver()
5586{
5587    closeGate();
5588
5589	OSIterator *iterator = OSCollectionIterator::withCollection(fLocalAsyncStreamReceivers);
5590	if( iterator != NULL )
5591	{
5592		IOFWAsyncStreamReceiver * found = NULL;
5593		while( (found = OSDynamicCast(IOFWAsyncStreamReceiver, iterator->getNextObject())) )
5594		{
5595			if( found )
5596				removeAsyncStreamReceiver( found );
5597		}
5598		iterator->release();
5599	}
5600
5601	openGate();
5602}
5603
5604// allocAddress
5605//
5606//
5607
5608IOReturn IOFireWireController::allocAddress(IOFWAddressSpace *space)
5609{
5610    /*
5611     * Lots of scope for optimizations here, perhaps building a hash table for
5612     * addresses etc.
5613     * Drivers may want to override this if their hardware can match addresses
5614     * without CPU intervention.
5615     */
5616    IOReturn result = kIOReturnSuccess;
5617
5618	closeGate();
5619
5620	// enforce exclusivity
5621	IOFWAddressSpace * found;
5622    fSpaceIterator->reset();
5623    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject()))
5624	{
5625		// if either of the conflicting address spaces wants to be exclusive
5626		if( space->isExclusive() || found->isExclusive() )
5627		{
5628			// check if they intersect
5629			if( found->intersects( space ) )
5630			{
5631				// we have a problem
5632				result = kIOReturnExclusiveAccess;
5633			}
5634		}
5635	}
5636
5637	if( result == kIOReturnSuccess )
5638	{
5639		if(!fLocalAddresses->setObject(space))
5640			result = kIOReturnNoMemory;
5641		else
5642			result = kIOReturnSuccess;
5643    }
5644
5645	openGate();
5646
5647	return result;
5648}
5649
5650// freeAddress
5651//
5652//
5653
5654void IOFireWireController::freeAddress(IOFWAddressSpace *space)
5655{
5656    closeGate();
5657
5658	fLocalAddresses->removeObject(space);
5659
5660	openGate();
5661}
5662
5663// allocatePseudoAddress
5664//
5665//
5666
5667IOReturn IOFireWireController::allocatePseudoAddress(FWAddress *addr, UInt32 lenDummy)
5668{
5669    unsigned int i, len;
5670    UInt8 * data;
5671    UInt8 used = 1;
5672
5673    closeGate();
5674
5675    if( fAllocatedAddresses == NULL )
5676    {
5677        fAllocatedAddresses = OSData::withCapacity(4);	// SBP2 + some spare
5678        fAllocatedAddresses->appendBytes(&used, 1);	// Physical always allocated
5679    }
5680
5681    if( !fAllocatedAddresses )
5682    {
5683        openGate();
5684        return kIOReturnNoMemory;
5685    }
5686
5687    len = fAllocatedAddresses->getLength();
5688    data = (UInt8*)fAllocatedAddresses->getBytesNoCopy();
5689    for( i=0; i<len; i++ )
5690    {
5691        if( data[i] == 0 )
5692        {
5693            data[i] = 1;
5694            addr->addressHi = i;
5695            addr->addressLo = 0;
5696
5697            openGate();
5698            return kIOReturnSuccess;
5699        }
5700    }
5701
5702    if( len >= 0xfffe )
5703    {
5704        openGate();
5705		return kIOReturnNoMemory;
5706    }
5707
5708    if( fAllocatedAddresses->appendBytes(&used, 1))
5709    {
5710        addr->addressHi = len;
5711        addr->addressLo = 0;
5712
5713        openGate();
5714        return kIOReturnSuccess;
5715    }
5716
5717    openGate();
5718    return kIOReturnNoMemory;
5719}
5720
5721// freePseudoAddress
5722//
5723//
5724
5725void IOFireWireController::freePseudoAddress(FWAddress addr, UInt32 lenDummy)
5726{
5727    unsigned int len;
5728    UInt8 * data;
5729
5730    closeGate();
5731
5732    assert( fAllocatedAddresses != NULL);
5733
5734    len = fAllocatedAddresses->getLength();
5735    assert(addr.addressHi < len);
5736    data = (UInt8*)fAllocatedAddresses->getBytesNoCopy();
5737    assert(data[addr.addressHi]);
5738    data[addr.addressHi] = 0;
5739
5740    openGate();
5741}
5742
5743#if 0
5744IOReturn MyTestingFWMultiIsochReceiveListenerCallback(void *refcon, IOFireWireMultiIsochReceivePacket *pPacket)
5745{
5746	DebugLog("AY_DEBUG: MyTestingFWMultiIsochReceiveListenerCallback\n");
5747
5748	pPacket->clientDone();
5749
5750	return kIOReturnSuccess;
5751}
5752#endif
5753
5754// processWriteRequest
5755//
5756// process quad and block writes.
5757
5758void IOFireWireController::processWriteRequest(UInt16 sourceID, UInt32 tLabel,
5759			UInt32 *hdr, void *buf, int len, IOFWSpeed speed)
5760{
5761    UInt32 ret = kFWResponseAddressError;
5762    FWAddress addr((hdr[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, hdr[2]);
5763    IOFWAddressSpace * found;
5764
5765#if 0
5766	// Special Andy Debug code to set/clear MultiIsochReceiver channels remotely via FireBug qwrite!
5767	if  ((addr.addressHi == 0xFFFF) && (addr.addressLo == 0xF0000A00) && (len == 4))
5768	{
5769		UInt32 add_chan = OSSwapBigToHostInt32(*((UInt32*) buf));
5770		DebugLog("Got quadlet-write to special MultiIsochReceiver channel-add address: add_chan=%d\n",add_chan);
5771		if (fFWIM)
5772		{
5773			IOReturn result;
5774			IOFireWireMultiIsochReceiveListener *pListener = createMultiIsochReceiveListener(add_chan,MyTestingFWMultiIsochReceiveListenerCallback,this);
5775			if (pListener)
5776			{
5777				result = pListener->Activate();
5778				if (result != kIOReturnSuccess)
5779					DebugLog("AY_DEBUG: pListener->Activate failed!\n");
5780
5781			}
5782			else
5783			{
5784				DebugLog("AY_DEBUG: createMultiIsochReceiveListener failed!\n");
5785			}
5786		}
5787	}
5788	else if  ((addr.addressHi == 0xFFFF) && (addr.addressLo == 0xF0000A04) && (len == 4))
5789	{
5790		//UInt32 remove_chan = OSSwapBigToHostInt32(*((UInt32*) buf));
5791		//InfoLog("Got quadlet-write to special MultiIsochReceiver channel-remove address: remove_chan=%d\n",remove_chan);
5792		//if (fFWIM)
5793		//	fFWIM->setLinkMode(kIOFWSetMultIsochReceiverChanRemove,remove_chan);
5794	}
5795	else if  ((addr.addressHi == 0xFFFF) && (addr.addressLo == 0xF0000A08) && (len == 4))
5796	{
5797		DebugLog("Got quadlet-write to special link-reset address\n");
5798		if (fFWIM)
5799			fFWIM->setLinkMode(kIOFWSetForceLinkReset,0);
5800	}
5801#endif
5802
5803    fSpaceIterator->reset();
5804    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
5805        ret = found->doWrite(sourceID, speed, addr, len, buf, (IOFWRequestRefCon)tLabel);
5806        if(ret != kFWResponseAddressError)
5807            break;
5808    }
5809
5810	FWTrace(kFWTController, kTPControllerProcessWriteRequest, (uintptr_t)fFWIM, sourceID, ret, tLabel);
5811
5812    if ( ((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase) != 0xffff )	// we should not respond to broadcast writes
5813		fFWIM->asyncWriteResponse(sourceID, speed, tLabel, ret, addr.addressHi);
5814	else
5815		DebugLog("Skipped asyncWriteResponse because destID=0x%x\n", (uint32_t)((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase));
5816}
5817
5818// processLockRequest
5819//
5820// process 32 and 64 bit locks.
5821
5822void IOFireWireController::processLockRequest(UInt16 sourceID, UInt32 tLabel,
5823			UInt32 *hdr, void *buf, int len, IOFWSpeed speed)
5824{
5825    UInt32 oldVal[2];
5826    UInt32 ret;
5827    UInt32 outLen =sizeof(oldVal);
5828    int type = (hdr[3] &  kFWAsynchExtendedTCode) >> kFWAsynchExtendedTCodePhase;
5829
5830    FWAddress addr((hdr[1] & kFWAsynchDestinationOffsetHigh) >> kFWAsynchDestinationOffsetHighPhase, hdr[2]);
5831
5832    IOFWRequestRefCon refcon = (IOFWRequestRefCon)(tLabel | kRequestIsLock | (type << kRequestExtTCodeShift));
5833
5834    ret = doLockSpace(sourceID, speed, addr, len, (const UInt32 *)buf, outLen, oldVal, type, refcon);
5835
5836	FWTrace(kFWTController, kTPControllerProcessLockRequest, (uintptr_t)fFWIM, ret, ((addr.nodeID << 16) & addr.addressHi), addr.addressLo);
5837
5838    if(ret != kFWResponsePending)
5839    {
5840        if ( ((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase) != 0xffff )	// we should not respond to broadcast locks
5841			fFWIM->asyncLockResponse(sourceID, speed, tLabel, ret, type, oldVal, outLen);
5842		else
5843			DebugLog("Skipped asyncLockResponse because destID=0x%x\n", (uint32_t)((hdr[0] & kFWAsynchDestinationID) >> kFWAsynchDestinationIDPhase));
5844    }
5845}
5846
5847// doReadSpace
5848//
5849//
5850
5851UInt32 IOFireWireController::doReadSpace(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
5852                                                IOMemoryDescriptor **buf, IOByteCount * offset, IODMACommand **dma_command,
5853                                                IOFWRequestRefCon refcon)
5854{
5855    IOFWAddressSpace * found;
5856    UInt32 ret = kFWResponseAddressError;
5857    fSpaceIterator->reset();
5858    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
5859        ret = found->doRead(nodeID, speed, addr, len, buf, offset,
5860                            refcon);
5861        if(ret != kFWResponseAddressError)
5862            break;
5863    }
5864
5865	// hack to pass the IODMACommand for the phys address space to the FWIM
5866
5867	if( (dma_command != NULL) && (ret != kFWResponseAddressError) )
5868	{
5869		IOFWPhysicalAddressSpace * phys_space = OSDynamicCast( IOFWPhysicalAddressSpace, found );
5870
5871		if( phys_space )
5872		{
5873			*dma_command = phys_space->getDMACommand();
5874		}
5875	}
5876
5877    return ret;
5878}
5879
5880// doWriteSpace
5881//
5882//
5883
5884UInt32 IOFireWireController::doWriteSpace(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
5885                                            const void *buf, IOFWRequestRefCon refcon)
5886{
5887    IOFWAddressSpace * found;
5888    UInt32 ret = kFWResponseAddressError;
5889    fSpaceIterator->reset();
5890    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
5891        ret = found->doWrite(nodeID, speed, addr, len, buf, refcon);
5892        if(ret != kFWResponseAddressError)
5893            break;
5894    }
5895    return ret;
5896}
5897
5898// doLockSpace
5899//
5900//
5901
5902UInt32 IOFireWireController::doLockSpace(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 inLen,
5903                                         const UInt32 *newVal,  UInt32 &outLen, UInt32 *oldVal, UInt32 type,
5904                                                IOFWRequestRefCon refcon)
5905{
5906    IOFWAddressSpace * found;
5907    UInt32 ret = kFWResponseAddressError;
5908    fSpaceIterator->reset();
5909    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject())) {
5910        ret = found->doLock(nodeID, speed, addr, inLen, newVal, outLen, oldVal, type, refcon);
5911        if(ret != kFWResponseAddressError)
5912            break;
5913    }
5914
5915    if(ret != kFWResponseComplete) {
5916        oldVal[0] = OSSwapHostToBigInt32(0xdeadbabe);
5917        outLen = 4;
5918    }
5919    return ret;
5920}
5921
5922// handleARxReqIntComplete
5923//
5924//
5925
5926void IOFireWireController::handleARxReqIntComplete( void )
5927{
5928    IOFWAddressSpace * found;
5929
5930    fSpaceIterator->reset();
5931    while( (found = (IOFWAddressSpace *) fSpaceIterator->getNextObject()) )
5932	{
5933		IOFWPseudoAddressSpace * space = OSDynamicCast( IOFWPseudoAddressSpace, found );
5934		if( space != NULL )
5935		{
5936			space->handleARxReqIntComplete();
5937		}
5938    }
5939}
5940
5941// isLockRequest
5942//
5943//
5944
5945bool IOFireWireController::isLockRequest(IOFWRequestRefCon refcon)
5946{
5947    return ((UInt64)refcon) & kRequestIsLock;
5948}
5949
5950// isQuadRequest
5951//
5952//
5953
5954bool IOFireWireController::isQuadRequest(IOFWRequestRefCon refcon)
5955{
5956    return ((UInt64)refcon) & kRequestIsQuad;
5957}
5958
5959// isCompleteRequest
5960//
5961//
5962
5963bool IOFireWireController::isCompleteRequest(IOFWRequestRefCon refcon)
5964{
5965    return ((UInt64)refcon) & kRequestIsComplete;
5966}
5967
5968// getExtendedTCode
5969//
5970//
5971
5972UInt32 IOFireWireController::getExtendedTCode(IOFWRequestRefCon refcon)
5973{
5974    return((UInt64)refcon & kRequestExtTCodeMask) >> kRequestExtTCodeShift;
5975}
5976
5977/////////////////////////////////////////////////////////////////////////////
5978// async response transmit
5979//
5980
5981// asyncReadResponse
5982//
5983// Send async read response packets
5984// useful for pseudo address spaces that require servicing outside the FireWire work loop.
5985
5986IOReturn IOFireWireController::asyncReadResponse(	UInt32 					generation,
5987													UInt16 					nodeID,
5988													int 					speed,
5989													IOMemoryDescriptor *	buf,
5990													IOByteCount 			offset,
5991													int 					size,
5992													IOFWRequestRefCon 		refcon )
5993{
5994    IOReturn result;
5995    UInt64 params = (UInt64)refcon;
5996    UInt32 label = params & kRequestLabel;
5997
5998    closeGate();
5999
6000	if( !checkGeneration(generation) )
6001	{
6002        result = kIOFireWireBusReset;
6003    }
6004	else if( params & kRequestIsQuad )
6005	{
6006		UInt32 quad = OSSwapHostToBigInt32(0xdeadbeef);
6007
6008		buf->readBytes( offset, &quad, 4 );
6009
6010		result = fFWIM->asyncReadQuadResponse(	nodeID,
6011												speed,
6012												label,
6013												kFWResponseComplete,
6014												quad );
6015    }
6016	else
6017    {
6018	    result = fFWIM->asyncReadResponse(	nodeID,
6019											speed,
6020											label,
6021											kFWResponseComplete,
6022											buf,
6023											offset,
6024											size,
6025											NULL );
6026    }
6027
6028	openGate();
6029
6030    return result;
6031}
6032
6033// asyncLockResponse
6034//
6035// Send async lock response packets
6036// useful for pseudo address spaces that require servicing outside the FireWire work loop.
6037
6038IOReturn IOFireWireController::asyncLockResponse( 	UInt32 					generation,
6039													UInt16 					nodeID,
6040													int 					speed,
6041													IOMemoryDescriptor *	buf,
6042													IOByteCount 			offset,
6043													int 					size,
6044													IOFWRequestRefCon 		refcon )
6045{
6046	FWTrace(kFWTController, kTPControllerAsyncLockResponse, (uintptr_t)fFWIM, nodeID, 0, 0);
6047
6048    IOReturn result;
6049    UInt64 params = (UInt64)refcon;
6050    UInt32 label = params & kRequestLabel;
6051
6052    closeGate();
6053
6054	if( !checkGeneration(generation) )
6055	{
6056        result = kIOFireWireBusReset;
6057    }
6058	else
6059    {
6060		void * bytes = IOMalloc( size );
6061
6062		buf->readBytes( offset, bytes, size );
6063
6064		result = fFWIM->asyncLockResponse(	nodeID,
6065											speed,
6066											label,
6067											kFWResponseComplete,
6068											getExtendedTCode(refcon),
6069											bytes,
6070											size );
6071
6072		IOFree( bytes, size );
6073
6074    }
6075
6076    openGate();
6077
6078    return result;
6079}
6080
6081/////////////////////////////////////////////////////////////////////////////
6082// timer command
6083//
6084
6085// createDelayedCmd
6086//
6087//
6088
6089IOFWDelayCommand * IOFireWireController::createDelayedCmd(UInt32 uSecDelay, FWBusCallback func, void *refcon)
6090{
6091    IOFWDelayCommand *delay;
6092    //IOLog("Creating delay of %d\n", uSecDelay);
6093    delay = OSTypeAlloc( IOFWDelayCommand );
6094    if(!delay)
6095        return NULL;
6096
6097    if(!delay->initWithDelay(this, uSecDelay, func, refcon))
6098	{
6099		delay->release();
6100        return NULL;
6101    }
6102
6103    return delay;
6104}
6105
6106#pragma mark -
6107/////////////////////////////////////////////////////////////////////////////
6108// isoch
6109//
6110
6111// createIsochChannel
6112//
6113//
6114
6115IOFWIsochChannel *IOFireWireController::createIsochChannel(	bool 		doIRM,
6116															UInt32 		bandwidth,
6117															IOFWSpeed 	prefSpeed,
6118															FWIsochChannelForceStopNotificationProc	stopProc,
6119															void *		stopRefCon )
6120{
6121	// NOTE: if changing this code, must also change IOFireWireUserClient::isochChannelAllocate()
6122
6123    IOFWIsochChannel *channel;
6124
6125    channel = OSTypeAlloc( IOFWIsochChannel );
6126    if(!channel)
6127	{
6128		return NULL;
6129	}
6130
6131    if( !channel->init(this, doIRM, bandwidth, prefSpeed, stopProc, stopRefCon) )
6132	{
6133		channel->release();
6134		channel = NULL;
6135    }
6136
6137    return channel;
6138}
6139
6140// createLocalIsochPort
6141//
6142//
6143
6144IOFWLocalIsochPort *IOFireWireController::createLocalIsochPort(	bool 			talking,
6145																DCLCommand *	opcodes,
6146																DCLTaskInfo *	info,
6147																UInt32 			startEvent,
6148																UInt32 			startState,
6149																UInt32 			startMask )
6150{
6151    IOFWLocalIsochPort *port;
6152    IODCLProgram *program;
6153
6154    program = fFWIM->createDCLProgram( talking, opcodes, info, startEvent, startState, startMask );
6155    if(!program)
6156		return NULL;
6157
6158    port = OSTypeAlloc( IOFWLocalIsochPort );
6159    if( !port )
6160	{
6161		program->release();
6162		return NULL;
6163    }
6164
6165    if(!port->init(program, this))
6166	{
6167		port->release();
6168		port = NULL;
6169    }
6170
6171    return port;
6172}
6173
6174// addAllocatedChannel
6175//
6176//
6177
6178void IOFireWireController::addAllocatedChannel(IOFWIsochChannel *channel)
6179{
6180    closeGate();
6181
6182	fAllocatedChannels->setObject(channel);
6183
6184	openGate();
6185}
6186
6187// removeAllocatedChannel
6188//
6189//
6190
6191void IOFireWireController::removeAllocatedChannel(IOFWIsochChannel *channel)
6192{
6193    closeGate();
6194
6195	fAllocatedChannels->removeObject(channel);
6196
6197	openGate();
6198}
6199
6200
6201void IOFireWireController::addToIRMAllocationSet(IOFireWireIRMAllocation *anObject)
6202{
6203	closeGate();
6204
6205	fIRMAllocationsAllocated->setObject(anObject);
6206
6207	openGate();
6208}
6209
6210void IOFireWireController::removeFromIRMAllocationSet(IOFireWireIRMAllocation *anObject)
6211{
6212	closeGate();
6213
6214	fIRMAllocationsAllocated->removeObject(anObject);
6215
6216	openGate();
6217}
6218
6219// addIRMAllocation
6220//
6221//
6222
6223void IOFireWireController::addIRMAllocation(IOFireWireIRMAllocation *irmAllocation)
6224{
6225    closeGate();
6226
6227	if( fIRMAllocationsAllocated->containsObject(irmAllocation) )
6228	{
6229		fIRMAllocations->setObject(irmAllocation);
6230	}
6231
6232	openGate();
6233}
6234
6235// removeIRMAllocation
6236//
6237//
6238
6239void IOFireWireController::removeIRMAllocation(IOFireWireIRMAllocation *irmAllocation)
6240{
6241    closeGate();
6242
6243	fIRMAllocations->removeObject(irmAllocation);
6244
6245	openGate();
6246}
6247
6248// allocateIRMBandwidthInGeneration
6249//
6250//
6251IOReturn IOFireWireController::allocateIRMBandwidthInGeneration(UInt32 bandwidthUnits, UInt32 generation)
6252{
6253	IOReturn res;
6254	UInt32 irmGeneration;
6255	UInt16 irmNodeID;
6256	IOFWCompareAndSwapCommand * fLockCmd;
6257	FWAddress addr;
6258	UInt32 expectedOldVal, newVal;
6259	UInt32 actualOldVal;
6260	bool lockSuccessful;
6261	UInt32 retries = 2;
6262
6263	// Get the current IRM and Generation
6264	getIRMNodeID(irmGeneration, irmNodeID);
6265
6266	// Check the current generation
6267	if (irmGeneration != generation)
6268		return kIOFireWireBusReset;
6269
6270	// Initialize the address for the current IRM's bandwidth available register
6271	addr.nodeID = irmNodeID;
6272	addr.addressHi = 0xFFFF;
6273	addr.addressLo = 0xF0000220;
6274
6275	// Start with the default, no-bandwidth allocated value for the old val!
6276	expectedOldVal = OSSwapHostToBigInt32(0x00001333);
6277
6278	// Create a compare/swap command
6279	fLockCmd = OSTypeAlloc( IOFWCompareAndSwapCommand );
6280	if (!fLockCmd)
6281		return kIOReturnNoMemory;
6282
6283	// Pre-initialize the compare/swap command. Reinit will take place before use!
6284	if (!fLockCmd->initAll(this,generation,addr, NULL, NULL,0,NULL,NULL))
6285	{
6286		fLockCmd->release();
6287		return kIOReturnError;
6288	}
6289
6290	while (retries > 0)
6291	{
6292		// Make sure, in the request, we don't set the newVal to a negative number
6293		if (bandwidthUnits > OSSwapBigToHostInt32(expectedOldVal))
6294		{
6295			res = kIOFireWireIsochBandwidthNotAvailable;
6296			break;
6297		}
6298
6299		// Calculate the new val for the compare/swap command
6300		newVal = OSSwapHostToBigInt32(OSSwapBigToHostInt32(expectedOldVal) - bandwidthUnits);
6301
6302		// Reinitialize the compare/swap command. If this fails, bail out of the retry loop!
6303		res = fLockCmd->reinit(generation,addr, &expectedOldVal, &newVal,1,NULL,NULL);
6304		if (res != kIOReturnSuccess)
6305			break;
6306
6307		// Submit the compare/swap command. Will not return until complete
6308		res = fLockCmd->submit();
6309
6310		// Check results, including actualOldVal
6311		if (res == kIOReturnSuccess)
6312			lockSuccessful = fLockCmd->locked(&actualOldVal);
6313		else
6314			lockSuccessful = false;
6315
6316		DebugLog("allocateIRMBandwidthInGeneration: res = 0x%08X, expectedOldVal = 0x%08X, newVal = 0x%08X, lockSuccessful = %d, actualOldVal = 0x%08X\n",
6317			  res, OSSwapBigToHostInt32(expectedOldVal),OSSwapBigToHostInt32(newVal),lockSuccessful,OSSwapBigToHostInt32(actualOldVal));
6318
6319		// If we got a bus reset (i.e. wrong generation), no point on retrying
6320		if (res == kIOFireWireBusReset)
6321			break;
6322
6323		// If we succeeded, we don't need to retry
6324		else if (lockSuccessful)
6325			break;
6326
6327		else
6328		{
6329			// Decrement the retry count
6330			retries -= 1;
6331
6332			// If we don't have an error, but we're here, it's because
6333			// the compare-swap didn't succeed. Set an error code, in case we're
6334			// out of retries.
6335			if (res == kIOReturnSuccess)
6336				res = kIOFireWireIsochBandwidthNotAvailable;
6337
6338			// Change our expected old value for the retry.
6339			expectedOldVal = actualOldVal;
6340		}
6341	}
6342
6343	// Release the lock command
6344	fLockCmd->release();
6345
6346	return res;
6347}
6348
6349// releaseIRMBandwidthInGeneration
6350//
6351//
6352IOReturn IOFireWireController::releaseIRMBandwidthInGeneration(UInt32 bandwidthUnits, UInt32 generation)
6353{
6354	IOReturn res;
6355	UInt32 irmGeneration;
6356	UInt16 irmNodeID;
6357	IOFWCompareAndSwapCommand * fLockCmd;
6358	FWAddress addr;
6359	UInt32 expectedOldVal, newVal;
6360	UInt32 actualOldVal;
6361	bool lockSuccessful;
6362	UInt32 retries = 2;
6363
6364	// Get the current IRM and Generation
6365	getIRMNodeID(irmGeneration, irmNodeID);
6366
6367	// Check the current generation
6368	if (irmGeneration != generation)
6369		return kIOFireWireBusReset;
6370
6371	// Initialize the address for the current IRM's bandwidth available register
6372	addr.nodeID = irmNodeID;
6373	addr.addressHi = 0xFFFF;
6374	addr.addressLo = kCSRBandwidthAvailable;
6375
6376	// Start with the default, no-bandwidth available value for the old val!
6377	expectedOldVal = OSSwapHostToBigInt32(0);
6378
6379	// Create a compare/swap command
6380	fLockCmd = OSTypeAlloc( IOFWCompareAndSwapCommand );
6381	if (!fLockCmd)
6382		return kIOReturnNoMemory;
6383
6384	// Pre-initialize the compare/swap command. Reinit will take place before use!
6385	if (!fLockCmd->initAll(this,generation,addr, NULL, NULL,0,NULL,NULL))
6386	{
6387		fLockCmd->release();
6388		return kIOReturnError;
6389	}
6390
6391	while (retries > 0)
6392	{
6393
6394#if 0
6395		// Make sure, in the request, we don't set an illegally large value
6396		if ((bandwidthUnits + OSSwapBigToHostInt32(expectedOldVal)) > 0x00001333 )
6397		{
6398			res = kIOReturnNoResources;
6399			break;
6400		}
6401#endif
6402
6403		// Calculate the new val for the compare/swap command
6404		newVal = OSSwapHostToBigInt32(OSSwapBigToHostInt32(expectedOldVal) + bandwidthUnits);
6405
6406		// Reinitialize the compare/swap command. If this fails, bail out of the retry loop!
6407		res = fLockCmd->reinit(generation,addr, &expectedOldVal, &newVal,1,NULL,NULL);
6408		if (res != kIOReturnSuccess)
6409			break;
6410
6411		// Submit the compare/swap command. Will not return until complete
6412		res = fLockCmd->submit();
6413
6414		// Check results, including actualOldVal
6415		if (res == kIOReturnSuccess)
6416			lockSuccessful = fLockCmd->locked(&actualOldVal);
6417		else
6418			lockSuccessful = false;
6419
6420		DebugLog("releaseIRMBandwidthInGeneration: res = 0x%08X, expectedOldVal = 0x%08X, newVal = 0x%08X, lockSuccessful = %d, actualOldVal = 0x%08X\n",
6421		res, OSSwapBigToHostInt32(expectedOldVal),OSSwapBigToHostInt32(newVal),lockSuccessful,OSSwapBigToHostInt32(actualOldVal));
6422
6423		// If we got a bus reset (i.e. wrong generation), no point on retrying
6424		if (res == kIOFireWireBusReset)
6425			break;
6426
6427		// If we succeeded, we don't need to retry
6428		else if (lockSuccessful)
6429			break;
6430
6431		else
6432		{
6433			// Decrement the retry count
6434			retries -= 1;
6435
6436			// If we don't have an error, but we're here, it's because
6437			// the compare-swap didn't succeed. Set an error code, in case we're
6438			// out of retries.
6439			if (res == kIOReturnSuccess)
6440				res = kIOReturnNoResources;
6441
6442			// Change our expected old value for the retry.
6443			expectedOldVal = actualOldVal;
6444		}
6445	}
6446
6447	// Release the lock command
6448	fLockCmd->release();
6449
6450	return res;
6451}
6452
6453// allocateIRMChannelInGeneration
6454//
6455//
6456IOReturn IOFireWireController::allocateIRMChannelInGeneration(UInt8 isochChannel, UInt32 generation)
6457{
6458	IOReturn res;
6459	UInt32 irmGeneration;
6460	UInt16 irmNodeID;
6461	IOFWCompareAndSwapCommand * fLockCmd;
6462	FWAddress addr;
6463	UInt32 newValMask;
6464	UInt32 expectedOldVal, newVal;
6465	UInt32 actualOldVal;
6466	bool lockSuccessful;
6467	UInt32 retries = 2;
6468
6469	// Get the current IRM and Generation
6470	getIRMNodeID(irmGeneration, irmNodeID);
6471
6472	// Check the current generation
6473	if (irmGeneration != generation)
6474		return kIOFireWireBusReset;
6475
6476	// Initialize the address for the current IRM's bandwidth available register
6477	addr.nodeID = irmNodeID;
6478	addr.addressHi = 0xFFFF;
6479
6480	if( isochChannel < 32 )
6481	{
6482		addr.addressLo = kCSRChannelsAvailable31_0;
6483		newValMask = OSSwapHostToBigInt32(~(1<<(31 - isochChannel)));
6484	}
6485	else if( isochChannel < 64 )
6486	{
6487		addr.addressLo = kCSRChannelsAvailable63_32;
6488		newValMask = OSSwapHostToBigInt32(~(1 << (63 - isochChannel)));
6489	}
6490	else
6491		return kIOReturnBadArgument;
6492
6493	// Start with the default, no channels allocated value for the old val!
6494	expectedOldVal = OSSwapHostToBigInt32(0xFFFFFFFF);
6495
6496	// Create a compare/swap command
6497	fLockCmd = OSTypeAlloc( IOFWCompareAndSwapCommand );
6498	if (!fLockCmd)
6499		return kIOReturnNoMemory;
6500
6501	// Pre-initialize the compare/swap command. Reinit will take place before use!
6502	if (!fLockCmd->initAll(this,generation,addr, NULL, NULL,0,NULL,NULL))
6503	{
6504		fLockCmd->release();
6505		return kIOReturnError;
6506	}
6507
6508	while (retries > 0)
6509	{
6510		// Make sure the channel is not already allocated
6511		if ((expectedOldVal & ~newValMask) == 0)
6512		{
6513			res = kIOFireWireChannelNotAvailable;
6514			break;
6515		}
6516
6517		// Calculate the new val for the compare/swap command
6518		newVal = expectedOldVal & newValMask;
6519
6520		// Reinitialize the compare/swap command. If this fails, bail out of the retry loop!
6521		res = fLockCmd->reinit(generation,addr, &expectedOldVal, &newVal,1,NULL,NULL);
6522		if (res != kIOReturnSuccess)
6523			break;
6524
6525		// Submit the compare/swap command. Will not return until complete
6526		res = fLockCmd->submit();
6527
6528		// Check results, including actualOldVal
6529		if (res == kIOReturnSuccess)
6530			lockSuccessful = fLockCmd->locked(&actualOldVal);
6531		else
6532			lockSuccessful = false;
6533
6534		DebugLog("allocateIRMChannelInGeneration: res = 0x%08X, expectedOldVal = 0x%08X, newVal = 0x%08X, lockSuccessful = %d, actualOldVal = 0x%08X\n",
6535		res, OSSwapBigToHostInt32(expectedOldVal),OSSwapBigToHostInt32(newVal),lockSuccessful,OSSwapBigToHostInt32(actualOldVal));
6536
6537		// If we got a bus reset (i.e. wrong generation), no point on retrying
6538		if (res == kIOFireWireBusReset)
6539			break;
6540
6541		// If we succeeded, we don't need to retry
6542		else if (lockSuccessful)
6543			break;
6544
6545		else
6546		{
6547			// Decrement the retry count
6548			retries -= 1;
6549
6550			// If we don't have an error, but we're here, it's because
6551			// the compare-swap didn't succeed. Set an error code, in case we're
6552			// out of retries.
6553			if (res == kIOReturnSuccess)
6554				res = kIOFireWireChannelNotAvailable;
6555
6556			// Change our expected old value for the retry.
6557			expectedOldVal = actualOldVal;
6558		}
6559	}
6560
6561	// Release the lock command
6562	fLockCmd->release();
6563
6564	return res;
6565}
6566
6567// releaseIRMChannelInGeneration
6568//
6569//
6570IOReturn IOFireWireController::releaseIRMChannelInGeneration(UInt8 isochChannel, UInt32 generation)
6571{
6572	IOReturn res;
6573	UInt32 irmGeneration;
6574	UInt16 irmNodeID;
6575	IOFWCompareAndSwapCommand * fLockCmd;
6576	FWAddress addr;
6577	UInt32 newValMask;
6578	UInt32 expectedOldVal, newVal;
6579	UInt32 actualOldVal;
6580	bool lockSuccessful;
6581	UInt32 retries = 2;
6582
6583	// Get the current IRM and Generation
6584	getIRMNodeID(irmGeneration, irmNodeID);
6585
6586	// Check the current generation
6587	if (irmGeneration != generation)
6588		return kIOFireWireBusReset;
6589
6590	// Initialize the address for the current IRM's bandwidth available register
6591	addr.nodeID = irmNodeID;
6592	addr.addressHi = 0xFFFF;
6593
6594	if( isochChannel < 32 )
6595	{
6596		addr.addressLo = kCSRChannelsAvailable31_0;
6597		newValMask = OSSwapHostToBigInt32(1<<(31 - isochChannel));
6598	}
6599	else if( isochChannel < 64 )
6600	{
6601		addr.addressLo = kCSRChannelsAvailable63_32;
6602		newValMask = OSSwapHostToBigInt32(1 << (63 - isochChannel));
6603	}
6604	else
6605		return kIOReturnBadArgument;
6606
6607	// Start with the default, all channels allocated value for the old val!
6608	expectedOldVal = OSSwapHostToBigInt32(0x00000000);
6609
6610	// Create a compare/swap command
6611	fLockCmd = OSTypeAlloc( IOFWCompareAndSwapCommand );
6612	if (!fLockCmd)
6613		return kIOReturnNoMemory;
6614
6615	// Pre-initialize the compare/swap command. Reinit will take place before use!
6616	if (!fLockCmd->initAll(this,generation,addr, NULL, NULL,0,NULL,NULL))
6617	{
6618		fLockCmd->release();
6619		return kIOReturnError;
6620	}
6621
6622	while (retries > 0)
6623	{
6624		// Make sure the channel is not already free
6625		if ((expectedOldVal & newValMask) == newValMask)
6626		{
6627			res = kIOReturnNoResources;
6628			break;
6629		}
6630
6631		// Calculate the new val for the compare/swap command
6632		newVal = expectedOldVal | newValMask;
6633
6634		// Reinitialize the compare/swap command. If this fails, bail out of the retry loop!
6635		res = fLockCmd->reinit(generation,addr, &expectedOldVal, &newVal,1,NULL,NULL);
6636		if (res != kIOReturnSuccess)
6637			break;
6638
6639		// Submit the compare/swap command. Will not return until complete
6640		res = fLockCmd->submit();
6641
6642		// Check results, including actualOldVal
6643		if (res == kIOReturnSuccess)
6644			lockSuccessful = fLockCmd->locked(&actualOldVal);
6645		else
6646			lockSuccessful = false;
6647
6648		DebugLog("releaseIRMChannelInGeneration: res = 0x%08X, expectedOldVal = 0x%08X, newVal = 0x%08X, lockSuccessful = %d, actualOldVal = 0x%08X\n",
6649		res, OSSwapBigToHostInt32(expectedOldVal),OSSwapBigToHostInt32(newVal),lockSuccessful,OSSwapBigToHostInt32(actualOldVal));
6650
6651		// If we got a bus reset (i.e. wrong generation), no point on retrying
6652		if (res == kIOFireWireBusReset)
6653			break;
6654
6655		// If we succeeded, we don't need to retry
6656		else if (lockSuccessful)
6657			break;
6658
6659		else
6660		{
6661			// Decrement the retry count
6662			retries -= 1;
6663
6664			// If we don't have an error, but we're here, it's because
6665			// the compare-swap didn't succeed. Set an error code, in case we're
6666			// out of retries.
6667			if (res == kIOReturnSuccess)
6668				res = kIOReturnNoResources;
6669
6670			// Change our expected old value for the retry.
6671			expectedOldVal = actualOldVal;
6672		}
6673	}
6674
6675	// Release the lock command
6676	fLockCmd->release();
6677
6678	return res;
6679}
6680
6681// createIRMAllocation
6682//
6683//
6684IOFireWireIRMAllocation * IOFireWireController::createIRMAllocation(Boolean releaseIRMResourcesOnFree,
6685											IOFireWireIRMAllocation::AllocationLostNotificationProc allocationLostProc,
6686											void *pLostNotificationProcRefCon)
6687{
6688	IOFireWireIRMAllocation * pIRMAllocation;
6689	pIRMAllocation = OSTypeAlloc( IOFireWireIRMAllocation );
6690    if( !pIRMAllocation )
6691        return NULL;
6692
6693	if( !pIRMAllocation->init(this,releaseIRMResourcesOnFree,allocationLostProc,pLostNotificationProcRefCon))
6694 	{
6695        pIRMAllocation->release();
6696        pIRMAllocation = NULL;
6697    }
6698
6699	return pIRMAllocation;
6700}
6701
6702#pragma mark -
6703////////////////////////////////////////////////////////////////////////////
6704
6705// activatePHYPacketListener
6706//
6707//
6708
6709IOReturn IOFireWireController::activatePHYPacketListener( IOFWPHYPacketListener * listener )
6710{
6711    IOReturn status = kIOReturnSuccess;
6712
6713	closeGate();
6714
6715	if( status == kIOReturnSuccess )
6716	{
6717		OSObject * prop = fFWIM->getProperty( "RcvPhyPkt" );
6718		if( prop )
6719		{
6720			UInt32 value = ((OSNumber*)prop)->unsigned32BitValue();
6721			if( value == 0 )
6722			{
6723				status = kIOReturnUnsupported;
6724			}
6725		}
6726	}
6727
6728	if( status == kIOReturnSuccess )
6729	{
6730		if( !fPHYPacketListeners->setObject( listener ) )
6731		{
6732			status = kIOReturnNoMemory;
6733		}
6734	}
6735
6736	openGate();
6737
6738	return status;
6739}
6740
6741// deactivatePHYPacketListener
6742//
6743//
6744
6745void IOFireWireController::deactivatePHYPacketListener( IOFWPHYPacketListener * listener )
6746{
6747    closeGate();
6748
6749	fPHYPacketListeners->removeObject( listener );
6750
6751	openGate();
6752}
6753
6754// processPHYPacket
6755//
6756// route incoming phy packets to all listeners
6757
6758void IOFireWireController::processPHYPacket( UInt32 data1, UInt32 data2 )
6759{
6760	// only process versaphy packets
6761	if(  data1 & 0x40000000 )
6762	{
6763		IOFWPHYPacketListener * listener;
6764		fPHYPacketListenersIterator->reset();
6765		while( (listener = (IOFWPHYPacketListener *)fPHYPacketListenersIterator->getNextObject()) )
6766		{
6767			listener->processPHYPacket( data1, data2 );
6768		}
6769	}
6770}
6771
6772// createPHYPacketListener
6773//
6774//
6775
6776IOFWPHYPacketListener *
6777IOFireWireController::createPHYPacketListener( FWPHYPacketCallback proc, void * refcon )
6778{
6779    IOFWPHYPacketListener * listener = IOFWPHYPacketListener::createWithController( this );
6780    if( listener )
6781	{
6782		listener->setCallback( proc );
6783		listener->setRefCon( refcon );
6784	}
6785
6786    return listener;
6787}
6788
6789#pragma mark -
6790////////////////////////////////////////////////////////////////////////////
6791
6792// getLocalNode
6793//
6794// static method to fetch the local node for a controller
6795
6796IOFireWireLocalNode * IOFireWireController::getLocalNode(IOFireWireController *control)
6797{
6798    OSIterator *childIterator;
6799    IOFireWireLocalNode *localNode = NULL;
6800    childIterator = control->getClientIterator();
6801    if( childIterator) {
6802        OSObject * child;
6803        while( (child = childIterator->getNextObject())) {
6804            localNode = OSDynamicCast(IOFireWireLocalNode, child);
6805            if(localNode) {
6806                break;
6807            }
6808        }
6809        childIterator->release();
6810    }
6811    return localNode;
6812}
6813
6814// getBusPowerManager
6815//
6816//
6817
6818IOFireWirePowerManager * IOFireWireController::getBusPowerManager( void )
6819{
6820	return fBusPowerManager;
6821}
6822
6823// getWorkLoop
6824//
6825//
6826
6827IOWorkLoop * IOFireWireController::getWorkLoop() const
6828{
6829    return fWorkLoop;
6830}
6831
6832// getLink
6833//
6834//
6835
6836IOFireWireLink * IOFireWireController::getLink() const
6837{
6838	return fFWIM;
6839}
6840
6841// getCycleTime
6842//
6843//
6844
6845IOReturn IOFireWireController::getCycleTime(UInt32 &cycleTime)
6846{
6847	IOReturn res;
6848
6849	res = fFWIM->getCycleTime(cycleTime);
6850
6851	return res;
6852}
6853
6854// getCycleTimeAndUpTime
6855//
6856//
6857
6858IOReturn IOFireWireController::getCycleTimeAndUpTime( UInt32 &cycleTime, UInt64 &uptime )
6859{
6860	IOReturn res;
6861
6862	res = fFWIM->getCycleTimeAndUpTime( cycleTime, uptime );
6863
6864	return res;
6865}
6866
6867// getBusCycleTime
6868//
6869//
6870
6871IOReturn IOFireWireController::getBusCycleTime(UInt32 &busTime, UInt32 &cycleTime)
6872{
6873    // Have to take workloop lock, in case the hardware is sleeping.
6874    IOReturn res;
6875    UInt32 cycleSecs;
6876
6877	closeGate();
6878
6879	res = fFWIM->getBusCycleTime(busTime, cycleTime);
6880
6881	openGate();
6882
6883	if(res == kIOReturnSuccess) {
6884        // Bottom 7 bits of busTime should be same as top 7 bits of cycle time.
6885        // However, link only updates bus time every few seconds,
6886        // so use cycletime for overlapping bits and check for cycletime wrap
6887        cycleSecs = cycleTime >> 25;
6888        // Update bus time.
6889        if((busTime & 0x7F) > cycleSecs) {
6890            // Must have wrapped, increment top part of busTime.
6891            cycleSecs += 0x80;
6892        }
6893        busTime = (busTime & ~0x7F) + cycleSecs;
6894    }
6895    return res;
6896}
6897
6898// hopCount
6899//
6900//
6901
6902UInt32 IOFireWireController::hopCount(UInt16 nodeAAddress, UInt16 nodeBAddress )
6903{
6904	nodeAAddress &= kFWMaxNodesPerBus;
6905	nodeBAddress &= kFWMaxNodesPerBus;
6906
6907	UInt16 lowNode = nodeAAddress > nodeBAddress ? nodeBAddress : nodeAAddress;
6908
6909    struct FWNodeScan
6910    {
6911        int nodeID;
6912        int childrenRemaining;
6913    };
6914
6915    FWNodeScan scanList[fRootNodeID];
6916    FWNodeScan *level;
6917	level = scanList;
6918
6919	const unsigned int maxNodes = fRootNodeID+1;
6920	UInt8 hopArray[maxNodes*(maxNodes+1)];
6921	bzero(hopArray, sizeof(hopArray));
6922
6923	closeGate();
6924
6925	// this is the same basic algorithm used in buildTopology
6926    int i;
6927	// stop once we've found the lower node because there's enough info in the hop count table at that point
6928	for( i = fRootNodeID; i >= lowNode; i-- )
6929	{
6930		// Add node to bottom of tree
6931		level->nodeID = i;
6932		level->childrenRemaining = countNodeIDChildren( i );
6933
6934		if (i != fRootNodeID)
6935		{
6936			int parentNodeNum, scanNodeNum;
6937			parentNodeNum = (level-1)->nodeID;
6938			for (scanNodeNum = i + 1; scanNodeNum <= fRootNodeID; scanNodeNum++)
6939			{
6940				UInt8 hops = hopArray[(maxNodes + 1)*parentNodeNum + scanNodeNum];
6941
6942				// fill out entire table so we don't have to use extra math to use a triangular matrix
6943				hopArray[(maxNodes + 1)*i + scanNodeNum] = hops + 1;
6944				hopArray[(maxNodes + 1)*scanNodeNum + i] = hops + 1;
6945				//IOLog("Calc Hops %d-%d: %d dervied from %d-%d:%d\n", i, scanNodeNum, hops+1, parentNodeNum, scanNodeNum, hops);
6946			}
6947		}
6948
6949		// Find next child port.
6950		if (i > 0)
6951		{
6952			while (level->childrenRemaining == 0)
6953			{
6954				// Go up one level in tree.
6955				level--;
6956				if(level < scanList)
6957				{
6958					ErrorLog("FireWire: SelfIDs don't build a proper tree for hop counts (missing selfIDS?)!!\n");
6959					return 0xFFFFFFFF;	// this seems like the best thing to return here, impossibly large
6960				}
6961				// One less child to scan.
6962				level->childrenRemaining--;
6963			}
6964			// Go down one level in tree.
6965			level++;
6966		}
6967	}
6968
6969	openGate();
6970
6971	// since both sides of matrix are filled in, no special math is necessary
6972	return hopArray[(maxNodes + 1)*nodeAAddress + nodeBAddress];
6973}
6974
6975// hopCount
6976//
6977//
6978
6979UInt32 IOFireWireController::hopCount( UInt16 nodeAAddress )
6980{
6981	//closeGate();
6982
6983	UInt32 hops = hopCount( nodeAAddress, fLocalNodeID );
6984
6985	//openGate();
6986
6987	return hops;
6988}
6989
6990// FWSpeed
6991// Returns pre-determined speed between nodeAddress and localNode
6992//
6993
6994IOFWSpeed IOFireWireController::FWSpeed(UInt16 nodeAddress) const
6995{
6996	return FWSpeed(nodeAddress, fLocalNodeID);
6997}
6998
6999// FWSpeed
7000// Returns pre-determined speed between nodeA and nodeB
7001//
7002
7003IOFWSpeed IOFireWireController::FWSpeed(UInt16 nodeA, UInt16 nodeB) const
7004{
7005	unsigned int txSpeed = kFWSpeedInvalid;
7006	nodeA &= kFWMaxNodesPerBus;
7007	nodeB &= kFWMaxNodesPerBus;
7008
7009	if ( nodeA < kFWMaxNodesPerBus && nodeB < kFWMaxNodesPerBus )
7010	{
7011		if ( nodeA < nodeB )
7012			txSpeed = fSpeedVector[nodeA + ((nodeB * (nodeB + 1))/2)];
7013		else
7014			txSpeed = fSpeedVector[nodeB + ((nodeA * (nodeA + 1))/2)];
7015	}
7016	else
7017	{
7018		// Get the broadcast speed.
7019		// there's only one "broadcast speed", so looking for the slowest speed between
7020		// the localNode and all others is sufficient for the speed between any node
7021		// and the "broadcast node"
7022		unsigned int remoteNodeSpeed = kFWSpeedInvalid;
7023		int i;
7024
7025		for ( i=0; i <= fRootNodeID; i++ )
7026		{
7027			remoteNodeSpeed = (unsigned int)FWSpeed(fLocalNodeID, i);
7028			//IOLog("IOFireWireController::FWSpeed(%x,%x) getting broadcast speed %x-%x=0x%x\n", nodeA, nodeB, fLocalNodeID, i, remoteNodeSpeed);
7029			txSpeed = txSpeed > remoteNodeSpeed ? remoteNodeSpeed : txSpeed;
7030		}
7031	}
7032	//DebugLog("IOFireWireController::FWSpeed( %d, %d ) = %d\n", nodeA, nodeB, txSpeed);
7033
7034	return (IOFWSpeed)txSpeed;
7035}
7036
7037// setNodeSpeed
7038//
7039//
7040
7041void IOFireWireController::setNodeSpeed( UInt16 nodeA, UInt16 nodeB, UInt8 speed )
7042{
7043	nodeA &= kFWMaxNodesPerBus;
7044	nodeB &= kFWMaxNodesPerBus;
7045
7046	if ( nodeA < kFWMaxNodesPerBus && nodeB < kFWMaxNodesPerBus )
7047	{
7048		if ( nodeA < nodeB )
7049			fSpeedVector[nodeA + ((nodeB * (nodeB + 1))/2)] = speed;
7050		else
7051			fSpeedVector[nodeB + ((nodeA * (nodeA + 1))/2)] = speed;
7052	}
7053	//IOLog("setNodeSpeed( A:%d, B:%d, Speed:0x%x)\n", nodeA, nodeB, speed);
7054}
7055
7056void IOFireWireController::setNodeSpeed( UInt16 nodeAddress, UInt8 speed )
7057{
7058	setNodeSpeed(nodeAddress, fLocalNodeID, speed);
7059}
7060
7061void IOFireWireController::setNodeSpeed( UInt16 nodeAddress, IOFWSpeed speed )
7062{
7063	if ( speed > 0xFF )
7064		ErrorLog("FireWire: Trying to set speed map entry larger than 8 bits.\n");
7065
7066	setNodeSpeed(nodeAddress, fLocalNodeID, (UInt8)speed);
7067}
7068
7069// maxPackLog
7070//
7071// How big (as a power of two) can packets sent to/received from the node be?
7072
7073int IOFireWireController::maxPackLog(bool forSend, UInt16 nodeAddress) const
7074{
7075    int log;
7076
7077    log = 9+FWSpeed(nodeAddress);
7078    if( forSend )
7079	{
7080        if( log > fMaxSendLog )
7081		{
7082            log = fMaxSendLog;
7083		}
7084	}
7085    else
7086	{
7087		if( log > fMaxSendLog )
7088		{
7089			log = fMaxRecvLog;
7090		}
7091	}
7092
7093	if( fUseHalfSizePackets )
7094	{
7095		if( log > 1 )
7096		{
7097			log--;
7098		}
7099	}
7100
7101	return log;
7102}
7103
7104// maxPackLog
7105//
7106// How big (as a power of two) can packets sent from A to B be?
7107
7108int IOFireWireController::maxPackLog(UInt16 nodeA, UInt16 nodeB) const
7109{
7110    return 9+FWSpeed(nodeA, nodeB);
7111}
7112
7113// nodeIDtoDevice
7114//
7115//
7116
7117IOFireWireDevice * IOFireWireController::nodeIDtoDevice(UInt32 generation, UInt16 nodeID)
7118{
7119    OSIterator *childIterator;
7120    IOFireWireDevice * found = NULL;
7121
7122    if(!checkGeneration(generation))
7123    {
7124	    return NULL;
7125    }
7126
7127    childIterator = getClientIterator();
7128
7129    if( childIterator)
7130	{
7131        OSObject *child;
7132        while( (child = childIterator->getNextObject()))
7133		{
7134            found = OSDynamicCast(IOFireWireDevice, child);
7135
7136            // don't need to sync with open/close routines when checking for kNotTerminated
7137			if( found && (found->getTerminationState() == kNotTerminated) && found->fNodeID == nodeID )
7138			{
7139				break;
7140			}
7141		}
7142        childIterator->release();
7143    }
7144    return found;
7145}
7146
7147// getGeneration
7148//
7149//
7150
7151UInt32 IOFireWireController::getGeneration() const
7152{
7153	return fBusGeneration;
7154}
7155
7156// checkGeneration
7157//
7158//
7159
7160bool IOFireWireController::checkGeneration(UInt32 gen) const
7161{
7162	return gen == fBusGeneration;
7163}
7164
7165
7166// getLocalNodeID
7167//
7168//
7169
7170UInt16 IOFireWireController::getLocalNodeID() const
7171{
7172	return fLocalNodeID;
7173}
7174
7175// getIRMNodeID
7176//
7177//
7178
7179IOReturn IOFireWireController::getIRMNodeID(UInt32 &generation, UInt16 &id)
7180{
7181	closeGate();
7182
7183	generation = fBusGeneration;
7184	id = fIRMNodeID;
7185
7186	openGate();
7187
7188	return kIOReturnSuccess;
7189}
7190
7191// clipMaxRec2K
7192//
7193//
7194
7195IOReturn IOFireWireController::clipMaxRec2K( Boolean clipMaxRec )
7196{
7197    IOReturn res;
7198
7199	closeGate();
7200
7201	//IOLog("IOFireWireController::clipMaxRec2K\n");
7202
7203	res = fFWIM->clipMaxRec2K(clipMaxRec);
7204
7205	openGate();
7206
7207	return res;
7208}
7209
7210// makeRoot
7211//
7212//
7213
7214IOReturn IOFireWireController::makeRoot(UInt32 generation, UInt16 nodeID)
7215{
7216    IOReturn res = kIOReturnSuccess;
7217    nodeID &= 63;
7218
7219	closeGate();
7220
7221	if(!checkGeneration(generation))
7222        res = kIOFireWireBusReset;
7223    else if( fRootNodeID != nodeID ) {
7224        // Send phy packet to set root hold off bit for node
7225        res = fFWIM->sendPHYPacket((kFWConfigurationPacketID << kFWPhyPacketIDPhase) |
7226                    (nodeID << kFWPhyPacketPhyIDPhase) | kFWPhyConfigurationR);
7227        if(kIOReturnSuccess == res)
7228		{
7229			FWTrace(kFWTResetBusAction, kTPResetMakeRoot, (uintptr_t)fFWIM, 0, 0, 0 );
7230	//		IOLog( "IOFireWireController::makeRoot resetBus\n" );
7231            res = resetBus();
7232		}
7233	}
7234
7235    openGate();
7236
7237    return res;
7238}
7239
7240// nodeMustBeRoot
7241//
7242//
7243void IOFireWireController::nodeMustBeRoot( UInt32 nodeID )
7244{
7245	fForcedRootNodeID	= nodeID;
7246	fNodeMustBeRootFlag = true;
7247}
7248
7249// nodeMustNotBeRoot
7250//
7251//
7252void IOFireWireController::nodeMustNotBeRoot( UInt32 nodeID )
7253{
7254	nodeID &= nodeID & 0x3f;
7255
7256	if( not fDelegateCycleMaster )
7257	{
7258		if( fScans[nodeID] )
7259		{
7260			fScans[nodeID]->fMustNotBeRoot = true;
7261			fNodeMustNotBeRootFlag = true;
7262		}
7263	}
7264}
7265
7266// setGapCount
7267//
7268//
7269void IOFireWireController::setGapCount( UInt32 gapCount )
7270{
7271	fForcedGapCount = gapCount;
7272	fForcedGapFlag	= true;
7273}
7274
7275// useHalfSizePackets
7276//
7277//
7278
7279void IOFireWireController::useHalfSizePackets( void )
7280{
7281	fUseHalfSizePackets = true;
7282	fRequestedHalfSizePackets = true;
7283}
7284
7285// disablePhyPortForNodeIDOnSleep
7286//
7287//
7288
7289void IOFireWireController::disablePhyPortOnSleepForNodeID( UInt32 nodeID )
7290{
7291	UInt32					childNodeID;
7292	UInt32					childNumber = 0;
7293	UInt32					childPort;
7294
7295	for( childNodeID = 0; childNodeID < (UInt32)(fLocalNodeID & 63); childNodeID++ )
7296	{
7297		if( childNodeID == nodeID )
7298		{
7299			// Found it. Now, which port is it connected to?
7300			childPort = getPortNumberFromIndex( childNumber );
7301
7302			if( childPort != 0xFFFFFFFF ) {
7303				fFWIM->disablePHYPortOnSleep( 1 << childPort );
7304				break;
7305			}
7306		}
7307		if( hopCount( childNodeID, fLocalNodeID ) == 1 )
7308		{
7309			childNumber++;
7310		}
7311	}
7312}
7313
7314#pragma mark -
7315/////////////////////////////////////////////////////////////////////////////
7316// workloop lock
7317//
7318
7319// openGate
7320//
7321//
7322
7323void IOFireWireController::openGate()
7324{
7325	fPendingQ.fSource->openGate();
7326}
7327
7328// closeGate
7329//
7330//
7331
7332void IOFireWireController::closeGate()
7333{
7334	fPendingQ.fSource->closeGate();
7335}
7336
7337// inGate
7338//
7339//
7340
7341bool IOFireWireController::inGate()
7342{
7343	return fPendingQ.fSource->inGate();
7344}
7345
7346#pragma mark -
7347/////////////////////////////////////////////////////////////////////////////
7348// queues
7349//
7350
7351// getTimeoutQ
7352//
7353//
7354
7355IOFWCmdQ& IOFireWireController::getTimeoutQ()
7356{
7357	return fTimeoutQ;
7358}
7359
7360// getPendingQ
7361//
7362//
7363
7364IOFWCmdQ& IOFireWireController::getPendingQ()
7365{
7366	return fPendingQ;
7367}
7368
7369// getAfterResetHandledQ
7370//
7371//
7372
7373IOFWCmdQ &IOFireWireController::getAfterResetHandledQ()
7374{
7375	return fAfterResetHandledQ;
7376}
7377
7378// IOFireWireController
7379//
7380//
7381
7382void IOFireWireController::enterLoggingMode( void )
7383{
7384	// set controller IOReg property to signify we're in logging mode
7385	if ( fFWIM->enterLoggingMode() )
7386	{
7387		setProperty(kFireWireLoggingMode, true);
7388		setProperty( kFireWireGenerationID, "Suspended" );	//zzz set GenID so SysProf does timeout
7389	}
7390}
7391
7392// MultiIsochReceiveListener Methods
7393//
7394//
7395IOFireWireMultiIsochReceiveListener *
7396IOFireWireController::createMultiIsochReceiveListener(UInt32 channel,
7397													  FWMultiIsochReceiveListenerCallback callback,
7398													  void *pCallbackRefCon,
7399													  FWMultiIsochReceiveListenerParams *pListenerParams)
7400{
7401	return IOFireWireMultiIsochReceiveListener::create(this,channel,callback,pCallbackRefCon,pListenerParams);
7402}
7403
7404IOReturn IOFireWireController::activateMultiIsochReceiveListener(IOFireWireMultiIsochReceiveListener *pListener)
7405{
7406	return fFWIM->activateMultiIsochReceiveListener(pListener);
7407}
7408
7409IOReturn IOFireWireController::deactivateMultiIsochReceiveListener(IOFireWireMultiIsochReceiveListener *pListener)
7410{
7411	return fFWIM->deactivateMultiIsochReceiveListener(pListener);
7412}
7413
7414void IOFireWireController::clientDoneWithMultiIsochReceivePacket(IOFireWireMultiIsochReceivePacket *pPacket)
7415{
7416	fFWIM->clientDoneWithMultiIsochReceivePacket(pPacket);
7417}
7418
7419