2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 #include <IOKit/IOCPU.h>
35 #include <IOKit/IODeviceTreeSupport.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOMapper.h>
38 #include <IOKit/IOMessage.h>
39 #include <IOKit/IONVRAM.h>
40 #include <IOKit/IOPlatformExpert.h>
41 #include <IOKit/IORangeAllocator.h>
42 #include <IOKit/IOWorkLoop.h>
43 #include <IOKit/pwr_mgt/RootDomain.h>
44 #include <IOKit/IOKitKeys.h>
45 #include <IOKit/IOTimeStamp.h>
47 #include <IOKit/system.h>
49 #include <libkern/c++/OSContainers.h>
52 #include <machine/machine_routines.h>
53 #include <pexpert/pexpert.h>
56 /* Delay period for UPS halt */
57 #define kUPSDelayHaltCPU_msec (1000*60*5)
59 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
60 static void getCStringForObject (OSObject
* inObj
, char * outStr
);
62 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
64 #define super IOService
66 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
68 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
70 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
78 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
79 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
80 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
82 static IOPlatformExpert
* gIOPlatform
;
83 static OSDictionary
* gIOInterruptControllers
;
84 static IOLock
* gIOInterruptControllersLock
;
86 OSSymbol
* gPlatformInterruptControllerName
;
88 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90 bool IOPlatformExpert::attach( IOService
* provider
)
93 if( !super::attach( provider
))
99 bool IOPlatformExpert::start( IOService
* provider
)
101 IORangeAllocator
* physicalRanges
;
102 OSData
* busFrequency
;
105 if (!super::start(provider
))
108 // Override the mapper present flag is requested by boot arguments.
109 if (PE_parse_boot_arg("dart", &debugFlags
) && (debugFlags
== 0))
110 removeProperty(kIOPlatformMapperPresentKey
);
112 // Register the presence or lack thereof a system
113 // PCI address mapper with the IOMapper class
114 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
116 gIOInterruptControllers
= OSDictionary::withCapacity(1);
117 gIOInterruptControllersLock
= IOLockAlloc();
119 // Correct the bus frequency in the device tree.
120 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
121 provider
->setProperty("clock-frequency", busFrequency
);
122 busFrequency
->release();
124 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
126 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
127 IORangeAllocator::kLocking
);
128 assert(physicalRanges
);
129 setProperty("Platform Memory Ranges", physicalRanges
);
134 PMInstantiatePowerDomains();
136 // Parse the serial-number data and publish a user-readable string
137 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
138 if (mydata
!= NULL
) {
139 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
140 if (serNoString
!= NULL
) {
141 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
142 serNoString
->release();
146 return( configure(provider
) );
149 bool IOPlatformExpert::configure( IOService
* provider
)
155 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
158 while( (dict
= OSDynamicCast( OSDictionary
,
159 topLevel
->getAnyObject()))) {
161 topLevel
->removeObject( dict
);
162 nub
= createNub( dict
);
167 nub
->registerService();
174 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
178 nub
= new IOPlatformDevice
;
180 if( !nub
->init( from
)) {
188 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
189 OSString
* name
, OSString
** matched
) const
191 return( nub
->IORegistryEntry::compareName( name
, matched
));
194 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
196 return( kIOReturnSuccess
);
199 long IOPlatformExpert::getBootROMType(void)
201 return _peBootROMType
;
204 long IOPlatformExpert::getChipSetType(void)
206 return _peChipSetType
;
209 long IOPlatformExpert::getMachineType(void)
211 return _peMachineType
;
214 void IOPlatformExpert::setBootROMType(long peBootROMType
)
216 _peBootROMType
= peBootROMType
;
219 void IOPlatformExpert::setChipSetType(long peChipSetType
)
221 _peChipSetType
= peChipSetType
;
224 void IOPlatformExpert::setMachineType(long peMachineType
)
226 _peMachineType
= peMachineType
;
229 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
234 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
239 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
244 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
246 return(OSDynamicCast(IORangeAllocator
,
247 getProperty("Platform Memory Ranges")));
250 int (*PE_halt_restart
)(unsigned int type
) = 0;
252 int IOPlatformExpert::haltRestart(unsigned int type
)
254 if (type
== kPEHangCPU
) while (1);
256 if (type
== kPEUPSDelayHaltCPU
) {
257 // Stall shutdown for 5 minutes, and if no outside force has
258 // removed our power at that point, proceed with a reboot.
259 IOSleep( kUPSDelayHaltCPU_msec
);
261 // Ideally we never reach this point.
263 type
= kPERestartCPU
;
266 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
270 void IOPlatformExpert::sleepKernel(void)
276 intState
= ml_set_interrupts_enabled(false);
278 for (cnt
= 0; cnt
< 10000; cnt
++) {
282 ml_set_interrupts_enabled(intState
);
284 // PE_initialize_console(0, kPEDisableScreen);
288 // PE_initialize_console(0, kPEEnableScreen);
292 long IOPlatformExpert::getGMTTimeOfDay(void)
297 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
302 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
304 return( PE_current_console( consoleInfo
));
307 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
310 return( PE_initialize_console( consoleInfo
, op
));
313 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
315 IOLockLock(gIOInterruptControllersLock
);
317 gIOInterruptControllers
->setObject(name
, interruptController
);
319 IOLockWakeup(gIOInterruptControllersLock
,
320 gIOInterruptControllers
, /* one-thread */ false);
322 IOLockUnlock(gIOInterruptControllersLock
);
324 return kIOReturnSuccess
;
327 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
331 IOLockLock(gIOInterruptControllersLock
);
334 object
= gIOInterruptControllers
->getObject(name
);
339 IOLockSleep(gIOInterruptControllersLock
,
340 gIOInterruptControllers
, THREAD_UNINT
);
343 IOLockUnlock(gIOInterruptControllersLock
);
344 return OSDynamicCast(IOInterruptController
, object
);
348 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
350 IOCPUInterruptController
*controller
;
352 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
353 if (controller
) controller
->setCPUInterruptProperties(service
);
356 bool IOPlatformExpert::atInterruptLevel(void)
358 return ml_at_interrupt_context();
361 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
367 //*********************************************************************************
370 //*********************************************************************************
372 void IOPlatformExpert::
373 PMLog(const char *who
, unsigned long event
,
374 unsigned long param1
, unsigned long param2
)
376 UInt32 debugFlags
= gIOKitDebug
;
378 if (debugFlags
& kIOLogPower
) {
380 uint32_t nows
, nowus
;
381 clock_get_system_microtime(&nows
, &nowus
);
382 nowus
+= (nows
% 1000) * 1000000;
384 kprintf("pm%u %x %.30s %d %x %x\n",
385 nowus
, (unsigned) current_thread(), who
, // Identity
386 (int) event
, param1
, param2
); // Args
388 if (debugFlags
& kIOLogTracePower
) {
389 static const UInt32 sStartStopBitField
[] =
390 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
392 // Arcane formula from Hacker's Delight by Warren
393 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
394 UInt32 sgnevent
= ((long) event
>> 31);
395 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
396 UInt32 code
= IODBG_POWER(absevent
);
398 UInt32 bit
= 1 << (absevent
& 0x1f);
399 if (absevent
< sizeof(sStartStopBitField
) * 8
400 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
401 // Or in the START or END bits, Start = 1 & END = 2
402 // If sgnevent == 0 then START - 0 => START
403 // else if sgnevent == -1 then START - -1 => END
404 code
|= DBG_FUNC_START
- sgnevent
;
407 // Record the timestamp, wish I had a this pointer
408 IOTimeStampConstant(code
, (UInt32
) who
, event
, param1
, param2
);
414 //*********************************************************************************
415 // PMInstantiatePowerDomains
417 // In this vanilla implementation, a Root Power Domain is instantiated.
418 // All other objects which register will be children of this Root.
419 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
420 // in a platform-specific subclass.
421 //*********************************************************************************
423 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
425 root
= new IOPMrootDomain
;
433 //*********************************************************************************
436 // In this vanilla implementation, all callers are made children of the root power domain.
437 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
438 //*********************************************************************************
440 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
442 root
->addPowerChild ( theDevice
);
445 //*********************************************************************************
448 //*********************************************************************************
450 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
452 return ((_pePMFeatures
& featureMask
) != 0);
455 //*********************************************************************************
458 //*********************************************************************************
460 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
462 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
465 //*********************************************************************************
466 // numBatteriesSupported
468 //*********************************************************************************
470 int IOPlatformExpert::numBatteriesSupported (void)
472 return (_peNumBatteriesSupported
);
475 //*********************************************************************************
478 // This method is called by the instantiated sublass of the platform expert to
479 // determine how a device should be inserted into the Power Domain. The subclass
480 // provides an XML power tree description against which a device is matched based
481 // on class and provider. If a match is found this routine returns true in addition
482 // to flagging the description tree at the appropriate node that a device has been
483 // registered for the given service.
484 //*********************************************************************************
486 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
489 unsigned int numPowerTreeNodes
;
490 OSDictionary
* entry
;
491 OSDictionary
* matchingDictionary
;
492 OSDictionary
* providerDictionary
;
493 OSDictionary
* deviceDictionary
;
494 OSDictionary
* nubDictionary
;
496 bool nodeFound
= false;
497 bool continueSearch
= false;
498 bool deviceMatch
= false;
499 bool providerMatch
= false;
500 bool multiParentMatch
= false;
502 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
505 numPowerTreeNodes
= inSubTree
->getCount ();
507 // iterate through the power tree to find a home for this device
509 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
511 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
513 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
514 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
516 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
517 if ( matchingDictionary
) {
519 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
520 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
521 deviceDictionary
->release ();
525 providerMatch
= true; // we indicate a match if there is no nub or provider
526 if ( theNub
&& providerDictionary
) {
527 providerMatch
= false;
528 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
529 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
530 nubDictionary
->release ();
534 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
535 if (deviceMatch
&& providerMatch
) {
536 if (NULL
!= multipleParentKeyValue
) {
537 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
538 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
542 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
544 // if the power tree specifies a provider dictionary but theNub is
545 // NULL then we cannot match with this entry.
547 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
550 // if this node is THE ONE...then register the device
553 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
555 if ( kIOLogPower
& gIOKitDebug
)
556 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
558 numInstancesRegistered
++;
560 // determine if we need to search for additional nodes for this item
561 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
567 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
569 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
570 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
571 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
574 if ( false == continueSearch
)
578 return ( nodeFound
);
581 //*********************************************************************************
582 // RegisterServiceInTree
584 // Register a device at the specified node of our power tree.
585 //*********************************************************************************
587 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
589 IOService
* aService
;
590 bool registered
= false;
592 unsigned int numChildren
;
593 OSDictionary
* child
;
595 // make sure someone is not already registered here
597 if ( NULL
== theTreeNode
->getObject ("service") ) {
599 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
601 // 1. CHILDREN ------------------
603 // we registered the node in the tree...now if the node has children
604 // registered we must tell this service to add them.
606 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
607 numChildren
= children
->getCount ();
608 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
609 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
610 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
611 theService
->addPowerChild (aService
);
616 // 2. PARENT --------------------
618 // also we must notify the parent of this node (if a registered service
619 // exists there) of a new child.
621 if ( theTreeParentNode
) {
622 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
623 if (aService
!= theProvider
)
624 aService
->addPowerChild (theService
);
634 //*********************************************************************************
635 // printDictionaryKeys
637 // Print the keys for the given dictionary and selected contents.
638 //*********************************************************************************
639 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
641 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
648 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
652 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
654 // if this is the IOClass key, print it's contents
656 if ( mkey
->isEqualTo ("IOClass") ) {
657 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
658 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
661 // if this is an IOProviderClass key print it
663 if ( mkey
->isEqualTo ("IOProviderClass") ) {
664 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
665 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
669 // also print IONameMatch keys
670 if ( mkey
->isEqualTo ("IONameMatch") ) {
671 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
672 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
675 // also print IONameMatched keys
677 if ( mkey
->isEqualTo ("IONameMatched") ) {
678 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
679 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
685 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
687 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
689 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
695 if ( mkey
->isEqualTo ("name") ) {
698 getCStringForObject (inDictionary
->getObject ("name"), nameStr
);
699 if (strlen(nameStr
) > 0)
700 IOLog ("%s name is %s\n", inMsg
, nameStr
);
703 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
711 static void getCStringForObject (OSObject
* inObj
, char * outStr
)
716 if ( (NULL
== inObj
) || (NULL
== outStr
))
719 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
721 if ((0 == strcmp(objString
,"OSString")) || (0 == strcmp (objString
, "OSSymbol")))
722 strcpy (outStr
, ((OSString
*)inObj
)->getCStringNoCopy());
724 else if (0 == strcmp(objString
,"OSData")) {
725 len
= ((OSData
*)inObj
)->getLength();
726 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
727 if (buffer
&& (len
> 0)) {
728 for (i
=0; i
< len
; i
++) {
729 outStr
[i
] = buffer
[i
];
736 /* IOShutdownNotificationsTimedOut
737 * - Called from a timer installed by PEHaltRestart
739 static void IOShutdownNotificationsTimedOut(
740 thread_call_param_t p0
,
741 thread_call_param_t p1
)
745 /* 30 seconds has elapsed - resume shutdown */
746 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
753 * Callouts from BSD for machine name & model
756 boolean_t
PEGetMachineName( char * name
, int maxLength
)
759 return( gIOPlatform
->getMachineName( name
, maxLength
));
764 boolean_t
PEGetModelName( char * name
, int maxLength
)
767 return( gIOPlatform
->getModelName( name
, maxLength
));
772 int PEGetPlatformEpoch(void)
775 return( gIOPlatform
->getBootROMType());
780 int PEHaltRestart(unsigned int type
)
782 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
783 bool noWaitForResponses
;
784 AbsoluteTime deadline
;
785 thread_call_t shutdown_hang
;
786 unsigned int tell_type
;
788 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
790 /* Notify IOKit PM clients of shutdown/restart
791 Clients subscribe to this message with a call to
792 IOService::registerInterest()
795 /* Spawn a thread that will panic in 30 seconds.
796 If all goes well the machine will be off by the time
799 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
800 (thread_call_param_t
) type
);
801 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
802 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
805 if( kPEUPSDelayHaltCPU
== type
) {
806 tell_type
= kPEHaltCPU
;
811 noWaitForResponses
= pmRootDomain
->tellChangeDown2(tell_type
);
812 /* This notification should have few clients who all do
813 their work synchronously.
815 In this "shutdown notification" context we don't give
816 drivers the option of working asynchronously and responding
817 later. PM internals make it very hard to wait for asynchronous
818 replies. In fact, it's a bad idea to even be calling
819 tellChangeDown2 from here at all.
823 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
827 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
829 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
833 long PEGetGMTTimeOfDay(void)
838 result
= gIOPlatform
->getGMTTimeOfDay();
843 void PESetGMTTimeOfDay(long secs
)
846 gIOPlatform
->setGMTTimeOfDay(secs
);
851 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
853 publishResource("IONVRAM");
856 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
857 bool waitForFunction
,
858 void *param1
, void *param2
,
859 void *param3
, void *param4
)
861 IOService
*service
, *_resources
;
863 if (waitForFunction
) {
864 _resources
= waitForService(resourceMatching(functionName
));
866 _resources
= resources();
868 if (_resources
== 0) return kIOReturnUnsupported
;
870 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
871 if (service
== 0) return kIOReturnUnsupported
;
873 return service
->callPlatformFunction(functionName
, waitForFunction
,
874 param1
, param2
, param3
, param4
);
877 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
882 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
885 #define super IOPlatformExpert
887 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
889 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
890 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
891 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
892 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
893 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
894 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
895 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
896 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
898 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
900 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
903 if( !super::probe( provider
, score
))
906 // check machine types
907 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
913 bool IODTPlatformExpert::configure( IOService
* provider
)
915 if( !super::configure( provider
))
918 processTopLevel( provider
);
923 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
927 nub
= new IOPlatformDevice
;
929 if( !nub
->init( from
, gIODTPlane
)) {
937 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
939 IORegistryEntry
* next
;
944 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
946 if( 0 == (nub
= createNub( next
)))
949 nub
->attach( parent
);
950 nub
->registerService();
958 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
961 IORegistryEntry
* next
;
962 IORegistryEntry
* cpus
;
963 IORegistryEntry
* options
;
966 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
968 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
969 next
->detachAll( gIODTPlane
);
974 // Publish an IODTNVRAM class on /options.
975 options
= rootEntry
->childFromPath("options", gIODTPlane
);
977 dtNVRAM
= new IODTNVRAM
;
979 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
983 dtNVRAM
->attach(this);
984 dtNVRAM
->registerService();
990 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
992 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
994 // publish top level, minus excludeList
995 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
998 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1000 if( nub
->getDeviceMemory())
1001 return( kIOReturnSuccess
);
1003 IODTResolveAddressing( nub
, "reg", 0);
1005 return( kIOReturnSuccess
);
1008 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1009 OSString
* name
, OSString
** matched
) const
1011 return( IODTCompareNubName( nub
, name
, matched
)
1012 || super::compareNubName( nub
, name
, matched
) );
1015 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1025 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1027 str
= (const char *) prop
->getBytesNoCopy();
1029 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1030 str
+= strlen( "AAPL," );
1033 while( (c
= *str
++)) {
1034 if( (c
== '/') || (c
== ' '))
1038 if( len
>= maxLength
)
1048 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1054 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1058 strncpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1063 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1065 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1067 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1069 super::registerNVRAMController(nvram
);
1072 int IODTPlatformExpert::haltRestart(unsigned int type
)
1074 if (dtNVRAM
) dtNVRAM
->sync();
1076 return super::haltRestart(type
);
1079 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1082 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1083 else return kIOReturnNotReady
;
1086 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1089 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1090 else return kIOReturnNotReady
;
1093 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1094 IORegistryEntry
* entry
,
1095 const OSSymbol
** name
, OSData
** value
)
1097 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1098 else return kIOReturnNotReady
;
1101 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1102 IORegistryEntry
* entry
,
1103 const OSSymbol
* name
, OSData
* value
)
1105 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1106 else return kIOReturnNotReady
;
1109 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1111 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1115 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1116 IOByteCount offset
, UInt8
* buffer
,
1119 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1121 else return kIOReturnNotReady
;
1124 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1125 IOByteCount offset
, UInt8
* buffer
,
1128 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1130 else return kIOReturnNotReady
;
1133 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1135 IOByteCount lengthSaved
= 0;
1137 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1139 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1144 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1145 UInt8
* serialNumber
;
1146 unsigned int serialNumberSize
;
1147 unsigned short pos
= 0;
1151 if (myProperty
!= NULL
) {
1152 serialNumberSize
= myProperty
->getLength();
1153 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1154 temp
= (char*)serialNumber
;
1155 if (serialNumberSize
> 0) {
1156 // check to see if this is a CTO serial number...
1157 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1159 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1160 memcpy(SerialNo
, serialNumber
+ 12, 8);
1161 memcpy(&SerialNo
[8], serialNumber
, 3);
1163 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1165 } else { // just a normal serial number
1166 memcpy(SerialNo
, serialNumber
+ 13, 8);
1167 memcpy(&SerialNo
[8], serialNumber
, 3);
1170 return OSString::withCString(SerialNo
);
1177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1180 #define super IOService
1182 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1184 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1185 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1186 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1187 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1189 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1191 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1192 OSString
** matched
) const
1194 return( IODTCompareNubName( this, name
, matched
));
1198 IOPlatformExpertDevice::initWithArgs(
1199 void * dtTop
, void * p2
, void * p3
, void * p4
)
1201 IORegistryEntry
* dt
= 0;
1202 void * argsData
[ 4 ];
1205 // dtTop may be zero on non- device tree systems
1206 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1207 ok
= super::init( dt
, gIODTPlane
);
1214 workLoop
= IOWorkLoop::workLoop();
1218 argsData
[ 0 ] = dtTop
;
1223 setProperty("IOPlatformArgs", (void *)argsData
, sizeof( argsData
));
1228 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1233 void IOPlatformExpertDevice::free()
1236 workLoop
->release();
1239 bool IOPlatformExpertDevice::attachToChild( IORegistryEntry
* child
,
1240 const IORegistryPlane
* plane
)
1242 return IOService::attachToChild( child
, plane
);
1245 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1248 #define super IOService
1250 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1252 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1253 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1254 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1255 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1257 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1259 bool IOPlatformDevice::compareName( OSString
* name
,
1260 OSString
** matched
) const
1262 return( ((IOPlatformExpert
*)getProvider())->
1263 compareNubName( this, name
, matched
));
1266 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1271 IOReturn
IOPlatformDevice::getResources( void )
1273 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1276 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1278 /*********************************************************************
1279 * IOPanicPlatform class
1281 * If no legitimate IOPlatformDevice matches, this one does and panics
1282 * the kernel with a suitable message.
1283 *********************************************************************/
1285 class IOPanicPlatform
: IOPlatformExpert
{
1286 OSDeclareDefaultStructors(IOPanicPlatform
);
1289 bool start(IOService
* provider
);
1293 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1296 bool IOPanicPlatform::start(IOService
* provider
) {
1297 const char * platform_name
= "(unknown platform name)";
1299 if (provider
) platform_name
= provider
->getName();
1301 panic("Unable to find driver for this platform: \"%s\".\n",