]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPlatformExpert.cpp
xnu-792.6.70.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
1c79356b 11 *
37839358
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * HISTORY
24 */
25
1c79356b
A
26#include <IOKit/IOCPU.h>
27#include <IOKit/IODeviceTreeSupport.h>
de355530 28#include <IOKit/IOKitDebug.h>
55e303ae
A
29#include <IOKit/IOMapper.h>
30#include <IOKit/IOMessage.h>
31#include <IOKit/IONVRAM.h>
32#include <IOKit/IOPlatformExpert.h>
33#include <IOKit/IORangeAllocator.h>
1c79356b
A
34#include <IOKit/IOWorkLoop.h>
35#include <IOKit/pwr_mgt/RootDomain.h>
55e303ae 36#include <IOKit/IOKitKeys.h>
91447636 37#include <IOKit/IOTimeStamp.h>
55e303ae
A
38
39#include <IOKit/system.h>
40
1c79356b
A
41#include <libkern/c++/OSContainers.h>
42
1c79356b
A
43extern "C" {
44#include <machine/machine_routines.h>
45#include <pexpert/pexpert.h>
46}
47
48void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg);
49static void getCStringForObject (OSObject * inObj, char * outStr);
50
51/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52
53#define super IOService
54
55OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
56
9bccf70c
A
57OSMetaClassDefineReservedUsed(IOPlatformExpert, 0);
58
55e303ae 59OSMetaClassDefineReservedUsed(IOPlatformExpert, 1);
1c79356b
A
60OSMetaClassDefineReservedUnused(IOPlatformExpert, 2);
61OSMetaClassDefineReservedUnused(IOPlatformExpert, 3);
62OSMetaClassDefineReservedUnused(IOPlatformExpert, 4);
63OSMetaClassDefineReservedUnused(IOPlatformExpert, 5);
64OSMetaClassDefineReservedUnused(IOPlatformExpert, 6);
65OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
66OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
67OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
68OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
69OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
70
71static IOPlatformExpert * gIOPlatform;
fa4905b1
A
72static OSDictionary * gIOInterruptControllers;
73static IOLock * gIOInterruptControllersLock;
1c79356b
A
74
75OSSymbol * gPlatformInterruptControllerName;
76
77/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
78
79bool IOPlatformExpert::attach( IOService * provider )
80{
81
82 if( !super::attach( provider ))
83 return( false);
84
85 return( true);
86}
87
88bool IOPlatformExpert::start( IOService * provider )
89{
90 IORangeAllocator * physicalRanges;
91 OSData * busFrequency;
3a60a9f5 92 uint32_t debugFlags;
1c79356b
A
93
94 if (!super::start(provider))
95 return false;
3a60a9f5
A
96
97 // Override the mapper present flag is requested by boot arguments.
98 if (PE_parse_boot_arg("dart", &debugFlags) && (debugFlags == 0))
99 removeProperty(kIOPlatformMapperPresentKey);
100
55e303ae
A
101 // Register the presence or lack thereof a system
102 // PCI address mapper with the IOMapper class
55e303ae 103 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey));
1c79356b 104
fa4905b1
A
105 gIOInterruptControllers = OSDictionary::withCapacity(1);
106 gIOInterruptControllersLock = IOLockAlloc();
107
1c79356b
A
108 // Correct the bus frequency in the device tree.
109 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
110 provider->setProperty("clock-frequency", busFrequency);
111 busFrequency->release();
112
113 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
114
115 physicalRanges = IORangeAllocator::withRange(0xffffffff, 1, 16,
116 IORangeAllocator::kLocking);
117 assert(physicalRanges);
118 setProperty("Platform Memory Ranges", physicalRanges);
119
120 setPlatform( this );
121 gIOPlatform = this;
122
123 PMInstantiatePowerDomains();
124
55e303ae
A
125 // Parse the serial-number data and publish a user-readable string
126 OSData* mydata = (OSData*) (provider->getProperty("serial-number"));
127 if (mydata != NULL) {
128 OSString *serNoString = createSystemSerialNumberString(mydata);
129 if (serNoString != NULL) {
130 provider->setProperty(kIOPlatformSerialNumberKey, serNoString);
131 serNoString->release();
132 }
133 }
134
1c79356b
A
135 return( configure(provider) );
136}
137
138bool IOPlatformExpert::configure( IOService * provider )
139{
140 OSSet * topLevel;
141 OSDictionary * dict;
142 IOService * nub;
143
144 topLevel = OSDynamicCast( OSSet, getProperty("top-level"));
145
146 if( topLevel) {
147 while( (dict = OSDynamicCast( OSDictionary,
148 topLevel->getAnyObject()))) {
149 dict->retain();
150 topLevel->removeObject( dict );
151 nub = createNub( dict );
152 if( 0 == nub)
153 continue;
154 dict->release();
155 nub->attach( this );
156 nub->registerService();
157 }
158 }
159
160 return( true );
161}
162
163IOService * IOPlatformExpert::createNub( OSDictionary * from )
164{
165 IOService * nub;
166
167 nub = new IOPlatformDevice;
168 if(nub) {
169 if( !nub->init( from )) {
170 nub->release();
171 nub = 0;
172 }
173 }
174 return( nub);
175}
176
177bool IOPlatformExpert::compareNubName( const IOService * nub,
55e303ae 178 OSString * name, OSString ** matched ) const
1c79356b
A
179{
180 return( nub->IORegistryEntry::compareName( name, matched ));
181}
182
183IOReturn IOPlatformExpert::getNubResources( IOService * nub )
184{
185 return( kIOReturnSuccess );
186}
187
188long IOPlatformExpert::getBootROMType(void)
189{
190 return _peBootROMType;
191}
192
193long IOPlatformExpert::getChipSetType(void)
194{
195 return _peChipSetType;
196}
197
198long IOPlatformExpert::getMachineType(void)
199{
200 return _peMachineType;
201}
202
203void IOPlatformExpert::setBootROMType(long peBootROMType)
204{
205 _peBootROMType = peBootROMType;
206}
207
208void IOPlatformExpert::setChipSetType(long peChipSetType)
209{
210 _peChipSetType = peChipSetType;
211}
212
213void IOPlatformExpert::setMachineType(long peMachineType)
214{
215 _peMachineType = peMachineType;
216}
217
218bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
219{
220 return( false );
221}
222
223bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
224{
225 return( false );
226}
227
55e303ae
A
228OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
229{
230 return NULL;
231}
232
1c79356b
A
233IORangeAllocator * IOPlatformExpert::getPhysicalRangeAllocator(void)
234{
235 return(OSDynamicCast(IORangeAllocator,
236 getProperty("Platform Memory Ranges")));
237}
238
239int (*PE_halt_restart)(unsigned int type) = 0;
240
241int IOPlatformExpert::haltRestart(unsigned int type)
242{
4a249263
A
243 IOPMrootDomain *rd = getPMRootDomain();
244 OSBoolean *b = 0;
245
246 if(rd) b = (OSBoolean *)OSDynamicCast(OSBoolean, rd->getProperty(OSString::withCString("StallSystemAtHalt")));
247
9bccf70c 248 if (type == kPEHangCPU) while (1);
4a249263
A
249
250 if (kOSBooleanTrue == b) {
251 // Stall shutdown for 5 minutes, and if no outside force has removed our power, continue with
252 // a reboot.
253 IOSleep(1000*60*5);
254 type = kPERestartCPU;
255 }
9bccf70c 256
1c79356b
A
257 if (PE_halt_restart) return (*PE_halt_restart)(type);
258 else return -1;
259}
260
261void IOPlatformExpert::sleepKernel(void)
262{
263#if 0
264 long cnt;
265 boolean_t intState;
266
267 intState = ml_set_interrupts_enabled(false);
268
269 for (cnt = 0; cnt < 10000; cnt++) {
270 IODelay(1000);
271 }
272
273 ml_set_interrupts_enabled(intState);
274#else
275// PE_initialize_console(0, kPEDisableScreen);
276
277 IOCPUSleepKernel();
278
279// PE_initialize_console(0, kPEEnableScreen);
280#endif
281}
282
283long IOPlatformExpert::getGMTTimeOfDay(void)
284{
285 return(0);
286}
287
288void IOPlatformExpert::setGMTTimeOfDay(long secs)
289{
290}
291
292
293IOReturn IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
294{
295 return( PE_current_console( consoleInfo));
296}
297
298IOReturn IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
299 unsigned int op)
300{
301 return( PE_initialize_console( consoleInfo, op ));
302}
303
304IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController)
305{
fa4905b1
A
306 IOLockLock(gIOInterruptControllersLock);
307
308 gIOInterruptControllers->setObject(name, interruptController);
309
9bccf70c
A
310 IOLockWakeup(gIOInterruptControllersLock,
311 gIOInterruptControllers, /* one-thread */ false);
312
fa4905b1 313 IOLockUnlock(gIOInterruptControllersLock);
1c79356b
A
314
315 return kIOReturnSuccess;
316}
317
318IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *name)
319{
fa4905b1 320 OSObject *object;
1c79356b 321
9bccf70c 322 IOLockLock(gIOInterruptControllersLock);
fa4905b1 323 while (1) {
fa4905b1
A
324
325 object = gIOInterruptControllers->getObject(name);
326
9bccf70c
A
327 if (object != 0)
328 break;
fa4905b1 329
9bccf70c
A
330 IOLockSleep(gIOInterruptControllersLock,
331 gIOInterruptControllers, THREAD_UNINT);
fa4905b1 332 }
1c79356b 333
9bccf70c 334 IOLockUnlock(gIOInterruptControllersLock);
fa4905b1 335 return OSDynamicCast(IOInterruptController, object);
1c79356b
A
336}
337
338
339void IOPlatformExpert::setCPUInterruptProperties(IOService *service)
340{
341 IOCPUInterruptController *controller;
342
343 controller = OSDynamicCast(IOCPUInterruptController, waitForService(serviceMatching("IOCPUInterruptController")));
344 if (controller) controller->setCPUInterruptProperties(service);
345}
346
347bool IOPlatformExpert::atInterruptLevel(void)
348{
349 return ml_at_interrupt_context();
350}
351
352bool IOPlatformExpert::platformAdjustService(IOService */*service*/)
353{
354 return true;
355}
356
357
358//*********************************************************************************
359// PMLog
360//
361//*********************************************************************************
362
91447636
A
363void IOPlatformExpert::
364PMLog(const char *who, unsigned long event,
365 unsigned long param1, unsigned long param2)
1c79356b 366{
91447636
A
367 UInt32 debugFlags = gIOKitDebug;
368
369 if (debugFlags & kIOLogPower) {
370
371 uint32_t nows, nowus;
372 clock_get_system_microtime(&nows, &nowus);
373 nowus += (nows % 1000) * 1000000;
374
375 kprintf("pm%u %x %.30s %d %x %x\n",
376 nowus, (unsigned) current_thread(), who, // Identity
377 (int) event, param1, param2); // Args
378
379 if (debugFlags & kIOLogTracePower) {
380 static const UInt32 sStartStopBitField[] =
381 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
382
383 // Arcane formula from Hacker's Delight by Warren
384 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
385 UInt32 sgnevent = ((long) event >> 31);
386 UInt32 absevent = sgnevent ^ (event + sgnevent);
387 UInt32 code = IODBG_POWER(absevent);
388
389 UInt32 bit = 1 << (absevent & 0x1f);
390 if (absevent < sizeof(sStartStopBitField) * 8
391 && (sStartStopBitField[absevent >> 5] & bit) ) {
392 // Or in the START or END bits, Start = 1 & END = 2
393 // If sgnevent == 0 then START - 0 => START
394 // else if sgnevent == -1 then START - -1 => END
395 code |= DBG_FUNC_START - sgnevent;
396 }
397
398 // Record the timestamp, wish I had a this pointer
399 IOTimeStampConstant(code, (UInt32) who, event, param1, param2);
400 }
1c79356b
A
401 }
402}
403
404
405//*********************************************************************************
406// PMInstantiatePowerDomains
407//
408// In this vanilla implementation, a Root Power Domain is instantiated.
409// All other objects which register will be children of this Root.
410// Where this is inappropriate, PMInstantiatePowerDomains is overridden
411// in a platform-specific subclass.
412//*********************************************************************************
413
414void IOPlatformExpert::PMInstantiatePowerDomains ( void )
415{
416 root = new IOPMrootDomain;
417 root->init();
418 root->attach(this);
419 root->start(this);
420 root->youAreRoot();
421}
422
423
424//*********************************************************************************
425// PMRegisterDevice
426//
427// In this vanilla implementation, all callers are made children of the root power domain.
428// Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
429//*********************************************************************************
430
431void IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
432{
433 root->addPowerChild ( theDevice );
434}
435
436//*********************************************************************************
437// hasPMFeature
438//
439//*********************************************************************************
440
441bool IOPlatformExpert::hasPMFeature (unsigned long featureMask)
442{
443 return ((_pePMFeatures & featureMask) != 0);
444}
445
446//*********************************************************************************
447// hasPrivPMFeature
448//
449//*********************************************************************************
450
451bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask)
452{
453 return ((_pePrivPMFeatures & privFeatureMask) != 0);
454}
455
456//*********************************************************************************
457// numBatteriesSupported
458//
459//*********************************************************************************
460
461int IOPlatformExpert::numBatteriesSupported (void)
462{
463 return (_peNumBatteriesSupported);
464}
465
466//*********************************************************************************
467// CheckSubTree
468//
469// This method is called by the instantiated sublass of the platform expert to
470// determine how a device should be inserted into the Power Domain. The subclass
471// provides an XML power tree description against which a device is matched based
472// on class and provider. If a match is found this routine returns true in addition
473// to flagging the description tree at the appropriate node that a device has been
474// registered for the given service.
475//*********************************************************************************
476
477bool IOPlatformExpert::CheckSubTree (OSArray * inSubTree, IOService * theNub, IOService * theDevice, OSDictionary * theParent)
478{
479 unsigned int i;
480 unsigned int numPowerTreeNodes;
481 OSDictionary * entry;
482 OSDictionary * matchingDictionary;
483 OSDictionary * providerDictionary;
484 OSDictionary * deviceDictionary;
485 OSDictionary * nubDictionary;
486 OSArray * children;
487 bool nodeFound = false;
488 bool continueSearch = false;
489 bool deviceMatch = false;
490 bool providerMatch = false;
491 bool multiParentMatch = false;
492
493 if ( (NULL == theDevice) || (NULL == inSubTree) )
494 return false;
495
496 numPowerTreeNodes = inSubTree->getCount ();
497
498 // iterate through the power tree to find a home for this device
499
500 for ( i = 0; i < numPowerTreeNodes; i++ ) {
501
502 entry = (OSDictionary *) inSubTree->getObject (i);
503
504 matchingDictionary = (OSDictionary *) entry->getObject ("device");
505 providerDictionary = (OSDictionary *) entry->getObject ("provider");
506
507 deviceMatch = true; // if no matching dictionary, this is not a criteria and so must match
508 if ( matchingDictionary ) {
509 deviceMatch = false;
510 if ( NULL != (deviceDictionary = theDevice->dictionaryWithProperties ())) {
511 deviceMatch = deviceDictionary->isEqualTo ( matchingDictionary, matchingDictionary );
512 deviceDictionary->release ();
513 }
514 }
515
516 providerMatch = true; // we indicate a match if there is no nub or provider
517 if ( theNub && providerDictionary ) {
518 providerMatch = false;
519 if ( NULL != (nubDictionary = theNub->dictionaryWithProperties ()) ) {
520 providerMatch = nubDictionary->isEqualTo ( providerDictionary, providerDictionary );
521 nubDictionary->release ();
522 }
523 }
524
525 multiParentMatch = true; // again we indicate a match if there is no multi-parent node
526 if (deviceMatch && providerMatch) {
527 if (NULL != multipleParentKeyValue) {
528 OSNumber * aNumber = (OSNumber *) entry->getObject ("multiple-parent");
529 multiParentMatch = (NULL != aNumber) ? multipleParentKeyValue->isEqualTo (aNumber) : false;
530 }
531 }
532
533 nodeFound = (deviceMatch && providerMatch && multiParentMatch);
534
535 // if the power tree specifies a provider dictionary but theNub is
536 // NULL then we cannot match with this entry.
537
538 if ( theNub == NULL && providerDictionary != NULL )
539 nodeFound = false;
540
541 // if this node is THE ONE...then register the device
542
543 if ( nodeFound ) {
544 if (RegisterServiceInTree (theDevice, entry, theParent, theNub) ) {
545
546 if ( kIOLogPower & gIOKitDebug)
547 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
548
549 numInstancesRegistered++;
550
551 // determine if we need to search for additional nodes for this item
552 multipleParentKeyValue = (OSNumber *) entry->getObject ("multiple-parent");
553 }
554 else
555 nodeFound = false;
556 }
557
558 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
559
560 if ( continueSearch && (NULL != (children = (OSArray *) entry->getObject ("children"))) ) {
561 nodeFound = CheckSubTree ( children, theNub, theDevice, entry );
562 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
563 }
564
565 if ( false == continueSearch )
566 break;
567 }
568
569 return ( nodeFound );
570}
571
572//*********************************************************************************
573// RegisterServiceInTree
574//
575// Register a device at the specified node of our power tree.
576//*********************************************************************************
577
578bool IOPlatformExpert::RegisterServiceInTree (IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider)
579{
580 IOService * aService;
581 bool registered = false;
582 OSArray * children;
583 unsigned int numChildren;
584 OSDictionary * child;
585
586 // make sure someone is not already registered here
587
588 if ( NULL == theTreeNode->getObject ("service") ) {
589
590 if ( theTreeNode->setObject ("service", OSDynamicCast ( OSObject, theService)) ) {
591
592 // 1. CHILDREN ------------------
593
594 // we registered the node in the tree...now if the node has children
595 // registered we must tell this service to add them.
596
597 if ( NULL != (children = (OSArray *) theTreeNode->getObject ("children")) ) {
598 numChildren = children->getCount ();
599 for ( unsigned int i = 0; i < numChildren; i++ ) {
600 if ( NULL != (child = (OSDictionary *) children->getObject (i)) ) {
601 if ( NULL != (aService = (IOService *) child->getObject ("service")) )
602 theService->addPowerChild (aService);
603 }
604 }
605 }
606
607 // 2. PARENT --------------------
608
609 // also we must notify the parent of this node (if a registered service
610 // exists there) of a new child.
611
612 if ( theTreeParentNode ) {
613 if ( NULL != (aService = (IOService *) theTreeParentNode->getObject ("service")) )
614 if (aService != theProvider)
615 aService->addPowerChild (theService);
616 }
617
618 registered = true;
619 }
620 }
621
622 return registered;
623}
624
625//*********************************************************************************
626// printDictionaryKeys
627//
628// Print the keys for the given dictionary and selected contents.
629//*********************************************************************************
630void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg)
631{
632 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection (inDictionary);
633 OSSymbol * mkey;
634 OSString * ioClass;
635 unsigned int i = 0;
636
637 mcoll->reset ();
638
639 mkey = OSDynamicCast (OSSymbol, mcoll->getNextObject ());
640
641 while (mkey) {
642
643 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
644
645 // if this is the IOClass key, print it's contents
646
647 if ( mkey->isEqualTo ("IOClass") ) {
648 ioClass = (OSString *) inDictionary->getObject ("IOClass");
649 if ( ioClass ) IOLog ("%s IOClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
650 }
651
652 // if this is an IOProviderClass key print it
653
654 if ( mkey->isEqualTo ("IOProviderClass") ) {
655 ioClass = (OSString *) inDictionary->getObject ("IOProviderClass");
656 if ( ioClass ) IOLog ("%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
657
658 }
659
660 // also print IONameMatch keys
661 if ( mkey->isEqualTo ("IONameMatch") ) {
662 ioClass = (OSString *) inDictionary->getObject ("IONameMatch");
663 if ( ioClass ) IOLog ("%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy () );
664 }
665
666 // also print IONameMatched keys
667
668 if ( mkey->isEqualTo ("IONameMatched") ) {
669 ioClass = (OSString *) inDictionary->getObject ("IONameMatched");
670 if ( ioClass ) IOLog ("%s IONameMatched is %s\n", inMsg, ioClass->getCStringNoCopy () );
671 }
672
673#if 0
674 // print clock-id
675
676 if ( mkey->isEqualTo ("AAPL,clock-id") ) {
677 char * cstr;
678 cstr = getCStringForObject (inDictionary->getObject ("AAPL,clock-id"));
679 if (cstr)
680 kprintf (" ===> AAPL,clock-id is %s\n", cstr );
681 }
682#endif
683
684 // print name
685
686 if ( mkey->isEqualTo ("name") ) {
687 char nameStr[64];
688 nameStr[0] = 0;
689 getCStringForObject (inDictionary->getObject ("name"), nameStr );
690 if (strlen(nameStr) > 0)
691 IOLog ("%s name is %s\n", inMsg, nameStr);
692 }
693
694 mkey = (OSSymbol *) mcoll->getNextObject ();
695
696 i++;
697 }
698
699 mcoll->release ();
700}
701
702static void getCStringForObject (OSObject * inObj, char * outStr)
703{
704 char * buffer;
705 unsigned int len, i;
706
707 if ( (NULL == inObj) || (NULL == outStr))
708 return;
709
710 char * objString = (char *) (inObj->getMetaClass())->getClassName();
711
712 if ((0 == strcmp(objString,"OSString")) || (0 == strcmp (objString, "OSSymbol")))
713 strcpy (outStr, ((OSString *)inObj)->getCStringNoCopy());
714
715 else if (0 == strcmp(objString,"OSData")) {
716 len = ((OSData *)inObj)->getLength();
717 buffer = (char *)((OSData *)inObj)->getBytesNoCopy();
718 if (buffer && (len > 0)) {
719 for (i=0; i < len; i++) {
720 outStr[i] = buffer[i];
721 }
722 outStr[len] = 0;
723 }
724 }
725}
726
fa4905b1
A
727/* IOPMPanicOnShutdownHang
728 * - Called from a timer installed by PEHaltRestart
729 */
730static void IOPMPanicOnShutdownHang(thread_call_param_t p0, thread_call_param_t p1)
731{
732 int type = (int)p0;
733
734 /* 30 seconds has elapsed - resume shutdown */
735 gIOPlatform->haltRestart(type);
736}
737
738
1c79356b
A
739extern "C" {
740
741/*
742 * Callouts from BSD for machine name & model
743 */
744
745boolean_t PEGetMachineName( char * name, int maxLength )
746{
747 if( gIOPlatform)
748 return( gIOPlatform->getMachineName( name, maxLength ));
749 else
750 return( false );
751}
752
753boolean_t PEGetModelName( char * name, int maxLength )
754{
755 if( gIOPlatform)
756 return( gIOPlatform->getModelName( name, maxLength ));
757 else
758 return( false );
759}
760
761int PEGetPlatformEpoch(void)
762{
763 if( gIOPlatform)
764 return( gIOPlatform->getBootROMType());
765 else
766 return( -1 );
767}
768
769int PEHaltRestart(unsigned int type)
770{
fa4905b1
A
771 IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain();
772 bool noWaitForResponses;
773 AbsoluteTime deadline;
774 thread_call_t shutdown_hang;
775
9bccf70c
A
776 if(type == kPEHaltCPU || type == kPERestartCPU)
777 {
778 /* Notify IOKit PM clients of shutdown/restart
779 Clients subscribe to this message with a call to
780 IOService::registerInterest()
781 */
782
783 /* Spawn a thread that will panic in 30 seconds.
784 If all goes well the machine will be off by the time
785 the timer expires.
786 */
787 shutdown_hang = thread_call_allocate( &IOPMPanicOnShutdownHang, (thread_call_param_t) type);
788 clock_interval_to_deadline( 30, kSecondScale, &deadline );
789 thread_call_enter1_delayed( shutdown_hang, 0, deadline );
790
791 noWaitForResponses = pmRootDomain->tellChangeDown2(type);
792 /* This notification should have few clients who all do
793 their work synchronously.
794
795 In this "shutdown notification" context we don't give
796 drivers the option of working asynchronously and responding
797 later. PM internals make it very hard to wait for asynchronous
798 replies. In fact, it's a bad idea to even be calling
799 tellChangeDown2 from here at all.
800 */
801 }
fa4905b1 802
1c79356b
A
803 if (gIOPlatform) return gIOPlatform->haltRestart(type);
804 else return -1;
805}
806
9bccf70c
A
807UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length)
808{
809 if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length);
810 else return 0;
811}
812
1c79356b
A
813long PEGetGMTTimeOfDay(void)
814{
815 if( gIOPlatform)
816 return( gIOPlatform->getGMTTimeOfDay());
817 else
818 return( 0 );
819}
820
821void PESetGMTTimeOfDay(long secs)
822{
823 if( gIOPlatform)
824 gIOPlatform->setGMTTimeOfDay(secs);
825}
826
827} /* extern "C" */
828
829void IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
830{
831 publishResource("IONVRAM");
832}
833
834IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
835 bool waitForFunction,
836 void *param1, void *param2,
837 void *param3, void *param4)
838{
839 IOService *service, *_resources;
840
841 if (waitForFunction) {
842 _resources = waitForService(resourceMatching(functionName));
843 } else {
844 _resources = resources();
845 }
846 if (_resources == 0) return kIOReturnUnsupported;
847
848 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
849 if (service == 0) return kIOReturnUnsupported;
850
851 return service->callPlatformFunction(functionName, waitForFunction,
852 param1, param2, param3, param4);
853}
854
9bccf70c
A
855IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
856{
857 return 0;
858}
1c79356b
A
859
860/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
861
862#undef super
863#define super IOPlatformExpert
864
865OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
866
867OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
868OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
869OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
870OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
871OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
872OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
873OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
874OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
875
876/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
877
878IOService * IODTPlatformExpert::probe( IOService * provider,
879 SInt32 * score )
880{
881 if( !super::probe( provider, score))
882 return( 0 );
883
884 // check machine types
885 if( !provider->compareNames( getProperty( gIONameMatchKey ) ))
886 return( 0 );
887
888 return( this);
889}
890
891bool IODTPlatformExpert::configure( IOService * provider )
892{
893 if( !super::configure( provider))
894 return( false);
895
896 processTopLevel( provider );
897
898 return( true );
899}
900
901IOService * IODTPlatformExpert::createNub( IORegistryEntry * from )
902{
903 IOService * nub;
904
905 nub = new IOPlatformDevice;
906 if( nub) {
907 if( !nub->init( from, gIODTPlane )) {
908 nub->free();
909 nub = 0;
910 }
911 }
912 return( nub);
913}
914
915bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
916{
917 IORegistryEntry * next;
918 IOService * nub;
919 bool ok = true;
920
921 if( iter) {
922 while( (next = (IORegistryEntry *) iter->getNextObject())) {
923
924 if( 0 == (nub = createNub( next )))
925 continue;
926
927 nub->attach( parent );
928 nub->registerService();
929 }
930 iter->release();
931 }
932
933 return( ok );
934}
935
91447636 936void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1c79356b
A
937{
938 OSIterator * kids;
939 IORegistryEntry * next;
940 IORegistryEntry * cpus;
941 IORegistryEntry * options;
942
943 // infanticide
91447636 944 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
1c79356b
A
945 if( kids) {
946 while( (next = (IORegistryEntry *)kids->getNextObject())) {
947 next->detachAll( gIODTPlane);
948 }
949 kids->release();
950 }
951
952 // Publish an IODTNVRAM class on /options.
91447636 953 options = rootEntry->childFromPath("options", gIODTPlane);
1c79356b
A
954 if (options) {
955 dtNVRAM = new IODTNVRAM;
956 if (dtNVRAM) {
957 if (!dtNVRAM->init(options, gIODTPlane)) {
958 dtNVRAM->release();
959 dtNVRAM = 0;
960 } else {
961 dtNVRAM->attach(this);
962 dtNVRAM->registerService();
963 }
964 }
965 }
966
967 // Publish the cpus.
91447636 968 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1c79356b
A
969 if ( cpus)
970 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
971
972 // publish top level, minus excludeList
91447636 973 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1c79356b
A
974}
975
976IOReturn IODTPlatformExpert::getNubResources( IOService * nub )
977{
978 if( nub->getDeviceMemory())
979 return( kIOReturnSuccess );
980
981 IODTResolveAddressing( nub, "reg", 0);
982
983 return( kIOReturnSuccess);
984}
985
986bool IODTPlatformExpert::compareNubName( const IOService * nub,
987 OSString * name, OSString ** matched ) const
988{
989 return( IODTCompareNubName( nub, name, matched )
990 || super::compareNubName( nub, name, matched) );
991}
992
993bool IODTPlatformExpert::getModelName( char * name, int maxLength )
994{
995 OSData * prop;
996 const char * str;
997 int len;
998 char c;
999 bool ok = false;
1000
1001 maxLength--;
1002
1003 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1004 if( prop ) {
1005 str = (const char *) prop->getBytesNoCopy();
1006
1007 if( 0 == strncmp( str, "AAPL,", strlen( "AAPL," ) ))
1008 str += strlen( "AAPL," );
1009
1010 len = 0;
1011 while( (c = *str++)) {
1012 if( (c == '/') || (c == ' '))
1013 c = '-';
1014
1015 name[ len++ ] = c;
1016 if( len >= maxLength)
1017 break;
1018 }
1019
1020 name[ len ] = 0;
1021 ok = true;
1022 }
1023 return( ok );
1024}
1025
1026bool IODTPlatformExpert::getMachineName( char * name, int maxLength )
1027{
1028 OSData * prop;
1029 bool ok = false;
1030
1031 maxLength--;
1032 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1033 ok = (0 != prop);
1034
1035 if( ok )
1036 strncpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1037
1038 return( ok );
1039}
1040
1041/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1042
1043void IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1044{
1045 if (dtNVRAM) dtNVRAM->registerNVRAMController(nvram);
1046
1047 super::registerNVRAMController(nvram);
1048}
1049
1050int IODTPlatformExpert::haltRestart(unsigned int type)
1051{
1052 if (dtNVRAM) dtNVRAM->sync();
1053
1054 return super::haltRestart(type);
1055}
1056
1057IOReturn IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1058 IOByteCount length)
1059{
1060 if (dtNVRAM) return dtNVRAM->readXPRAM(offset, buffer, length);
1061 else return kIOReturnNotReady;
1062}
1063
1064IOReturn IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1065 IOByteCount length)
1066{
1067 if (dtNVRAM) return dtNVRAM->writeXPRAM(offset, buffer, length);
1068 else return kIOReturnNotReady;
1069}
1070
1071IOReturn IODTPlatformExpert::readNVRAMProperty(
1072 IORegistryEntry * entry,
1073 const OSSymbol ** name, OSData ** value )
1074{
1075 if (dtNVRAM) return dtNVRAM->readNVRAMProperty(entry, name, value);
1076 else return kIOReturnNotReady;
1077}
1078
1079IOReturn IODTPlatformExpert::writeNVRAMProperty(
1080 IORegistryEntry * entry,
1081 const OSSymbol * name, OSData * value )
1082{
1083 if (dtNVRAM) return dtNVRAM->writeNVRAMProperty(entry, name, value);
1084 else return kIOReturnNotReady;
1085}
1086
d52fe63f
A
1087OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void)
1088{
1089 if (dtNVRAM) return dtNVRAM->getNVRAMPartitions();
1090 else return 0;
1091}
1092
1093IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1094 IOByteCount offset, UInt8 * buffer,
1095 IOByteCount length)
1096{
1097 if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset,
1098 buffer, length);
1099 else return kIOReturnNotReady;
1100}
1101
1102IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1103 IOByteCount offset, UInt8 * buffer,
1104 IOByteCount length)
1105{
1106 if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1107 buffer, length);
1108 else return kIOReturnNotReady;
1109}
1110
9bccf70c
A
1111IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1112{
1113 IOByteCount lengthSaved = 0;
1114
1115 if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1116
1117 if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length);
1118
1119 return lengthSaved;
1120}
d52fe63f 1121
55e303ae
A
1122OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) {
1123 UInt8* serialNumber;
1124 unsigned int serialNumberSize;
91447636 1125 unsigned short pos = 0;
55e303ae
A
1126 char* temp;
1127 char SerialNo[30];
1128
1129 if (myProperty != NULL) {
1130 serialNumberSize = myProperty->getLength();
1131 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
91447636 1132 temp = (char*)serialNumber;
55e303ae
A
1133 if (serialNumberSize > 0) {
1134 // check to see if this is a CTO serial number...
1135 while (pos < serialNumberSize && temp[pos] != '-') pos++;
1136
1137 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1138 memcpy(SerialNo, serialNumber + 12, 8);
1139 memcpy(&SerialNo[8], serialNumber, 3);
1140 SerialNo[11] = '-';
1141 memcpy(&SerialNo[12], serialNumber + 3, 8);
1142 SerialNo[20] = 0;
1143 } else { // just a normal serial number
1144 memcpy(SerialNo, serialNumber + 13, 8);
1145 memcpy(&SerialNo[8], serialNumber, 3);
1146 SerialNo[11] = 0;
1147 }
1148 return OSString::withCString(SerialNo);
1149 }
1150 }
1151 return NULL;
1152}
1153
1154
1c79356b
A
1155/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1156
1157#undef super
1158#define super IOService
1159
1160OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1161
1162OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1163OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1164OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1165OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1166
1167/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1168
1169bool IOPlatformExpertDevice::compareName( OSString * name,
55e303ae 1170 OSString ** matched ) const
1c79356b
A
1171{
1172 return( IODTCompareNubName( this, name, matched ));
1173}
1174
1175bool
1176IOPlatformExpertDevice::initWithArgs(
1177 void * dtTop, void * p2, void * p3, void * p4 )
1178{
1179 IORegistryEntry * dt = 0;
1180 void * argsData[ 4 ];
1181 bool ok;
1182
1183 // dtTop may be zero on non- device tree systems
1184 if( dtTop && (dt = IODeviceTreeAlloc( dtTop )))
1185 ok = super::init( dt, gIODTPlane );
1186 else
1187 ok = super::init();
1188
1189 if( !ok)
1190 return( false);
1191
1192 workLoop = IOWorkLoop::workLoop();
1193 if (!workLoop)
1194 return false;
1195
1196 argsData[ 0 ] = dtTop;
1197 argsData[ 1 ] = p2;
1198 argsData[ 2 ] = p3;
1199 argsData[ 3 ] = p4;
1200
1201 setProperty("IOPlatformArgs", (void *)argsData, sizeof( argsData));
1202
1203 return( true);
1204}
1205
1206IOWorkLoop *IOPlatformExpertDevice::getWorkLoop() const
1207{
1208 return workLoop;
1209}
1210
1211void IOPlatformExpertDevice::free()
1212{
1213 if (workLoop)
1214 workLoop->release();
1215}
1216
1217/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1218
1219#undef super
1220#define super IOService
1221
1222OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
1223
1224OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
1225OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
1226OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
1227OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
1228
1229/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1230
1231bool IOPlatformDevice::compareName( OSString * name,
55e303ae 1232 OSString ** matched ) const
1c79356b
A
1233{
1234 return( ((IOPlatformExpert *)getProvider())->
1235 compareNubName( this, name, matched ));
1236}
1237
1238IOService * IOPlatformDevice::matchLocation( IOService * /* client */ )
1239{
1240 return( this );
1241}
1242
1243IOReturn IOPlatformDevice::getResources( void )
1244{
1245 return( ((IOPlatformExpert *)getProvider())->getNubResources( this ));
1246}
1247
1248/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1249
1250/*********************************************************************
1251* IOPanicPlatform class
1252*
1253* If no legitimate IOPlatformDevice matches, this one does and panics
1254* the kernel with a suitable message.
1255*********************************************************************/
1256
1257class IOPanicPlatform : IOPlatformExpert {
1258 OSDeclareDefaultStructors(IOPanicPlatform);
1259
1260public:
1261 bool start(IOService * provider);
1262};
1263
1264
1265OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
1266
1267
1268bool IOPanicPlatform::start(IOService * provider) {
1269 const char * platform_name = "(unknown platform name)";
1270
1271 if (provider) platform_name = provider->getName();
1272
1273 panic("Unable to find driver for this platform: \"%s\".\n",
1274 platform_name);
1275
1276 return false;
1277}