1/*
2 * Copyright (c) 1998-2000 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 Apple Computer, Inc.  All rights reserved.
24 *
25 * HISTORY
26 * 21 May 99 wgulland created.
27 *
28 */
29
30#define DEBUGGING_LEVEL 0	// 1 = low; 2 = high; 3 = extreme
31#define DEBUGLOG kprintf
32#include <IOKit/assert.h>
33
34#include <IOKit/IOMessage.h>
35#include <IOKit/firewire/IOFireWireUnit.h>
36#include <IOKit/firewire/IOFireWireDevice.h>
37#include <IOKit/firewire/IOFireWireController.h>
38#include <IOKit/firewire/IOConfigDirectory.h>
39#import <IOKit/firewire/IOFWSimpleContiguousPhysicalAddressSpace.h>
40
41#include "FWDebugging.h"
42
43OSDefineMetaClassAndStructors(IOFireWireUnitAux, IOFireWireNubAux);
44OSMetaClassDefineReservedUnused(IOFireWireUnitAux, 0);
45OSMetaClassDefineReservedUnused(IOFireWireUnitAux, 1);
46OSMetaClassDefineReservedUnused(IOFireWireUnitAux, 2);
47OSMetaClassDefineReservedUnused(IOFireWireUnitAux, 3);
48
49#pragma mark -
50
51// init
52//
53//
54
55bool IOFireWireUnitAux::init( IOFireWireUnit * primary )
56{
57	bool success = true;		// assume success
58
59	// init super
60
61    if( !IOFireWireNubAux::init( primary ) )
62        success = false;
63
64	if( success )
65	{
66	}
67
68	return success;
69}
70
71// free
72//
73//
74
75void IOFireWireUnitAux::free()
76{
77	IOFireWireNubAux::free();
78}
79
80// isPhysicalAccessEnabled
81//
82//
83
84bool IOFireWireUnitAux::isPhysicalAccessEnabled( void )
85{
86	IOFireWireUnit * unit = (IOFireWireUnit*)fPrimary;
87	IOFireWireDevice * device = unit->fDevice;
88	return device->isPhysicalAccessEnabled();
89}
90
91// createSimpleContiguousPhysicalAddressSpace
92//
93//
94
95IOFWSimpleContiguousPhysicalAddressSpace * IOFireWireUnitAux::createSimpleContiguousPhysicalAddressSpace( vm_size_t size, IODirection direction )
96{
97    IOFWSimpleContiguousPhysicalAddressSpace * space = IOFireWireNubAux::createSimpleContiguousPhysicalAddressSpace( size, direction );
98
99	if( space != NULL )
100	{
101		space->addTrustedNode( ((IOFireWireUnit*)fPrimary)->fDevice );
102	}
103
104	return space;
105}
106
107// createSimplePhysicalAddressSpace
108//
109//
110
111IOFWSimplePhysicalAddressSpace * IOFireWireUnitAux::createSimplePhysicalAddressSpace( vm_size_t size, IODirection direction )
112{
113    IOFWSimplePhysicalAddressSpace * space = IOFireWireNubAux::createSimplePhysicalAddressSpace( size, direction );
114
115	if( space != NULL )
116	{
117		space->addTrustedNode( ((IOFireWireUnit*)fPrimary)->fDevice );
118	}
119
120	return space;
121}
122
123#pragma mark -
124
125/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
126
127OSDefineMetaClassAndStructors(IOFireWireUnit, IOFireWireNub)
128OSMetaClassDefineReservedUnused(IOFireWireUnit, 0);
129OSMetaClassDefineReservedUnused(IOFireWireUnit, 1);
130
131#pragma mark -
132/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
133
134// init
135//
136//
137
138bool IOFireWireUnit::init( OSDictionary *propTable, IOConfigDirectory *directory )
139{
140    if(!IOFireWireNub::init(propTable))
141        return false;
142
143    directory->retain();
144    fDirectory = directory;
145    return true;
146}
147
148// createAuxiliary
149//
150// virtual method for creating auxiliary object.  subclasses needing to subclass
151// the auxiliary object can override this.
152
153IOFireWireNubAux * IOFireWireUnit::createAuxiliary( void )
154{
155	IOFireWireUnitAux * auxiliary;
156
157	auxiliary = OSTypeAlloc( IOFireWireUnitAux );
158
159    if( auxiliary != NULL && !auxiliary->init(this) )
160	{
161        auxiliary->release();
162        auxiliary = NULL;
163    }
164
165    return auxiliary;
166}
167
168// attach
169//
170//
171
172bool IOFireWireUnit::attach( IOService *provider )
173{
174    fDevice = OSDynamicCast(IOFireWireDevice, provider);
175    if(!fDevice)
176		return false;
177	fDevice->retain();
178    if( !IOFireWireNub::attach(provider))
179        return (false);
180    fControl = fDevice->getController();
181    fControl->retain();
182    fDevice->getNodeIDGeneration(fGeneration, fNodeID, fLocalNodeID);
183
184	// check if this is a kprintf unit directory
185	OSNumber * spec_id_number = (OSNumber*)getProperty( gFireWireUnit_Spec_ID );
186	OSNumber * sw_vers_number = (OSNumber*)getProperty( gFireWireUnit_SW_Version );
187	if( spec_id_number && sw_vers_number )
188	{
189		if( (spec_id_number->unsigned32BitValue() == kIOFWSpecID_AAPL) &&
190			(sw_vers_number->unsigned32BitValue() == kIOFWSWVers_KPF) )
191		{
192			// tell the controller to enter logging mode
193			fControl->enterLoggingMode();
194		}
195	}
196
197    return true;
198}
199
200// free
201//
202//
203
204void IOFireWireUnit::free()
205{
206	if( fDevice != NULL )
207	{
208		fDevice->release();
209		fDevice = NULL;
210	}
211
212    IOFireWireNub::free();
213}
214
215// message
216//
217//
218
219IOReturn IOFireWireUnit::message( 	UInt32 		mess,
220									IOService *	provider,
221									void * 		argument )
222{
223    if(provider == fDevice &&
224       (kIOMessageServiceIsRequestingClose == mess ||
225        kIOFWMessageServiceIsRequestingClose == mess))
226	{
227        fDevice->getNodeIDGeneration(fGeneration, fNodeID, fLocalNodeID);
228		if( isOpen() )
229		{
230			messageClients( mess );
231        }
232
233		return kIOReturnSuccess;
234    }
235
236    // Propagate bus reset start/end messages
237    if(provider == fDevice &&
238       (kIOMessageServiceIsResumed == mess ||
239        kIOMessageServiceIsSuspended == mess))
240	{
241        fDevice->getNodeIDGeneration(fGeneration, fNodeID, fLocalNodeID);
242		messageClients( mess );
243        return kIOReturnSuccess;
244    }
245
246	if( kIOFWMessagePowerStateChanged == mess )
247	{
248		messageClients( mess );
249		return kIOReturnSuccess;
250	}
251
252	if( kIOFWMessageTopologyChanged == mess )
253	{
254		messageClients( mess );
255		return kIOReturnSuccess;
256	}
257
258    return IOService::message(mess, provider, argument );
259}
260
261/**
262 ** Matching methods
263 **/
264
265// matchPropertyTable
266//
267//
268
269bool IOFireWireUnit::matchPropertyTable( OSDictionary * table )
270{
271    //
272    // If the service object wishes to compare some of its properties in its
273    // property table against the supplied matching dictionary,
274    // it should do so in this method and return truth on success.
275    //
276    if (!IOFireWireNub::matchPropertyTable(table))  return false;
277
278    // We return success if the following expression is true -- individual
279    // comparisions evaluate to truth if the named property is not present
280    // in the supplied matching dictionary.
281
282    bool res = compareProperty(table, gFireWireUnit_Spec_ID) &&
283        compareProperty(table, gFireWireUnit_SW_Version) &&
284        compareProperty(table, gFireWireVendor_ID) &&
285        compareProperty(table, gFireWire_GUID);
286    return res;
287}
288
289#pragma mark -
290
291/////////////////////////////////////////////////////////////////////////////
292// open / close
293//
294
295// handleOpen
296//
297//
298
299bool IOFireWireUnit::handleOpen(	IOService *	  	forClient,
300									IOOptionBits	options,
301									void *		  	arg )
302{
303	// arbitration lock is held
304
305    bool success = true;
306
307	if( isOpen() )
308	{
309		success = false;
310	}
311
312	if( success )
313	{
314		success = fDevice->open( this, options, arg );
315	}
316
317	if( success )
318	{
319        success = IOFireWireNub::handleOpen( forClient, options, arg );
320    }
321
322	return success;
323}
324
325// handleClose
326//
327//
328
329void IOFireWireUnit::handleClose(   IOService *	  	forClient,
330									IOOptionBits	options )
331{
332	// arbitration lock is held
333
334	// retain since device->close() could start a termination thread
335
336    retain();
337
338	IOFireWireNub::handleClose(forClient, options);
339    fDevice->close( this, options );
340
341	if( getTerminationState() == kNeedsTermination )
342	{
343		setTerminationState( kTerminated );
344
345		retain();		// will be released in thread function
346
347		thread_t		thread;
348		if( kernel_thread_start((thread_continue_t)IOFireWireUnit::terminateUnitThreadFunc, this, &thread) == KERN_SUCCESS )
349		{
350			thread_deallocate(thread);
351		}
352	}
353
354	release();
355}
356
357// terminateUnit
358//
359//
360
361void IOFireWireUnit::terminateUnit( void )
362{
363	// synchronize with the open close routines
364
365	lockForArbitration();
366
367	// retain since we could start a termination thread
368    retain();
369
370	if( isOpen() )
371	{
372		if( getTerminationState() == kNotTerminated )
373		{
374			setTerminationState( kNeedsTermination );
375
376			// send our custom requesting close message
377
378			messageClients( kIOFWMessageServiceIsRequestingClose );
379		}
380	}
381	else
382	{
383		TerminationState state = getTerminationState();
384
385		// if we're closed, we shouldn't be in the kNeedsTermination state
386
387		FWKLOGASSERT( state != kNeedsTermination );
388
389		if( state == kNotTerminated )
390		{
391			setTerminationState( kTerminated );
392
393			retain();		// will be released in thread function
394
395			thread_t		thread;
396			if( kernel_thread_start((thread_continue_t)IOFireWireUnit::terminateUnitThreadFunc, this, &thread) == KERN_SUCCESS )
397			{
398				thread_deallocate(thread);
399			}
400		}
401	}
402
403	release();
404
405	unlockForArbitration();
406}
407
408// terminateUnitThreadFunc
409//
410//
411
412void IOFireWireUnit::terminateUnitThreadFunc( void * refcon )
413{
414    IOFireWireUnit *me = (IOFireWireUnit *)refcon;
415
416	FWKLOG(( "IOFireWireUnit::terminateUnitThreadFunc - entered terminate unit = 0x%08lx\n", me ));
417
418	me->fControl->closeGate();
419
420	// synchronize with open and close routines
421
422	me->lockForArbitration();
423
424    if( ( me->getTerminationState() == kTerminated) &&
425		  !me->isInactive() && !me->isOpen() )
426	{
427		// release arbitration lock before terminating.
428        // this leaves a small hole of someone opening the device right here,
429        // which shouldn't be too bad - the client will just get terminated too.
430
431		me->unlockForArbitration();
432
433		me->terminate();
434
435    }
436	else
437	{
438		me->unlockForArbitration();
439    }
440
441	me->fControl->openGate();
442
443	me->release();		// retained when thread was spawned
444
445	FWKLOG(( "IOFireWireUnit::terminateUnitThreadFunc - exiting terminate unit = 0x%08lx\n", me ));
446}
447
448// setConfigDirectory
449//
450//
451
452IOReturn IOFireWireUnit::setConfigDirectory( IOConfigDirectory * directory )
453{
454	// arbitration lock is held
455
456	IOReturn status = kIOReturnSuccess;
457
458	TerminationState state = getTerminationState();
459
460	FWKLOGASSERT( state != kTerminated );
461
462	if( state == kNeedsTermination )
463	{
464		setTerminationState( kNotTerminated );
465	}
466
467	status = IOFireWireNub::setConfigDirectory( directory );
468
469	return status;
470}
471
472#pragma mark -
473
474/////////////////////////////////////////////////////////////////////////////
475// node flags
476//
477
478// setNodeFlags
479//
480//
481
482void IOFireWireUnit::setNodeFlags( UInt32 flags )
483{
484	if( fDevice )
485		fDevice->setNodeFlags( flags );
486}
487
488// clearNodeFlags
489//
490//
491
492void IOFireWireUnit::clearNodeFlags( UInt32 flags )
493{
494	if( fDevice )
495		fDevice->clearNodeFlags( flags );
496}
497
498// getNodeFlags
499//
500//
501
502UInt32 IOFireWireUnit::getNodeFlags( void )
503{
504	if( fDevice )
505		return fDevice->getNodeFlags();
506	else
507		return 0;
508}
509
510// setMaxSpeed
511//
512//
513
514void IOFireWireUnit::setMaxSpeed( IOFWSpeed speed )
515{
516	if( fDevice )
517		fDevice->setMaxSpeed( speed );
518}
519
520#pragma mark -
521
522/////////////////////////////////////////////////////////////////////////////
523// address spaces
524//
525
526/*
527 * Create local FireWire address spaces for the device to access
528 */
529
530// createPhysicalAddressSpace
531//
532//
533
534IOFWPhysicalAddressSpace * IOFireWireUnit::createPhysicalAddressSpace( IOMemoryDescriptor *mem )
535{
536    IOFWPhysicalAddressSpace * space = fControl->createPhysicalAddressSpace(mem);
537
538	if( space != NULL )
539	{
540		space->addTrustedNode( fDevice );
541	}
542
543	return space;
544}
545
546// createPseudoAddressSpace
547//
548//
549
550IOFWPseudoAddressSpace * IOFireWireUnit::createPseudoAddressSpace( 	FWAddress *		addr,
551																	UInt32 			len,
552																	FWReadCallback 	reader,
553																	FWWriteCallback writer,
554																	void *			refcon )
555{
556    IOFWPseudoAddressSpace * space = fControl->createPseudoAddressSpace(addr, len, reader, writer, refcon);
557
558	if( space != NULL )
559	{
560		space->addTrustedNode( fDevice );
561	}
562
563	return space;
564
565}
566