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