1/*
2 *  IOFireWireLocalNode.cpp
3 *  IOFireWireFamily
4 *
5 *  Created by Niels on Fri Aug 16 2002.
6 *  Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
7 *
8 * @APPLE_LICENSE_HEADER_START@
9 *
10 * The contents of this file constitute Original Code as defined in and
11 * are subject to the Apple Public Source License Version 1.1 (the
12 * "License").  You may not use this file except in compliance with the
13 * License.  Please obtain a copy of the License at
14 * http://www.apple.com/publicsource and read it before using this file.
15 *
16 * This Original Code and all software distributed under the License are
17 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
18 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
19 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
21 * License for the specific language governing rights and limitations
22 * under the License.
23 *
24 * @APPLE_LICENSE_HEADER_END@
25 */
26/*
27	$Log: IOFireWireLocalNode.cpp,v $
28	Revision 1.12  2012/06/07 18:06:02  calderon
29	Fix IOFireWireController leak
30	<rdar://11005341> or <rdar://11411007>
31
32	Revision 1.11  2009/03/26 22:45:17  calderon
33	<rdar://6728033> User client fails to terminate with unexpected consuequences
34
35	Revision 1.10  2008/04/24 00:01:39  collin
36	more K640
37
38	Revision 1.9  2006/11/08 22:33:38  ayanowit
39	Changed the SetProperty(...) function on the IOFireWireLocalNode, which is used to instantiate objects with the IOFireWireMatchingNub, to add a new way
40	of instantiating IOFireWireMatchingNub matched objects, where we ensure that only one of those objects gets instantiated on the LocalNode (SummonNubExclusive).
41	This is part of the changes needed to get AppleFWAudio to start using the IOFireWireMatchingNub instead of directly matching on IOFireWireLocalNode.
42
43	Revision 1.8  2005/02/18 22:56:53  gecko1
44	3958781 Q45C EVT: FireWire ASP reporter says port speed is 800 Mb/sec
45
46	Revision 1.7  2003/10/16 00:57:20  collin
47	*** empty log message ***
48
49	Revision 1.6  2003/02/20 02:00:12  collin
50	*** empty log message ***
51
52	Revision 1.5  2003/02/17 21:47:52  collin
53	*** empty log message ***
54
55	Revision 1.4  2002/10/31 18:53:13  wgulland
56	Fix kernel panic when unloading family while reading ROMs
57
58	Revision 1.3  2002/10/18 23:29:44  collin
59	fix includes, fix cast which fails on new compiler
60
61	Revision 1.2  2002/09/25 00:27:24  niels
62	flip your world upside-down
63
64*/
65
66// public
67#import <IOKit/firewire/IOFireWireBus.h>
68#import <IOKit/firewire/IOFireWireController.h>
69
70// private
71#import "IOFireWireMagicMatchingNub.h"
72#import "IOFireWireLocalNode.h"
73
74OSDefineMetaClassAndStructors(IOFireWireLocalNodeAux, IOFireWireNubAux);
75OSMetaClassDefineReservedUnused(IOFireWireLocalNodeAux, 0);
76OSMetaClassDefineReservedUnused(IOFireWireLocalNodeAux, 1);
77OSMetaClassDefineReservedUnused(IOFireWireLocalNodeAux, 2);
78OSMetaClassDefineReservedUnused(IOFireWireLocalNodeAux, 3);
79
80#pragma mark -
81
82// init
83//
84//
85
86bool IOFireWireLocalNodeAux::init( IOFireWireLocalNode * primary )
87{
88	bool success = true;		// assume success
89
90	// init super
91
92    if( !IOFireWireNubAux::init( primary ) )
93        success = false;
94
95	if( success )
96	{
97	}
98
99	return success;
100}
101
102// free
103//
104//
105
106void IOFireWireLocalNodeAux::free()
107{
108	IOFireWireNubAux::free();
109}
110
111#pragma mark -
112
113OSDefineMetaClassAndStructors(IOFireWireLocalNode, IOFireWireNub)
114
115// init
116//
117//
118
119bool IOFireWireLocalNode::init(OSDictionary * propTable)
120{
121    if(!IOFireWireNub::init(propTable))
122       return false;
123    fMaxReadROMPackLog = 11;
124    fMaxReadPackLog = 11;
125    fMaxWritePackLog = 11;
126
127	fOpenClients = OSSet::withCapacity( 2 );
128	if( fOpenClients == NULL )
129		return false;
130
131    return true;
132}
133
134// createAuxiliary
135//
136// virtual method for creating auxiliary object.  subclasses needing to subclass
137// the auxiliary object can override this.
138
139IOFireWireNubAux * IOFireWireLocalNode::createAuxiliary( void )
140{
141	IOFireWireLocalNodeAux * auxiliary;
142
143	auxiliary = OSTypeAlloc( IOFireWireLocalNodeAux );
144
145    if( auxiliary != NULL && !auxiliary->init(this) )
146	{
147        auxiliary->release();
148        auxiliary = NULL;
149    }
150
151    return auxiliary;
152}
153
154// free
155//
156//
157
158void IOFireWireLocalNode::free()
159{
160    if( fOpenClients != NULL )
161	{
162        fOpenClients->release();
163		fOpenClients = NULL;
164	}
165
166    if ( fControl )
167    {
168        fControl->release();
169        fControl = NULL;
170    }
171
172    IOFireWireNub::free();
173}
174
175// attach
176//
177//
178
179bool IOFireWireLocalNode::attach(IOService * provider )
180{
181    assert(OSDynamicCast(IOFireWireController, provider));
182    if( !IOFireWireNub::attach(provider))
183        return (false);
184    fControl = (IOFireWireController *)provider;
185    fControl->retain();
186
187    return(true);
188}
189
190// setNodeProperties
191//
192//
193
194void IOFireWireLocalNode::setNodeProperties(UInt32 gen, UInt16 nodeID,
195                                        UInt32 *selfIDs, int numSelfIDs, IOFWSpeed maxSpeed )
196{
197    OSObject *prop;
198
199    fLocalNodeID = fNodeID = nodeID;
200    fGeneration = gen;
201
202	prop = OSNumber::withNumber(nodeID, 16);
203    setProperty(gFireWireNodeID, prop);
204    prop->release();
205
206    // Store selfIDs
207    prop = OSData::withBytes(selfIDs, numSelfIDs*sizeof(UInt32));
208    setProperty(gFireWireSelfIDs, prop);
209    prop->release();
210
211    prop = OSNumber::withNumber(maxSpeed, 32);
212    setProperty(gFireWireSpeed, prop);
213    prop->release();
214}
215
216// message
217//
218//
219
220IOReturn IOFireWireLocalNode::message( UInt32 mess, IOService * provider,
221                                    void * argument )
222{
223	if( kIOFWMessagePowerStateChanged == mess )
224	{
225		messageClients( mess );
226		return kIOReturnSuccess;
227	}
228
229	if( kIOFWMessageTopologyChanged == mess )
230	{
231		messageClients( mess );
232		return kIOReturnSuccess;
233	}
234
235    return IOService::message(mess, provider, argument );
236}
237
238// handleOpen
239//
240//
241
242bool IOFireWireLocalNode::handleOpen( 	IOService *	  forClient,
243                            IOOptionBits	  options,
244                            void *		  arg )
245{
246	bool ok = true ;
247
248	if ( fOpenClients->getCount() == 0)
249		ok = IOFireWireNub::handleOpen( this, 0, NULL ) ;
250
251	if ( ok )
252	{
253		fOpenClients->setObject( forClient );
254	}
255
256    return ok;
257}
258
259// handleClose
260//
261//
262
263void IOFireWireLocalNode::handleClose(   IOService *	  forClient,
264                            IOOptionBits	  options )
265{
266	if( fOpenClients->containsObject( forClient ) )
267	{
268		fOpenClients->removeObject( forClient );
269
270		if ( fOpenClients->getCount() == 0 )
271			IOFireWireNub::handleClose( this, 0 );
272	}
273}
274
275// handleIsOpen
276//
277//
278
279bool IOFireWireLocalNode::handleIsOpen( const IOService * forClient ) const
280{
281	return fOpenClients->containsObject( forClient );
282}
283
284// setProperties
285//
286//
287
288IOReturn IOFireWireLocalNode::setProperties( OSObject * properties )
289{
290	IOFireWireMagicMatchingNub *nub = NULL;
291    IOReturn ret = kIOReturnBadArgument;
292	bool doSummon = false;
293	OSIterator *localNodeChildIterator;
294	OSIterator *magicMatchingNubChildIterator;
295	OSObject *localNodeChild;
296	OSObject *matchingNubChild;
297	OSObject *desiredChild;
298	OSString *desiredChildString;
299
300    OSDictionary *dict = OSDynamicCast(OSDictionary, properties);
301    OSDictionary *summon;
302    if(!dict)
303        return kIOReturnUnsupported;
304
305	// Take the FireWire workloop lock, to prevent multi-thread issues
306	if (fControl)
307		fControl->closeGate();
308	else
309		return kIOReturnNoDevice;
310
311	summon = OSDynamicCast(OSDictionary, dict->getObject("SummonNubExclusive"));
312    if(summon)
313	{
314		//IOLog("SummonNubExclusive\n");
315
316		// For now, assume we'll need to summon the object
317		doSummon = true;
318
319		localNodeChildIterator = getClientIterator();
320		if( localNodeChildIterator )
321		{
322			while( (localNodeChild = localNodeChildIterator->getNextObject()) )
323			{
324				//IOLog("found a localNodeChild\n");
325
326				IOFireWireMagicMatchingNub * matchingNub = OSDynamicCast(IOFireWireMagicMatchingNub, localNodeChild);
327				if(matchingNub)
328				{
329					//IOLog("found a matchingNub\n");
330
331					desiredChild = matchingNub->getProperty( "IODesiredChild" );
332					if (desiredChild)
333					{
334						desiredChildString = OSDynamicCast(OSString,desiredChild);
335						if (desiredChildString)
336						{
337							//IOLog("desiredChildString = %s\n",desiredChildString->getCStringNoCopy());
338
339							magicMatchingNubChildIterator = matchingNub->getClientIterator();
340							if( magicMatchingNubChildIterator )
341							{
342								while( (matchingNubChild = magicMatchingNubChildIterator->getNextObject()) )
343								{
344									//IOLog("found a matchingNubChild\n");
345
346									// See if this matching nub's child is of the IODesiredChild class
347									if (matchingNubChild->metaCast(desiredChildString))
348									{
349										//IOLog("matchingNubChild is IODesiredChild\n");
350										doSummon = false;
351									}
352								}
353								magicMatchingNubChildIterator->release();
354							}
355						}
356					}
357				}
358			}
359			localNodeChildIterator->release();
360		}
361	}
362	else
363	{
364		summon = OSDynamicCast(OSDictionary, dict->getObject("SummonNub"));
365		if(!summon)
366			ret = kIOReturnBadArgument;
367		else
368			doSummon = true;
369	}
370
371    if (doSummon)
372	{
373		do {
374			nub = OSTypeAlloc( IOFireWireMagicMatchingNub );
375			if(!nub->init(summon))
376				break;
377			if (!nub->attach(this))
378				break;
379			nub->registerService(kIOServiceSynchronous);
380			// Kill nub if nothing matched
381			if(!nub->getClient()) {
382				nub->detach(this);
383			}
384			ret = kIOReturnSuccess;
385		} while (0);
386		if(nub)
387			nub->release();
388	}
389
390	if (fControl)
391		fControl->openGate();
392
393    return ret;
394}
395