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// public
24#import "FWDebugging.h"
25
26#import <IOKit/firewire/IOFireWireFamilyCommon.h>
27#import <IOKit/firewire/IOLocalConfigDirectory.h>
28#import <IOKit/firewire/IOFWUtils.h>
29#import <IOKit/firewire/IOFireWireNub.h>
30#import <IOKit/firewire/IOFireWireBus.h>
31
32// private
33#import "IOConfigEntry.h"
34#import "IOFireWireUserClient.h"
35#import "IOFWUserObjectExporter.h"
36
37
38// system
39#import <libkern/c++/OSIterator.h>
40#import <libkern/c++/OSData.h>
41#import <libkern/c++/OSArray.h>
42#import <libkern/c++/OSObject.h>
43#import <libkern/c++/OSString.h>
44#import <IOKit/IOLib.h>
45
46OSDefineMetaClassAndStructors(IOLocalConfigDirectory, IOConfigDirectory);
47OSMetaClassDefineReservedUsed(IOLocalConfigDirectory, 0);
48OSMetaClassDefineReservedUnused(IOLocalConfigDirectory, 1);
49OSMetaClassDefineReservedUnused(IOLocalConfigDirectory, 2);
50
51// init
52//
53//
54
55bool IOLocalConfigDirectory::init()
56{
57    if(!IOConfigDirectory::initWithOffset(0, 0))
58        return false;
59    fEntries = OSArray::withCapacity(2);
60    if(!fEntries)
61        return false;
62    return true;
63}
64
65// free
66//
67//
68
69void IOLocalConfigDirectory::free()
70{
71    if(fEntries)
72        fEntries->release();
73    if(fROM)
74        fROM->release();
75IOConfigDirectory::free();
76}
77
78// getBase
79//
80//
81
82const UInt32 *IOLocalConfigDirectory::getBase()
83{
84    if(fROM)
85        return ((const UInt32 *)fROM->getBytesNoCopy()) ;//+fStart+1;
86    else
87        return &fHeader;
88}
89
90IOConfigDirectory *IOLocalConfigDirectory::getSubDir(int start, int type)
91{
92	return NULL;
93}
94
95// lockData
96//
97//
98
99const UInt32 * IOLocalConfigDirectory::lockData( void )
100{
101	return getBase();
102}
103
104// unlockData
105//
106//
107
108void IOLocalConfigDirectory::unlockData( void )
109{
110	// nothing to do
111}
112
113// create
114//
115//
116
117IOLocalConfigDirectory *IOLocalConfigDirectory::create()
118{
119    IOLocalConfigDirectory *dir;
120    dir = OSTypeAlloc( IOLocalConfigDirectory );
121    if(!dir)
122        return NULL;
123
124    if(!dir->init()) {
125        dir->release();
126        return NULL;
127    }
128    return dir;
129}
130
131// update
132//
133//
134
135IOReturn IOLocalConfigDirectory::update(UInt32 offset, const UInt32 *&romBase)
136{
137    IOReturn res = kIOReturnSuccess;
138    if(!fROM) {
139        if(offset == 0)
140            romBase = &fHeader;
141        else
142            res = kIOReturnNoMemory;
143    }
144    else {
145        if(offset*sizeof(UInt32) <= fROM->getLength())
146            romBase = (const UInt32 *)fROM->getBytesNoCopy();
147        else
148            res = kIOReturnNoMemory;
149    }
150    return res;
151}
152
153// updateROMCache
154//
155//
156
157IOReturn IOLocalConfigDirectory::updateROMCache( UInt32 offset, UInt32 length )
158{
159	return kIOReturnSuccess;
160}
161
162// checkROMState
163//
164//
165
166IOReturn IOLocalConfigDirectory::checkROMState( void )
167{
168	return kIOReturnSuccess;
169}
170
171// incrementGeneration
172//
173//
174
175IOReturn IOLocalConfigDirectory::incrementGeneration( void )
176{
177	IOReturn status = kIOReturnSuccess;
178
179	unsigned int numEntries = fEntries->getCount();
180
181    unsigned int i;
182    for( i = 0; i < numEntries; i++ )
183	{
184		IOConfigEntry * entry = OSDynamicCast( IOConfigEntry, fEntries->getObject(i) );
185        if( entry == NULL )
186		{
187			IOLog( __FILE__" %d internal error!\n", __LINE__ );
188            status = kIOReturnInternalError;
189			break;
190		}
191
192        if( (entry->fType == kConfigImmediateKeyType) && (entry->fKey == kConfigGenerationKey) )
193		{
194			entry->fValue++;
195		}
196	}
197
198	return status;
199}
200
201// compile
202//
203//
204
205IOReturn IOLocalConfigDirectory::compile(OSData *rom)
206{
207    UInt32 header;
208    UInt32 big_header;
209	UInt16 crc = 0;
210    OSData *tmp;	// Temporary data for directory entries.
211    unsigned int size;
212    unsigned int numEntries;
213    unsigned int i;
214    unsigned int offset = 0;
215    if(fROM)
216        fROM->release();
217    fROM = rom;
218    rom->retain();
219    size = fROM->getLength();
220    fStart = size/sizeof(UInt32);
221    numEntries = fEntries->getCount();
222
223    /*
224     * We can't just compile into the rom, because the CRC for the directory
225     * depends on the entry data, and we can't (legally) overwrite data in an
226     * OSData (it needs an overwriteBytes() method).
227     * So compile into tmp, then calculate crc, then append lenth|crc and tmp.
228     */
229
230    rom->ensureCapacity(size + sizeof(UInt32)*(1+numEntries));
231    tmp = OSData::withCapacity(sizeof(UInt32)*(numEntries));
232    for( i = 0; i < numEntries; i++ )
233	{
234        IOConfigEntry *entry = OSDynamicCast(IOConfigEntry, fEntries->getObject(i));
235        UInt32 val;
236		UInt32 big_val;
237        if(!entry)
238		{
239			IOLog(__FILE__" %d internal error!\n", __LINE__ )  ;
240            return kIOReturnInternalError;	// Oops!
241		}
242
243        switch(entry->fType)
244		{
245            case kConfigImmediateKeyType:
246				val = entry->fValue;
247                break;
248            case kConfigOffsetKeyType:
249                val = (entry->fAddr.addressLo-kCSRRegisterSpaceBaseAddressLo)/sizeof(UInt32);
250                break;
251            case kConfigLeafKeyType:
252            case kConfigDirectoryKeyType:
253                val = numEntries-i+offset;
254                offset += entry->totalSize();
255                break;
256            default:
257				IOLog(__FILE__" %d internal error!\n", __LINE__ )  ;
258                return kIOReturnInternalError;	// Oops!
259        }
260
261        val |= entry->fKey << kConfigEntryKeyValuePhase;
262        val |= entry->fType << kConfigEntryKeyTypePhase;
263
264		big_val = OSSwapHostToBigInt32( val );
265        crc = FWUpdateCRC16(crc, big_val);
266
267        tmp->appendBytes(&big_val, sizeof(UInt32));
268    }
269
270    header = numEntries << kConfigLeafDirLengthPhase;
271    header |= crc;
272	big_header = OSSwapHostToBigInt32( header );
273    rom->appendBytes(&big_header, sizeof(UInt32));
274    rom->appendBytes(tmp);
275    tmp->release();
276
277    // Now (recursively) append each leaf and directory.
278    for(i=0; i<numEntries; i++)
279	{
280        IOConfigEntry *entry = OSDynamicCast(IOConfigEntry, fEntries->getObject(i));
281        UInt32 val;
282		UInt32 big_val;
283        if(!entry)
284		{
285            return kIOReturnInternalError;	// Oops!
286        }
287		switch(entry->fType)
288		{
289            case kConfigImmediateKeyType:
290            case kConfigOffsetKeyType:
291                break;
292            case kConfigLeafKeyType:
293            {
294                OSData *data = OSDynamicCast(OSData, entry->fData);
295                const void *buffer;
296                unsigned int len, pad;
297                if(data)
298				{
299                    len = data->getLength();
300                    pad = (4 - (len & 3)) & 3;
301                    if(pad)
302					{
303                        len += pad;
304                        // Make sure the buffer is big enough for the CRC calc.
305                        data->ensureCapacity(len);
306                    }
307                    buffer = data->getBytesNoCopy();
308                }
309                else
310				{
311                    return kIOReturnInternalError;	// Oops!
312                }
313
314				crc = FWComputeCRC16((const UInt32 *)buffer, len / 4);
315                val = (len/4) << kConfigLeafDirLengthPhase;
316                val |= crc;
317				big_val = OSSwapHostToBigInt32( val );
318				rom->appendBytes(&big_val, sizeof(UInt32));
319                rom->appendBytes(buffer, len);
320                break;
321            }
322            case kConfigDirectoryKeyType:
323            {
324                IOReturn res;
325                IOLocalConfigDirectory *dir = OSDynamicCast(IOLocalConfigDirectory,
326                                                         	entry->fData);
327                if(!dir)
328                    return kIOReturnInternalError;	// Oops!
329                res = dir->compile(rom);
330                if(kIOReturnSuccess != res)
331                    return res;
332                break;
333            }
334            default:
335                return kIOReturnInternalError;	// Oops!
336       }
337    }
338    return kIOReturnSuccess;
339}
340
341// addEntry
342//
343//
344
345IOReturn IOLocalConfigDirectory::addEntry(int key, UInt32 value, OSString* desc )
346{
347    IOReturn res;
348
349	IOConfigEntry *entry = IOConfigEntry::create(key, value);
350
351	if(!entry)
352	{
353		return kIOReturnNoMemory;
354	}
355	if(!fEntries->setObject(entry))
356	{
357		res = kIOReturnNoMemory;
358	}
359	else
360	{
361		res = kIOReturnSuccess;
362	}
363
364	entry->release();	// In array now.
365
366	if(desc)
367	{
368		addEntry(desc);
369	}
370
371	// keep our count current...
372	fNumEntries = fEntries->getCount() ;
373
374	return res;
375}
376
377// addEntry
378//
379//
380
381IOReturn IOLocalConfigDirectory::addEntry( int key, IOLocalConfigDirectory *value, OSString* desc )
382{
383    IOReturn res;
384
385	IOConfigEntry *entry = IOConfigEntry::create(key, kConfigDirectoryKeyType, value);
386	if(!entry)
387	{
388		return kIOReturnNoMemory;
389	}
390	if(!fEntries->setObject(entry))
391	{
392		res = kIOReturnNoMemory;
393	}
394	else
395	{
396		res = kIOReturnSuccess;
397	}
398
399	entry->release();	// In array now.
400	if(desc)
401	{
402		addEntry(desc);
403	}
404
405	// keep our count current...
406	fNumEntries = fEntries->getCount() ;
407
408	return res;
409}
410
411// addEntry
412//
413//
414
415IOReturn IOLocalConfigDirectory::addEntry(int key, OSData *value, OSString* desc )
416{
417    IOReturn res;
418
419	// copying the OSData makes us robust against clients
420	// which modify the OSData after they pass it in to us.
421
422	OSData * valueCopy = OSData::withData( value );
423	if( valueCopy == NULL )
424		return kIOReturnNoMemory;
425
426	IOConfigEntry *entry = IOConfigEntry::create(key, kConfigLeafKeyType, valueCopy );
427	if( entry == NULL )
428	{
429		return kIOReturnNoMemory;
430	}
431
432	valueCopy->release();
433	valueCopy = NULL;
434
435	if(!fEntries->setObject(entry))
436	{
437		res = kIOReturnNoMemory;
438	}
439	else
440	{
441		res = kIOReturnSuccess;
442	}
443
444	entry->release();	// In array now.
445
446	if(desc)
447	{
448		addEntry(desc);
449	}
450
451	// keep our count current...
452	fNumEntries = fEntries->getCount() ;
453
454	return res;
455}
456
457// addEntry
458//
459//
460
461IOReturn IOLocalConfigDirectory::addEntry( int key, FWAddress value, OSString* desc )
462{
463    IOReturn res;
464
465	IOConfigEntry *entry = IOConfigEntry::create(key, value);
466	if(!entry)
467	{
468		return kIOReturnNoMemory;
469	}
470	if(!fEntries->setObject(entry))
471	{
472		res = kIOReturnNoMemory;
473	}
474	else
475	{
476		res = kIOReturnSuccess;
477	}
478	entry->release();	// In array now.
479	if(desc)
480	{
481		addEntry(desc);
482	}
483
484	// keep our count current...
485	fNumEntries = fEntries->getCount() ;
486
487	return res;
488}
489
490// addEntry
491//
492//
493
494IOReturn IOLocalConfigDirectory::addEntry(OSString *desc)
495{
496    IOReturn res;
497    OSData * value;
498
499	UInt64 zeros = 0;
500
501    int stringLength = desc->getLength();
502	int paddingLength = (4 - (stringLength & 3)) & 3;
503	int headerLength = 8;
504
505	// make an OSData containing the string
506	value = OSData::withCapacity( headerLength + stringLength + paddingLength );
507	if( !value )
508	{
509		return kIOReturnNoMemory;
510	}
511
512	// append zeros for header
513 	value->appendBytes( &zeros, headerLength );
514
515	// append the string
516    value->appendBytes( desc->getCStringNoCopy(), stringLength );
517
518	// append zeros to pad to nearest quadlet
519	value->appendBytes( &zeros, paddingLength );
520
521	res = addEntry( kConfigTextualDescriptorKey, value );
522
523	value->release(); 	// In ROM now
524	desc->release();	// call eats a retain count
525
526	// keep our count current...
527	fNumEntries = fEntries->getCount() ;
528
529    return res;
530}
531
532// removeSubDir
533//
534//
535
536IOReturn IOLocalConfigDirectory::removeSubDir(IOLocalConfigDirectory *value)
537{
538    unsigned int i, numEntries;
539    numEntries = fEntries->getCount();
540
541	for(i=0; i<numEntries; ++i)
542	{
543		IOConfigEntry *entry = OSDynamicCast(IOConfigEntry, fEntries->getObject(i));
544		if(!entry)
545		{
546			return kIOReturnInternalError;	// Oops!
547		}
548		if(entry->fType == kConfigDirectoryKeyType)
549		{
550			if(entry->fData == value)
551			{
552				fEntries->removeObject(i);
553
554				// keep our count current...
555				fNumEntries = fEntries->getCount() ;
556
557				return kIOReturnSuccess;
558			}
559		}
560	}
561	return kIOConfigNoEntry;
562}
563
564// getEntries
565//
566//
567
568const OSArray * IOLocalConfigDirectory::getEntries() const
569{
570	return fEntries;
571}
572
573// getIndexValue
574//
575//
576
577IOReturn
578IOLocalConfigDirectory::getIndexValue(int index, IOConfigDirectory *&value)
579{
580	IOReturn error = checkROMState();
581	if ( error )
582	{
583		return error ;
584	}
585
586	if( index < 0 || index >= fNumEntries )
587	{
588		return kIOReturnBadArgument;
589	}
590
591	{
592		lockData();
593
594		value = OSDynamicCast( IOConfigDirectory, ((IOConfigEntry*)fEntries->getObject( index ) )->fData ) ;
595
596		unlockData();
597
598		if ( value )
599		{
600			value->retain() ;
601		}
602		else
603		{
604			error = kIOReturnBadArgument ;
605		}
606
607	}
608
609	return error ;
610}
611
612void
613IOLocalConfigDirectory::exporterCleanup( const OSObject * self, IOFWUserObjectExporter * exporter )
614{
615	IOLocalConfigDirectory * me = (IOLocalConfigDirectory*)self;
616	((IOFireWireUserClient*)exporter->getOwner())->getOwner()->getBus()->RemoveUnitDirectory( me ) ;
617}
618