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 <IOKit/firewire/IOConfigDirectory.h>
25#import <IOKit/firewire/IORemoteConfigDirectory.h>
26#import <IOKit/firewire/IOFireWireDevice.h>
27
28// private
29#import "FWDebugging.h"
30#include "IOConfigDirectoryIterator.h"
31
32// system
33#import <libkern/c++/OSIterator.h>
34#import <libkern/c++/OSData.h>
35#import <libkern/OSByteOrder.h>
36
37static int findIndex(const UInt32* base, int size, int key,
38                     UInt32 type = kInvalidConfigROMEntryType);
39
40int findIndex(const UInt32* base, int size, int key, UInt32 type)
41{
42    int i;
43    UInt32 mask, test;
44    test = (UInt32)key << kConfigEntryKeyValuePhase;
45    mask = kConfigEntryKeyValue;
46    if(type != kInvalidConfigROMEntryType) {
47        test |= type << kConfigEntryKeyTypePhase;
48        mask |= kConfigEntryKeyType;
49    }
50    // OR test into mask, in case key was more than just the key value
51    mask |= test;
52    for(i=0; i<size; i++) {
53        if( (OSSwapBigToHostInt32(base[i]) & mask) == test )
54            break;
55    }
56    if(i >= size)
57        i = -1;
58    return i;
59}
60
61
62/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63
64OSDefineMetaClass( IOConfigDirectory, OSObject )
65OSDefineAbstractStructors(IOConfigDirectory, OSObject)
66OSMetaClassDefineReservedUnused(IOConfigDirectory, 0);
67OSMetaClassDefineReservedUnused(IOConfigDirectory, 1);
68OSMetaClassDefineReservedUnused(IOConfigDirectory, 2);
69OSMetaClassDefineReservedUnused(IOConfigDirectory, 3);
70OSMetaClassDefineReservedUnused(IOConfigDirectory, 4);
71OSMetaClassDefineReservedUnused(IOConfigDirectory, 5);
72OSMetaClassDefineReservedUnused(IOConfigDirectory, 6);
73OSMetaClassDefineReservedUnused(IOConfigDirectory, 7);
74OSMetaClassDefineReservedUnused(IOConfigDirectory, 8);
75
76// initWithOffset
77//
78//
79
80bool IOConfigDirectory::initWithOffset(int start, int type)
81{
82    IOReturn status = kIOReturnSuccess;
83    const UInt32 *data;
84
85    if( !OSObject::init() )
86	{
87        status = kIOReturnError;
88	}
89
90	if( status == kIOReturnSuccess )
91	{
92		fStart = start;
93		fType = type;
94
95		status = updateROMCache( start, 1 );
96	}
97
98	if( status == kIOReturnSuccess )
99	{
100		data = lockData();
101		fNumEntries = (OSSwapBigToHostInt32(data[start]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase;
102		unlockData();
103
104		if( fNumEntries > 256 ) // 1k request
105		{
106			status = kIOReturnNoMemory;
107		}
108	}
109
110	if( status == kIOReturnSuccess )
111	{
112	//	FWKLOG(( "IOConfigDirectory::initWithOffset updateROMCache( %d, %d )\n", start, fNumEntries ));
113		status = updateROMCache(start + 1, fNumEntries);
114	}
115
116	if( status != kIOReturnSuccess )
117	{
118		fNumEntries = 0;
119	}
120
121	return true;
122}
123
124// createIterator
125//
126//
127
128IOReturn IOConfigDirectory::createIterator(UInt32 testVal, UInt32 testMask, OSIterator *&iterator)
129{
130	IOReturn status = kIOReturnSuccess;
131
132    IOConfigDirectoryIterator *iter = NULL;
133
134	status = checkROMState();
135
136	if( status == kIOReturnSuccess )
137	{
138		iter = OSTypeAlloc( IOConfigDirectoryIterator );
139		if( iter == NULL )
140			status = kIOReturnNoMemory;
141	}
142
143	if( status == kIOReturnSuccess )
144	{
145		status = iter->init( this, testVal, testMask );
146		if( status == kIOReturnSuccess )
147		{
148			iterator = iter;
149		}
150		else
151		{
152			iter->release();
153			iter = NULL;
154		}
155	}
156
157	return status;
158}
159
160// getKeyType
161//
162//
163
164IOReturn IOConfigDirectory::getKeyType(int key, IOConfigKeyType &type)
165{
166	IOReturn status = kIOReturnSuccess;
167    int index = 0;
168
169	status = checkROMState();
170
171	if( status == kIOReturnSuccess )
172	{
173		const UInt32 * data = lockData() + fStart + 1;
174		index = findIndex(data, fNumEntries, key);
175		unlockData();
176
177		if( index < 0 )
178			status = kIOConfigNoEntry;
179	}
180
181	if( status == kIOReturnSuccess )
182	{
183		status = getIndexType(index, type);
184	}
185
186    return status;
187}
188
189// getKeyValue
190//
191//
192
193IOReturn IOConfigDirectory::getKeyValue(int key, UInt32 &value, OSString** text)
194{
195	IOReturn status = kIOReturnSuccess;
196    int index = 0;
197
198	status = checkROMState();
199
200	if( status == kIOReturnSuccess )
201	{
202		const UInt32 * data = lockData() + fStart + 1;
203		index = findIndex(data, fNumEntries, key);
204		unlockData();
205
206		if( index < 0 )
207        	status = kIOConfigNoEntry;
208	}
209
210	if( status == kIOReturnSuccess )
211	{
212		status = getIndexValue(index, value);
213    }
214
215	if( status == kIOReturnSuccess && text )
216	{
217		// textual descriptor is optional
218        *text = NULL;
219        status = getIndexValue(index+1, *text);
220		if( status != kIOFireWireConfigROMInvalid )
221			status = kIOReturnSuccess;
222    }
223
224    return status;
225}
226
227// getKeyValue
228//
229//
230
231IOReturn IOConfigDirectory::getKeyValue(int key, OSData *&value, OSString** text)
232{
233	IOReturn status = kIOReturnSuccess;
234    int index = 0;
235
236	status = checkROMState();
237
238	if( status == kIOReturnSuccess )
239	{
240		const UInt32 * data = lockData() + fStart + 1;
241		index = findIndex(data, fNumEntries, key, kConfigLeafKeyType);
242		unlockData();
243
244		if( index < 0 )
245		{
246			status = kIOConfigNoEntry;
247		}
248	}
249
250	if( status == kIOReturnSuccess )
251	{
252		status = getIndexValue(index, value);
253    }
254
255	if( status == kIOReturnSuccess && text )
256	{
257		// textual descriptor is optional
258        *text = NULL;
259        status = getIndexValue(index+1, *text);
260		if( status != kIOFireWireConfigROMInvalid )
261			status = kIOReturnSuccess;
262    }
263
264    return status;
265}
266
267// getKeyValue
268//
269//
270
271IOReturn IOConfigDirectory::getKeyValue(int key, IOConfigDirectory *&value,
272                                                        OSString** text)
273{
274	IOReturn status = kIOReturnSuccess;
275    int index = 0;
276
277	status = checkROMState();
278
279	if( status == kIOReturnSuccess )
280	{
281		const UInt32 * data = lockData() + fStart + 1;
282		index = findIndex(data, fNumEntries, key, kConfigDirectoryKeyType);
283		unlockData();
284
285		if( index < 0 )
286		{
287			status = kIOConfigNoEntry;
288		}
289	}
290
291	if( status == kIOReturnSuccess )
292	{
293		status = getIndexValue(index, value);
294    }
295
296	if( status == kIOReturnSuccess && text )
297	{
298		// textual descriptor is optional
299        *text = NULL;
300        status = getIndexValue(index+1, *text);
301		if( status != kIOFireWireConfigROMInvalid )
302			status = kIOReturnSuccess;
303    }
304
305    return status;
306}
307
308// getKeyOffset
309//
310//
311
312IOReturn IOConfigDirectory::getKeyOffset(int key, FWAddress &value, OSString** text)
313{
314	IOReturn status = kIOReturnSuccess;
315    int index = 0;
316
317	status = checkROMState();
318
319	if( status == kIOReturnSuccess )
320	{
321		const UInt32 * data = lockData() + fStart + 1;
322		index = findIndex(data, fNumEntries, key, kConfigOffsetKeyType);
323		unlockData();
324
325		if( index < 0 )
326        	status = kIOConfigNoEntry;
327	}
328
329	if( status == kIOReturnSuccess )
330	{
331		status = getIndexOffset(index, value);
332    }
333
334	if( status == kIOReturnSuccess && text)
335	{
336		// textual descriptor is optional
337        *text = NULL;
338        status = getIndexValue(index+1, *text);
339		if( status != kIOFireWireConfigROMInvalid )
340			status = kIOReturnSuccess;
341	}
342
343	return status;
344}
345
346// getKeySubdirectories
347//
348//
349
350IOReturn IOConfigDirectory::getKeySubdirectories(int key, OSIterator *&iterator)
351{
352    IOReturn status = createIterator((key << kConfigEntryKeyValuePhase) |
353							(kConfigDirectoryKeyType << kConfigEntryKeyTypePhase),
354								kConfigEntryKeyType | kConfigEntryKeyValue, iterator);
355
356	return status;
357}
358
359// getType
360//
361//
362
363int IOConfigDirectory::getType() const
364{
365	return fType;
366}
367
368// getNumEntries
369//
370//
371
372int IOConfigDirectory::getNumEntries() const
373{
374	return fNumEntries;
375}
376
377// getIndexType
378//
379//
380
381IOReturn IOConfigDirectory::getIndexType(int index, IOConfigKeyType &type)
382{
383	IOReturn status = kIOReturnSuccess;
384    UInt32 entry;
385
386	status = checkROMState();
387
388	if( status == kIOReturnSuccess )
389	{
390		if( index < 0 || index >= fNumEntries )
391			status = kIOReturnBadArgument;
392	}
393
394	if( status == kIOReturnSuccess )
395	{
396		const UInt32 * data = lockData();
397		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
398		unlockData();
399
400		type = (IOConfigKeyType)((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase);
401    }
402
403	return status;
404}
405
406// getIndexKey
407//
408//
409
410IOReturn IOConfigDirectory::getIndexKey(int index, int &key)
411{
412	IOReturn status = kIOReturnSuccess;
413    UInt32 entry;
414
415	status = checkROMState();
416
417	if( status == kIOReturnSuccess )
418	{
419		if( index < 0 || index >= fNumEntries )
420			status = kIOReturnBadArgument;
421	}
422
423	if( status == kIOReturnSuccess )
424	{
425		const UInt32 * data = lockData();
426		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
427		unlockData();
428
429		key = (IOConfigKeyType)((entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase);
430	}
431
432    return status;
433}
434
435// getIndexValue
436//
437//
438
439IOReturn IOConfigDirectory::getIndexValue(int index, UInt32 &value)
440{
441	IOReturn status = kIOReturnSuccess;
442    UInt32 entry;
443
444	status = checkROMState();
445
446	if( status == kIOReturnSuccess )
447	{
448		if( index < 0 || index >= fNumEntries )
449			status = kIOReturnBadArgument;
450	}
451
452	if( status == kIOReturnSuccess )
453	{
454		const UInt32 * data = lockData();
455		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
456		unlockData();
457
458		// Return the value as an integer, whatever it really is.
459		value = entry & kConfigEntryValue;
460    }
461
462	return status;
463}
464
465// getIndexValue
466//
467//
468
469IOReturn IOConfigDirectory::getIndexValue(int index, OSData *&value)
470{
471	IOReturn status = kIOReturnSuccess;
472    UInt32 entry;
473    const UInt32 *data;
474    UInt32 offset;
475    int len = 0;
476
477	status = checkROMState();
478
479	if( status == kIOReturnSuccess )
480	{
481		if( index < 0 || index >= fNumEntries )
482			status = kIOReturnBadArgument;
483	}
484
485	if( status == kIOReturnSuccess )
486	{
487		data = lockData();
488		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
489		unlockData();
490
491		if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigLeafKeyType)
492			status = kIOReturnBadArgument;
493	}
494
495	if( status == kIOReturnSuccess )
496	{
497		status = getIndexOffset( index, offset );
498	}
499
500	if( status == kIOReturnSuccess )
501	{
502		status = updateROMCache( offset, 1 );
503	}
504
505	if( status == kIOReturnSuccess )
506	{
507		data = lockData();
508		len = ((OSSwapBigToHostInt32(data[offset]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase);
509		unlockData();
510
511	//	FWKLOG(( "IOConfigDirectory::getIndexValue(OSData) updateROMCache( %ld, %d )\n", offset, len ));
512
513		status = updateROMCache( offset + 1, len );
514    }
515
516	if( status == kIOReturnSuccess )
517	{
518		data = lockData();
519		value = OSData::withBytes(data+offset+1, len*sizeof(UInt32));
520		unlockData();
521
522		if( value == NULL)
523			status = kIOReturnNoMemory;
524	}
525
526    return status;
527}
528
529// getIndexValue
530//
531//
532
533IOReturn IOConfigDirectory::getIndexValue(int index, OSString *&value)
534{
535	IOReturn status = kIOReturnSuccess;
536    UInt32 entry = 0;
537    const UInt32 *data;
538    UInt32 offset;
539    int len = 0;
540
541	status = checkROMState();
542
543	if( status == kIOReturnSuccess )
544	{
545		if( index < 0 || index >= fNumEntries )
546		{
547			DebugLog("IOConfigDirectory<%p>::getIndexValue -- index out of bounds\n", this ) ;
548			status = kIOReturnBadArgument;
549		}
550	}
551
552	if( status == kIOReturnSuccess )
553	{
554		data = lockData();
555		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
556		unlockData();
557
558		if( ((entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase) != kConfigTextualDescriptorKey )
559		{
560			DebugLog("IOConfigDirectory<%p>::getIndexValue -- key is not a textual descriptor key entry=0x%x\n", this, (uint32_t)entry ) ;
561			status = kIOReturnBadArgument;
562		}
563	}
564
565	if( status == kIOReturnSuccess )
566	{
567		if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigLeafKeyType )
568		{
569			DebugLog("IOConfigDirectory<%p>::getIndexValue -- key type is not leaf\n", this ) ;
570			status = kIOReturnBadArgument;
571		}
572	}
573
574	if( status == kIOReturnSuccess )
575	{
576		status = getIndexOffset(index, offset);
577	}
578
579	if( status == kIOReturnSuccess )
580	{
581		status = updateROMCache(offset, 1);
582	}
583
584	if( status == kIOReturnSuccess )
585	{
586		data = lockData();
587		len = (OSSwapBigToHostInt32(data[offset]) & kConfigLeafDirLength) >> kConfigLeafDirLengthPhase;
588		unlockData();
589
590		// Check for silly length, people are careless with string data!
591		if( (len * 4) > 256 )
592        	status = kIOReturnBadArgument;
593	}
594
595	if( status == kIOReturnSuccess )
596	{
597		FWKLOG(( "IOConfigDirectory::getIndexValue(OSString) updateROMCache( %ld, %d )\n", offset, len ));
598
599    	status = updateROMCache(offset + 1,len);
600	}
601
602	if( status == kIOReturnSuccess )
603	{
604		data = lockData();
605
606		len -= 2;	// skip spec_type, specifier_ID, language_ID
607		len *= sizeof(UInt32);	// Convert from Quads to chars
608
609		char tbuf[len];
610		char * text;
611
612		UInt32 specifier = OSSwapBigToHostInt32(data[offset+1]);
613		//UInt32 specifier_ID = specifier & 0x00FFFFFF;
614		UInt8 specifier_type = (UInt8)(specifier >> 24);	//descriptor_type
615		UInt32 language_ID = OSSwapBigToHostInt32(data[offset+2]) & 0x0000FFFF;
616
617		if ( specifier_type == 0x80 && language_ID == 0x409 )
618		{
619			// Decode using vendor specific UTF-16 simple conversion
620			char * aUniStr = (char *)(&data[offset+3]);
621			const unsigned int halfsize = len/2;
622			unsigned int i;
623			for ( i=0; i < halfsize; i++ )
624				tbuf[i] = aUniStr[i*2];
625
626			text = (char *)tbuf;
627			len = halfsize;
628		}
629		else
630		{
631			// Skip over length, CRC, spec_type, specifier_ID, language_ID
632			text = (char *)(&data[offset+3]);
633		}
634
635		// Now skip over leading zeros in string
636		while(len && !*text) {
637			len--;
638			text++;
639		}
640
641		if(len)
642		{
643			// strings aren't required to have null terminators
644			// add one just in case
645			char * temp_string = (char *)IOMalloc( len+1 );
646			if( temp_string )
647			{
648				bcopy( text, temp_string, len );
649				temp_string[len] = '\0';
650				value = OSString::withCString(temp_string);
651				IOFree( temp_string, len+1 );
652			}
653		}
654		else
655			value = OSString::withCString("");
656
657		unlockData();
658
659		if( value == NULL )
660			status = kIOReturnNoMemory;
661	}
662
663	DebugLogCond( status != kIOReturnSuccess, "IOConfigDirectory<%p>::getIndexValue -- return status 0x%x\n", this, status ) ;
664
665	return status;
666}
667
668// getIndexValue
669//
670//
671
672IOReturn IOConfigDirectory::getIndexValue(int index, IOConfigDirectory *&value)
673{
674	IOReturn status = kIOReturnSuccess;
675    UInt32 entry = 0;
676    UInt32 offset;
677
678	status = checkROMState();
679
680	if( status == kIOReturnSuccess )
681	{
682		if( index < 0 || index >= fNumEntries )
683			status = kIOReturnBadArgument;
684	}
685
686	if( status == kIOReturnSuccess )
687	{
688		const UInt32 * data = lockData();
689		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
690		unlockData();
691
692		if( ((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) != kConfigDirectoryKeyType)
693			status = kIOReturnBadArgument;
694	}
695
696	if( status == kIOReturnSuccess )
697	{
698		status = getIndexOffset(index, offset);
699	}
700
701	if( status == kIOReturnSuccess )
702	{
703		value = getSubDir( offset, (entry & kConfigEntryKeyValue) >> kConfigEntryKeyValuePhase );
704		if( value == NULL )
705			status = kIOReturnNoMemory;
706	}
707
708	return status;
709}
710
711// getIndexOffset
712//
713//
714
715IOReturn IOConfigDirectory::getIndexOffset(int index, FWAddress &value)
716{
717	IOReturn status = kIOReturnSuccess;
718    UInt32 entry = 0;
719    UInt32 offset;
720
721	status = checkROMState();
722
723	if( status == kIOReturnSuccess )
724	{
725		if( index < 0 || index >= fNumEntries )
726			status = kIOReturnBadArgument;
727	}
728
729	if( status == kIOReturnSuccess )
730	{
731		const UInt32 * data = lockData();
732		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
733		unlockData();
734
735		if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigImmediateKeyType)
736        	status = kIOReturnBadArgument;
737	}
738
739	if( status == kIOReturnSuccess )
740	{
741		value.addressHi = kCSRRegisterSpaceBaseAddressHi;
742		offset = entry & kConfigEntryValue;
743		if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigOffsetKeyType)
744		{
745			value.addressLo = kCSRRegisterSpaceBaseAddressLo + offset*sizeof(UInt32);
746		}
747		else
748		{
749			offset += fStart + 1 + index;
750			value.addressLo = kConfigROMBaseAddress + offset*sizeof(UInt32);
751		}
752	}
753
754    return status;
755}
756
757// getIndexOffset
758//
759//
760
761IOReturn IOConfigDirectory::getIndexOffset(int index, UInt32 &value)
762{
763	IOReturn status = kIOReturnSuccess;
764    UInt32 entry = 0;
765
766	status = checkROMState();
767
768	if( status == kIOReturnSuccess )
769	{
770		if( index < 0 || index >= fNumEntries )
771			status = kIOReturnBadArgument;
772	}
773
774	if( status == kIOReturnSuccess )
775	{
776		const UInt32 * data = lockData();
777		entry = OSSwapBigToHostInt32(data[fStart + 1 + index]);
778		unlockData();
779
780		if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigImmediateKeyType)
781		{
782			status = kIOReturnBadArgument;
783		}
784		else if(((entry & kConfigEntryKeyType) >> kConfigEntryKeyTypePhase) == kConfigOffsetKeyType)
785		{
786			status = kIOReturnBadArgument;
787		}
788	}
789
790	if( status == kIOReturnSuccess )
791	{
792		value = entry & kConfigEntryValue;
793		value += fStart + 1 + index;
794	}
795
796    return status;
797}
798
799// getIndexEntry
800//
801//
802
803IOReturn IOConfigDirectory::getIndexEntry(int index, UInt32 &value)
804{
805	IOReturn status = kIOReturnSuccess;
806
807	status = checkROMState();
808
809	if( status == kIOReturnSuccess )
810	{
811		if( index < 0 || index >= fNumEntries )
812			status = kIOReturnBadArgument;
813	}
814
815	if( status == kIOReturnSuccess )
816	{
817		const UInt32 * data = lockData();
818		value = OSSwapBigToHostInt32(data[fStart + 1 + index]);
819		unlockData();
820	}
821
822    return status;
823}
824
825// getSubdirectories
826//
827//
828
829IOReturn IOConfigDirectory::getSubdirectories(OSIterator *&iterator)
830{
831    return createIterator(kConfigDirectoryKeyType << kConfigEntryKeyTypePhase,
832                          kConfigEntryKeyType, iterator);
833}
834
835