1/*
2 * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22#include "IOFireWireIPUnit.h"
23#include "IOFireWireIP.h"
24#include <IOKit/IOMessage.h>
25#include <IOKit/firewire/IOFireWireBus.h>
26#include <IOKit/firewire/IOFWAddressSpace.h>
27#include <IOKit/firewire/IOConfigDirectory.h>
28#include "IOFWIPDefinitions.h"
29
30OSDefineMetaClassAndStructors(IOFireWireIPUnit, IOService)
31OSMetaClassDefineReservedUnused(IOFireWireIPUnit, 0);
32OSMetaClassDefineReservedUnused(IOFireWireIPUnit, 1);
33OSMetaClassDefineReservedUnused(IOFireWireIPUnit, 2);
34OSMetaClassDefineReservedUnused(IOFireWireIPUnit, 3);
35
36
37bool IOFireWireIPUnit::start(IOService *provider)
38{
39	fIPLocalNode	= NULL;
40	fFWBusInterface = NULL;
41	fStarted		= false;
42
43    fDevice = OSDynamicCast(IOFireWireNub, provider);
44
45    if ( not fDevice )
46        return false;
47
48	fDrb = NULL;
49
50    if ( not IOService::start(provider))
51        return (false);
52
53	IOFireWireController *control = fDevice->getController();
54	if ( not control )
55        return (false);
56
57	if ( not configureFWBusInterface(control) )
58	{
59		IOLog("IOFireWireIPUnit - configureFWBusInterface failed \n");
60        return (false);
61	}
62
63	UWIDE	eui64;
64
65    CSRNodeUniqueID	fwuid = fDevice->getUniqueID();
66
67	eui64.hi = (UInt32)(fwuid >> 32);
68	eui64.lo = (UInt32)(fwuid & 0xffffffff);
69
70	fDrb = fFWBusInterface->initDRBwithDevice(eui64, fDevice, false);
71
72    if ( not fDrb )
73	{
74		IOLog("IOFireWireIPUnit - initDRBwithDevice failed \n");
75        return (false);
76	}
77
78	fDrb->retain();
79
80	if ( fFWBusInterface->updateARBwithDevice(fDevice, eui64) == NULL )
81	{
82		IOLog("IOFireWireIPUnit - updateARBwithDevice failed \n");
83        return (false);
84	}
85
86	fFWBusInterface->fwIPUnitAttach();
87
88	fTerminateNotifier = IOService::addMatchingNotification(gIOTerminatedNotification,
89													serviceMatching("IOFWIPBusInterface"),
90													&busInterfaceTerminate, this, (void*)fFWBusInterface, 0);
91
92	fStarted = true;
93
94    registerService();
95
96    return true;
97}
98
99bool IOFireWireIPUnit::busInterfaceTerminate(void *target, void *refCon, IOService *newService, IONotifier * notifier)
100{
101	if(target == NULL || newService == NULL)
102		return false;
103
104	IOFireWireIPUnit	*unit = OSDynamicCast(IOFireWireIPUnit, (IOService *)target);
105
106	if ( not unit )
107		return false;
108
109	if ( unit->fStarted )
110	{
111		if ( unit->fFWBusInterface != refCon)
112			return false;
113
114		unit->terminate();
115	}
116
117	return true;
118}
119
120bool IOFireWireIPUnit::finalize(IOOptionBits options)
121{
122	if ( fStarted )
123	{
124		if ( fTerminateNotifier != NULL )
125			fTerminateNotifier->remove();
126
127		fTerminateNotifier = NULL;
128
129		if ( fFWBusInterface )
130			fFWBusInterface->fwIPUnitTerminate();
131
132		if ( fDrb )
133		{
134			fFWBusInterface->releaseARB(fDrb->fwaddr);
135
136			fFWBusInterface->releaseDRB(fDrb->fwaddr);
137
138			fDrb->release();
139		}
140
141		fDrb = NULL;
142
143		if ( fFWBusInterface )
144		{
145			fFWBusInterface->release();
146
147			if ( fFWBusInterface->getUnitCount() == 0 )
148				fFWBusInterface->terminate();
149		}
150
151		fFWBusInterface = NULL;
152
153		fDevice = NULL;
154	}
155	fStarted = false;
156
157	return IOService::finalize(options);
158}
159
160void IOFireWireIPUnit::free(void)
161{
162    IOService::free();
163}
164
165IOReturn IOFireWireIPUnit::message(UInt32 type, IOService *provider, void *argument)
166{
167    IOReturn res = kIOReturnSuccess;
168
169	switch (type)
170	{
171		case kIOMessageServiceIsTerminated:
172		case kIOMessageServiceIsRequestingClose:
173		case kIOMessageServiceIsSuspended:
174			break;
175
176		case kIOMessageServiceIsResumed:
177			if( fStarted )
178			{
179				fIPLocalNode->closeIPoFWGate();
180
181				updateDrb();
182
183				fIPLocalNode->openIPoFWGate();
184			}
185			break;
186
187		default: // default the action to return kIOReturnUnsupported
188			res = kIOReturnUnsupported;
189			break;
190	}
191
192    return res;
193}
194
195/*!
196    @function updateDrb
197    @abstract Updates the device reference block in the FireWire IP unit
198*/
199void IOFireWireIPUnit::updateDrb()
200{
201	if(fDrb)
202	{
203		fDrb->maxSpeed	 = fDevice->FWSpeed();
204		fDrb->maxPayload = fDevice->maxPackLog(true);
205		fFWBusInterface->updateBroadcastValues(true);
206	}
207}
208
209bool IOFireWireIPUnit::configureFWBusInterface(IOFireWireController *controller)
210{
211	bool status = false;
212
213	fIPLocalNode = getIPNode(controller);
214
215	if( fIPLocalNode )
216	{
217		fIPLocalNode->retain();
218
219		if ( fIPLocalNode->clientStarting() == true )
220		{
221			OSDictionary *matchingTable;
222
223			matchingTable = serviceMatching("IOFWIPBusInterface");
224
225			if ( matchingTable )
226			{
227				OSObject *prop = fIPLocalNode->getProperty(gFireWire_GUID);
228				if( prop )
229					matchingTable->setObject(gFireWire_GUID, prop);
230			}
231
232			waitForService( matchingTable );
233		}
234
235		fFWBusInterface = getIPTransmitInterface(fIPLocalNode) ;
236
237		status = true;
238		if( fFWBusInterface == NULL )
239			fFWBusInterface = new IOFWIPBusInterface;
240
241		status = fFWBusInterface->init(fIPLocalNode);
242		if( status )
243		{
244			fFWBusInterface->retain();
245		}
246		else
247		{
248			fFWBusInterface->release();
249			fFWBusInterface = 0;
250		}
251
252		fIPLocalNode->release();
253	}
254
255	return status;
256}
257
258IOFWIPBusInterface *IOFireWireIPUnit::getIPTransmitInterface(IOFireWireIP *fIPLocalNode)
259{
260	OSIterator	*childIterator = fIPLocalNode->getChildIterator(gIOServicePlane);
261
262
263	IORegistryEntry *child = NULL;
264	if(childIterator)
265	{
266		while((child = (IORegistryEntry*)childIterator->getNextObject()))
267		{
268			if(strncmp(child->getName(gIOServicePlane), "IOFWIPBusInterface", strlen("IOFWIPBusInterface")) == 0)
269				break;
270		}
271		childIterator->release();
272		childIterator = NULL;
273	}
274
275	IOFWIPBusInterface *fwBusInterface = NULL;
276
277	if(child)
278		fwBusInterface = OSDynamicCast(IOFWIPBusInterface, child);
279
280	return fwBusInterface;
281}
282
283IOFireWireIP *IOFireWireIPUnit::getIPNode(IOFireWireController *control)
284{
285	OSIterator	*iterator = getMatchingServices( serviceMatching("IOFireWireLocalNode") );
286
287	IOFireWireNub *localNode = NULL;
288
289	if( iterator )
290	{
291		IOService * obj = NULL;
292		while((obj = (IOService*)iterator->getNextObject()))
293		{
294			localNode = OSDynamicCast(IOFireWireNub, obj);
295			if(localNode)
296			{
297				if(localNode->getController() == control)
298					break;
299				else
300					localNode = NULL;
301			}
302		}
303		iterator->release();
304		iterator = NULL;
305	}
306
307	IOFireWireIP *fwIP = NULL;
308
309	if( localNode )
310	{
311		OSDictionary *matchingTable;
312
313		matchingTable = serviceMatching("IOFireWireIP");
314
315		if ( matchingTable )
316		{
317			OSObject *prop = localNode->getProperty(gFireWire_GUID);
318			if( prop )
319				matchingTable->setObject(gFireWire_GUID, prop);
320		}
321
322		fwIP = OSDynamicCast(IOFireWireIP, waitForService( matchingTable ));
323	}
324
325	return fwIP;
326}
327
328