2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 #include <IOKit/IOCPU.h>
33 #include <IOKit/IODeviceTreeSupport.h>
34 #include <IOKit/IOKitDebug.h>
35 #include <IOKit/IOMapper.h>
36 #include <IOKit/IOMessage.h>
37 #include <IOKit/IONVRAM.h>
38 #include <IOKit/IOPlatformExpert.h>
39 #include <IOKit/IORangeAllocator.h>
40 #include <IOKit/IOWorkLoop.h>
41 #include <IOKit/pwr_mgt/RootDomain.h>
42 #include <IOKit/IOKitKeys.h>
43 #include <IOKit/IOTimeStamp.h>
45 #include <IOKit/system.h>
47 #include <libkern/c++/OSContainers.h>
50 #include <machine/machine_routines.h>
51 #include <pexpert/pexpert.h>
54 /* Delay period for UPS halt */
55 #define kUPSDelayHaltCPU_msec (1000*60*5)
57 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
58 static void getCStringForObject (OSObject
* inObj
, char * outStr
);
60 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62 #define super IOService
64 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
66 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
68 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
69 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
78 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
80 static IOPlatformExpert
* gIOPlatform
;
81 static OSDictionary
* gIOInterruptControllers
;
82 static IOLock
* gIOInterruptControllersLock
;
84 OSSymbol
* gPlatformInterruptControllerName
;
86 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88 bool IOPlatformExpert::attach( IOService
* provider
)
91 if( !super::attach( provider
))
97 bool IOPlatformExpert::start( IOService
* provider
)
99 IORangeAllocator
* physicalRanges
;
100 OSData
* busFrequency
;
103 if (!super::start(provider
))
106 // Override the mapper present flag is requested by boot arguments.
107 if (PE_parse_boot_arg("dart", &debugFlags
) && (debugFlags
== 0))
108 removeProperty(kIOPlatformMapperPresentKey
);
110 // Register the presence or lack thereof a system
111 // PCI address mapper with the IOMapper class
112 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
114 gIOInterruptControllers
= OSDictionary::withCapacity(1);
115 gIOInterruptControllersLock
= IOLockAlloc();
117 // Correct the bus frequency in the device tree.
118 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
119 provider
->setProperty("clock-frequency", busFrequency
);
120 busFrequency
->release();
122 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
124 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
125 IORangeAllocator::kLocking
);
126 assert(physicalRanges
);
127 setProperty("Platform Memory Ranges", physicalRanges
);
132 PMInstantiatePowerDomains();
134 // Parse the serial-number data and publish a user-readable string
135 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
136 if (mydata
!= NULL
) {
137 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
138 if (serNoString
!= NULL
) {
139 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
140 serNoString
->release();
144 return( configure(provider
) );
147 bool IOPlatformExpert::configure( IOService
* provider
)
153 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
156 while( (dict
= OSDynamicCast( OSDictionary
,
157 topLevel
->getAnyObject()))) {
159 topLevel
->removeObject( dict
);
160 nub
= createNub( dict
);
165 nub
->registerService();
172 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
176 nub
= new IOPlatformDevice
;
178 if( !nub
->init( from
)) {
186 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
187 OSString
* name
, OSString
** matched
) const
189 return( nub
->IORegistryEntry::compareName( name
, matched
));
192 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
194 return( kIOReturnSuccess
);
197 long IOPlatformExpert::getBootROMType(void)
199 return _peBootROMType
;
202 long IOPlatformExpert::getChipSetType(void)
204 return _peChipSetType
;
207 long IOPlatformExpert::getMachineType(void)
209 return _peMachineType
;
212 void IOPlatformExpert::setBootROMType(long peBootROMType
)
214 _peBootROMType
= peBootROMType
;
217 void IOPlatformExpert::setChipSetType(long peChipSetType
)
219 _peChipSetType
= peChipSetType
;
222 void IOPlatformExpert::setMachineType(long peMachineType
)
224 _peMachineType
= peMachineType
;
227 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
232 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
237 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
242 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
244 return(OSDynamicCast(IORangeAllocator
,
245 getProperty("Platform Memory Ranges")));
248 int (*PE_halt_restart
)(unsigned int type
) = 0;
250 int IOPlatformExpert::haltRestart(unsigned int type
)
252 if (type
== kPEHangCPU
) while (1);
254 if (type
== kPEUPSDelayHaltCPU
) {
255 // Stall shutdown for 5 minutes, and if no outside force has
256 // removed our power at that point, proceed with a reboot.
257 IOSleep( kUPSDelayHaltCPU_msec
);
259 // Ideally we never reach this point.
261 type
= kPERestartCPU
;
263 kprintf("platform halt restart\n");
264 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
268 void IOPlatformExpert::sleepKernel(void)
274 intState
= ml_set_interrupts_enabled(false);
276 for (cnt
= 0; cnt
< 10000; cnt
++) {
280 ml_set_interrupts_enabled(intState
);
282 // PE_initialize_console(0, kPEDisableScreen);
286 // PE_initialize_console(0, kPEEnableScreen);
290 long IOPlatformExpert::getGMTTimeOfDay(void)
295 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
300 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
302 return( PE_current_console( consoleInfo
));
305 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
308 return( PE_initialize_console( consoleInfo
, op
));
311 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
313 IOLockLock(gIOInterruptControllersLock
);
315 gIOInterruptControllers
->setObject(name
, interruptController
);
317 IOLockWakeup(gIOInterruptControllersLock
,
318 gIOInterruptControllers
, /* one-thread */ false);
320 IOLockUnlock(gIOInterruptControllersLock
);
322 return kIOReturnSuccess
;
325 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
329 IOLockLock(gIOInterruptControllersLock
);
332 object
= gIOInterruptControllers
->getObject(name
);
337 IOLockSleep(gIOInterruptControllersLock
,
338 gIOInterruptControllers
, THREAD_UNINT
);
341 IOLockUnlock(gIOInterruptControllersLock
);
342 return OSDynamicCast(IOInterruptController
, object
);
346 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
348 IOCPUInterruptController
*controller
;
350 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
351 if (controller
) controller
->setCPUInterruptProperties(service
);
354 bool IOPlatformExpert::atInterruptLevel(void)
356 return ml_at_interrupt_context();
359 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
365 //*********************************************************************************
368 //*********************************************************************************
370 void IOPlatformExpert::
371 PMLog(const char *who
, unsigned long event
,
372 unsigned long param1
, unsigned long param2
)
374 UInt32 debugFlags
= gIOKitDebug
;
376 if (debugFlags
& kIOLogPower
) {
378 uint32_t nows
, nowus
;
379 clock_get_system_microtime(&nows
, &nowus
);
380 nowus
+= (nows
% 1000) * 1000000;
382 kprintf("pm%u %x %.30s %d %x %x\n",
383 nowus
, (unsigned) current_thread(), who
, // Identity
384 (int) event
, param1
, param2
); // Args
386 if (debugFlags
& kIOLogTracePower
) {
387 static const UInt32 sStartStopBitField
[] =
388 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
390 // Arcane formula from Hacker's Delight by Warren
391 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
392 UInt32 sgnevent
= ((long) event
>> 31);
393 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
394 UInt32 code
= IODBG_POWER(absevent
);
396 UInt32 bit
= 1 << (absevent
& 0x1f);
397 if (absevent
< sizeof(sStartStopBitField
) * 8
398 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
399 // Or in the START or END bits, Start = 1 & END = 2
400 // If sgnevent == 0 then START - 0 => START
401 // else if sgnevent == -1 then START - -1 => END
402 code
|= DBG_FUNC_START
- sgnevent
;
405 // Record the timestamp, wish I had a this pointer
406 IOTimeStampConstant(code
, (UInt32
) who
, event
, param1
, param2
);
412 //*********************************************************************************
413 // PMInstantiatePowerDomains
415 // In this vanilla implementation, a Root Power Domain is instantiated.
416 // All other objects which register will be children of this Root.
417 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
418 // in a platform-specific subclass.
419 //*********************************************************************************
421 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
423 root
= new IOPMrootDomain
;
431 //*********************************************************************************
434 // In this vanilla implementation, all callers are made children of the root power domain.
435 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
436 //*********************************************************************************
438 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
440 root
->addPowerChild ( theDevice
);
443 //*********************************************************************************
446 //*********************************************************************************
448 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
450 return ((_pePMFeatures
& featureMask
) != 0);
453 //*********************************************************************************
456 //*********************************************************************************
458 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
460 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
463 //*********************************************************************************
464 // numBatteriesSupported
466 //*********************************************************************************
468 int IOPlatformExpert::numBatteriesSupported (void)
470 return (_peNumBatteriesSupported
);
473 //*********************************************************************************
476 // This method is called by the instantiated sublass of the platform expert to
477 // determine how a device should be inserted into the Power Domain. The subclass
478 // provides an XML power tree description against which a device is matched based
479 // on class and provider. If a match is found this routine returns true in addition
480 // to flagging the description tree at the appropriate node that a device has been
481 // registered for the given service.
482 //*********************************************************************************
484 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
487 unsigned int numPowerTreeNodes
;
488 OSDictionary
* entry
;
489 OSDictionary
* matchingDictionary
;
490 OSDictionary
* providerDictionary
;
491 OSDictionary
* deviceDictionary
;
492 OSDictionary
* nubDictionary
;
494 bool nodeFound
= false;
495 bool continueSearch
= false;
496 bool deviceMatch
= false;
497 bool providerMatch
= false;
498 bool multiParentMatch
= false;
500 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
503 numPowerTreeNodes
= inSubTree
->getCount ();
505 // iterate through the power tree to find a home for this device
507 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
509 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
511 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
512 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
514 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
515 if ( matchingDictionary
) {
517 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
518 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
519 deviceDictionary
->release ();
523 providerMatch
= true; // we indicate a match if there is no nub or provider
524 if ( theNub
&& providerDictionary
) {
525 providerMatch
= false;
526 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
527 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
528 nubDictionary
->release ();
532 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
533 if (deviceMatch
&& providerMatch
) {
534 if (NULL
!= multipleParentKeyValue
) {
535 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
536 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
540 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
542 // if the power tree specifies a provider dictionary but theNub is
543 // NULL then we cannot match with this entry.
545 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
548 // if this node is THE ONE...then register the device
551 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
553 if ( kIOLogPower
& gIOKitDebug
)
554 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
556 numInstancesRegistered
++;
558 // determine if we need to search for additional nodes for this item
559 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
565 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
567 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
568 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
569 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
572 if ( false == continueSearch
)
576 return ( nodeFound
);
579 //*********************************************************************************
580 // RegisterServiceInTree
582 // Register a device at the specified node of our power tree.
583 //*********************************************************************************
585 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
587 IOService
* aService
;
588 bool registered
= false;
590 unsigned int numChildren
;
591 OSDictionary
* child
;
593 // make sure someone is not already registered here
595 if ( NULL
== theTreeNode
->getObject ("service") ) {
597 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
599 // 1. CHILDREN ------------------
601 // we registered the node in the tree...now if the node has children
602 // registered we must tell this service to add them.
604 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
605 numChildren
= children
->getCount ();
606 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
607 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
608 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
609 theService
->addPowerChild (aService
);
614 // 2. PARENT --------------------
616 // also we must notify the parent of this node (if a registered service
617 // exists there) of a new child.
619 if ( theTreeParentNode
) {
620 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
621 if (aService
!= theProvider
)
622 aService
->addPowerChild (theService
);
632 //*********************************************************************************
633 // printDictionaryKeys
635 // Print the keys for the given dictionary and selected contents.
636 //*********************************************************************************
637 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
639 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
646 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
650 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
652 // if this is the IOClass key, print it's contents
654 if ( mkey
->isEqualTo ("IOClass") ) {
655 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
656 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
659 // if this is an IOProviderClass key print it
661 if ( mkey
->isEqualTo ("IOProviderClass") ) {
662 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
663 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
667 // also print IONameMatch keys
668 if ( mkey
->isEqualTo ("IONameMatch") ) {
669 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
670 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
673 // also print IONameMatched keys
675 if ( mkey
->isEqualTo ("IONameMatched") ) {
676 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
677 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
683 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
685 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
687 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
693 if ( mkey
->isEqualTo ("name") ) {
696 getCStringForObject (inDictionary
->getObject ("name"), nameStr
);
697 if (strlen(nameStr
) > 0)
698 IOLog ("%s name is %s\n", inMsg
, nameStr
);
701 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
709 static void getCStringForObject (OSObject
* inObj
, char * outStr
)
714 if ( (NULL
== inObj
) || (NULL
== outStr
))
717 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
719 if ((0 == strcmp(objString
,"OSString")) || (0 == strcmp (objString
, "OSSymbol")))
720 strcpy (outStr
, ((OSString
*)inObj
)->getCStringNoCopy());
722 else if (0 == strcmp(objString
,"OSData")) {
723 len
= ((OSData
*)inObj
)->getLength();
724 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
725 if (buffer
&& (len
> 0)) {
726 for (i
=0; i
< len
; i
++) {
727 outStr
[i
] = buffer
[i
];
734 /* IOShutdownNotificationsTimedOut
735 * - Called from a timer installed by PEHaltRestart
737 static void IOShutdownNotificationsTimedOut(
738 thread_call_param_t p0
,
739 thread_call_param_t p1
)
743 /* 30 seconds has elapsed - resume shutdown */
744 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
751 * Callouts from BSD for machine name & model
754 boolean_t
PEGetMachineName( char * name
, int maxLength
)
757 return( gIOPlatform
->getMachineName( name
, maxLength
));
762 boolean_t
PEGetModelName( char * name
, int maxLength
)
765 return( gIOPlatform
->getModelName( name
, maxLength
));
770 int PEGetPlatformEpoch(void)
773 return( gIOPlatform
->getBootROMType());
778 int PEHaltRestart(unsigned int type
)
780 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
781 bool noWaitForResponses
;
782 AbsoluteTime deadline
;
783 thread_call_t shutdown_hang
;
784 unsigned int tell_type
;
786 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
788 /* Notify IOKit PM clients of shutdown/restart
789 Clients subscribe to this message with a call to
790 IOService::registerInterest()
793 /* Spawn a thread that will panic in 30 seconds.
794 If all goes well the machine will be off by the time
797 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
798 (thread_call_param_t
) type
);
799 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
800 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
803 if( kPEUPSDelayHaltCPU
== type
) {
804 tell_type
= kPEHaltCPU
;
809 noWaitForResponses
= pmRootDomain
->tellChangeDown2(tell_type
);
810 /* This notification should have few clients who all do
811 their work synchronously.
813 In this "shutdown notification" context we don't give
814 drivers the option of working asynchronously and responding
815 later. PM internals make it very hard to wait for asynchronous
816 replies. In fact, it's a bad idea to even be calling
817 tellChangeDown2 from here at all.
821 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
825 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
827 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
831 long PEGetGMTTimeOfDay(void)
836 result
= gIOPlatform
->getGMTTimeOfDay();
841 void PESetGMTTimeOfDay(long secs
)
844 gIOPlatform
->setGMTTimeOfDay(secs
);
849 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
851 publishResource("IONVRAM");
854 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
855 bool waitForFunction
,
856 void *param1
, void *param2
,
857 void *param3
, void *param4
)
859 IOService
*service
, *_resources
;
861 if (waitForFunction
) {
862 _resources
= waitForService(resourceMatching(functionName
));
864 _resources
= resources();
866 if (_resources
== 0) return kIOReturnUnsupported
;
868 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
869 if (service
== 0) return kIOReturnUnsupported
;
871 return service
->callPlatformFunction(functionName
, waitForFunction
,
872 param1
, param2
, param3
, param4
);
875 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
880 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
883 #define super IOPlatformExpert
885 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
887 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
888 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
889 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
890 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
891 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
892 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
893 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
894 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
896 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
898 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
901 if( !super::probe( provider
, score
))
904 // check machine types
905 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
911 bool IODTPlatformExpert::configure( IOService
* provider
)
913 if( !super::configure( provider
))
916 processTopLevel( provider
);
921 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
925 nub
= new IOPlatformDevice
;
927 if( !nub
->init( from
, gIODTPlane
)) {
935 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
937 IORegistryEntry
* next
;
942 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
944 if( 0 == (nub
= createNub( next
)))
947 nub
->attach( parent
);
948 nub
->registerService();
956 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
959 IORegistryEntry
* next
;
960 IORegistryEntry
* cpus
;
961 IORegistryEntry
* options
;
964 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
966 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
967 next
->detachAll( gIODTPlane
);
972 // Publish an IODTNVRAM class on /options.
973 options
= rootEntry
->childFromPath("options", gIODTPlane
);
975 dtNVRAM
= new IODTNVRAM
;
977 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
981 dtNVRAM
->attach(this);
982 dtNVRAM
->registerService();
988 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
990 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
992 // publish top level, minus excludeList
993 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
996 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
998 if( nub
->getDeviceMemory())
999 return( kIOReturnSuccess
);
1001 IODTResolveAddressing( nub
, "reg", 0);
1003 return( kIOReturnSuccess
);
1006 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1007 OSString
* name
, OSString
** matched
) const
1009 return( IODTCompareNubName( nub
, name
, matched
)
1010 || super::compareNubName( nub
, name
, matched
) );
1013 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1023 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1025 str
= (const char *) prop
->getBytesNoCopy();
1027 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1028 str
+= strlen( "AAPL," );
1031 while( (c
= *str
++)) {
1032 if( (c
== '/') || (c
== ' '))
1036 if( len
>= maxLength
)
1046 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1052 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1056 strncpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1061 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1063 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1065 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1067 super::registerNVRAMController(nvram
);
1070 int IODTPlatformExpert::haltRestart(unsigned int type
)
1072 if (dtNVRAM
) dtNVRAM
->sync();
1074 return super::haltRestart(type
);
1077 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1080 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1081 else return kIOReturnNotReady
;
1084 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1087 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1088 else return kIOReturnNotReady
;
1091 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1092 IORegistryEntry
* entry
,
1093 const OSSymbol
** name
, OSData
** value
)
1095 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1096 else return kIOReturnNotReady
;
1099 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1100 IORegistryEntry
* entry
,
1101 const OSSymbol
* name
, OSData
* value
)
1103 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1104 else return kIOReturnNotReady
;
1107 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1109 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1113 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1114 IOByteCount offset
, UInt8
* buffer
,
1117 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1119 else return kIOReturnNotReady
;
1122 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1123 IOByteCount offset
, UInt8
* buffer
,
1126 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1128 else return kIOReturnNotReady
;
1131 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1133 IOByteCount lengthSaved
= 0;
1135 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1137 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1142 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1143 UInt8
* serialNumber
;
1144 unsigned int serialNumberSize
;
1145 unsigned short pos
= 0;
1149 if (myProperty
!= NULL
) {
1150 serialNumberSize
= myProperty
->getLength();
1151 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1152 temp
= (char*)serialNumber
;
1153 if (serialNumberSize
> 0) {
1154 // check to see if this is a CTO serial number...
1155 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1157 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1158 memcpy(SerialNo
, serialNumber
+ 12, 8);
1159 memcpy(&SerialNo
[8], serialNumber
, 3);
1161 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1163 } else { // just a normal serial number
1164 memcpy(SerialNo
, serialNumber
+ 13, 8);
1165 memcpy(&SerialNo
[8], serialNumber
, 3);
1168 return OSString::withCString(SerialNo
);
1175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1178 #define super IOService
1180 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1182 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1183 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1184 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1185 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1187 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1189 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1190 OSString
** matched
) const
1192 return( IODTCompareNubName( this, name
, matched
));
1196 IOPlatformExpertDevice::initWithArgs(
1197 void * dtTop
, void * p2
, void * p3
, void * p4
)
1199 IORegistryEntry
* dt
= 0;
1200 void * argsData
[ 4 ];
1203 // dtTop may be zero on non- device tree systems
1204 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1205 ok
= super::init( dt
, gIODTPlane
);
1212 workLoop
= IOWorkLoop::workLoop();
1216 argsData
[ 0 ] = dtTop
;
1221 setProperty("IOPlatformArgs", (void *)argsData
, sizeof( argsData
));
1226 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1231 void IOPlatformExpertDevice::free()
1234 workLoop
->release();
1237 bool IOPlatformExpertDevice::attachToChild( IORegistryEntry
* child
,
1238 const IORegistryPlane
* plane
)
1240 return IOService::attachToChild( child
, plane
);
1243 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1246 #define super IOService
1248 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1250 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1251 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1252 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1253 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1255 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1257 bool IOPlatformDevice::compareName( OSString
* name
,
1258 OSString
** matched
) const
1260 return( ((IOPlatformExpert
*)getProvider())->
1261 compareNubName( this, name
, matched
));
1264 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1269 IOReturn
IOPlatformDevice::getResources( void )
1271 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1274 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1276 /*********************************************************************
1277 * IOPanicPlatform class
1279 * If no legitimate IOPlatformDevice matches, this one does and panics
1280 * the kernel with a suitable message.
1281 *********************************************************************/
1283 class IOPanicPlatform
: IOPlatformExpert
{
1284 OSDeclareDefaultStructors(IOPanicPlatform
);
1287 bool start(IOService
* provider
);
1291 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1294 bool IOPanicPlatform::start(IOService
* provider
) {
1295 const char * platform_name
= "(unknown platform name)";
1297 if (provider
) platform_name
= provider
->getName();
1299 panic("Unable to find driver for this platform: \"%s\".\n",