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 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
55 static void getCStringForObject (OSObject
* inObj
, char * outStr
);
57 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
59 #define super IOService
61 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
63 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
65 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
66 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
67 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
68 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
69 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
77 static IOPlatformExpert
* gIOPlatform
;
78 static OSDictionary
* gIOInterruptControllers
;
79 static IOLock
* gIOInterruptControllersLock
;
81 OSSymbol
* gPlatformInterruptControllerName
;
83 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
85 bool IOPlatformExpert::attach( IOService
* provider
)
88 if( !super::attach( provider
))
94 bool IOPlatformExpert::start( IOService
* provider
)
96 IORangeAllocator
* physicalRanges
;
97 OSData
* busFrequency
;
100 if (!super::start(provider
))
103 // Override the mapper present flag is requested by boot arguments.
104 if (PE_parse_boot_arg("dart", &debugFlags
) && (debugFlags
== 0))
105 removeProperty(kIOPlatformMapperPresentKey
);
107 // Register the presence or lack thereof a system
108 // PCI address mapper with the IOMapper class
109 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
111 gIOInterruptControllers
= OSDictionary::withCapacity(1);
112 gIOInterruptControllersLock
= IOLockAlloc();
114 // Correct the bus frequency in the device tree.
115 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
116 provider
->setProperty("clock-frequency", busFrequency
);
117 busFrequency
->release();
119 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
121 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
122 IORangeAllocator::kLocking
);
123 assert(physicalRanges
);
124 setProperty("Platform Memory Ranges", physicalRanges
);
129 PMInstantiatePowerDomains();
131 // Parse the serial-number data and publish a user-readable string
132 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
133 if (mydata
!= NULL
) {
134 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
135 if (serNoString
!= NULL
) {
136 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
137 serNoString
->release();
141 return( configure(provider
) );
144 bool IOPlatformExpert::configure( IOService
* provider
)
150 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
153 while( (dict
= OSDynamicCast( OSDictionary
,
154 topLevel
->getAnyObject()))) {
156 topLevel
->removeObject( dict
);
157 nub
= createNub( dict
);
162 nub
->registerService();
169 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
173 nub
= new IOPlatformDevice
;
175 if( !nub
->init( from
)) {
183 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
184 OSString
* name
, OSString
** matched
) const
186 return( nub
->IORegistryEntry::compareName( name
, matched
));
189 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
191 return( kIOReturnSuccess
);
194 long IOPlatformExpert::getBootROMType(void)
196 return _peBootROMType
;
199 long IOPlatformExpert::getChipSetType(void)
201 return _peChipSetType
;
204 long IOPlatformExpert::getMachineType(void)
206 return _peMachineType
;
209 void IOPlatformExpert::setBootROMType(long peBootROMType
)
211 _peBootROMType
= peBootROMType
;
214 void IOPlatformExpert::setChipSetType(long peChipSetType
)
216 _peChipSetType
= peChipSetType
;
219 void IOPlatformExpert::setMachineType(long peMachineType
)
221 _peMachineType
= peMachineType
;
224 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
229 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
234 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
239 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
241 return(OSDynamicCast(IORangeAllocator
,
242 getProperty("Platform Memory Ranges")));
245 int (*PE_halt_restart
)(unsigned int type
) = 0;
247 int IOPlatformExpert::haltRestart(unsigned int type
)
249 IOPMrootDomain
*rd
= getPMRootDomain();
252 if(rd
) b
= (OSBoolean
*)OSDynamicCast(OSBoolean
, rd
->getProperty(OSString::withCString("StallSystemAtHalt")));
254 if (type
== kPEHangCPU
) while (1);
256 if (kOSBooleanTrue
== b
) {
257 // Stall shutdown for 5 minutes, and if no outside force has removed our power, continue with
260 type
= kPERestartCPU
;
263 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
267 void IOPlatformExpert::sleepKernel(void)
273 intState
= ml_set_interrupts_enabled(false);
275 for (cnt
= 0; cnt
< 10000; cnt
++) {
279 ml_set_interrupts_enabled(intState
);
281 // PE_initialize_console(0, kPEDisableScreen);
285 // PE_initialize_console(0, kPEEnableScreen);
289 long IOPlatformExpert::getGMTTimeOfDay(void)
294 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
299 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
301 return( PE_current_console( consoleInfo
));
304 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
307 return( PE_initialize_console( consoleInfo
, op
));
310 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
312 IOLockLock(gIOInterruptControllersLock
);
314 gIOInterruptControllers
->setObject(name
, interruptController
);
316 IOLockWakeup(gIOInterruptControllersLock
,
317 gIOInterruptControllers
, /* one-thread */ false);
319 IOLockUnlock(gIOInterruptControllersLock
);
321 return kIOReturnSuccess
;
324 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
328 IOLockLock(gIOInterruptControllersLock
);
331 object
= gIOInterruptControllers
->getObject(name
);
336 IOLockSleep(gIOInterruptControllersLock
,
337 gIOInterruptControllers
, THREAD_UNINT
);
340 IOLockUnlock(gIOInterruptControllersLock
);
341 return OSDynamicCast(IOInterruptController
, object
);
345 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
347 IOCPUInterruptController
*controller
;
349 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
350 if (controller
) controller
->setCPUInterruptProperties(service
);
353 bool IOPlatformExpert::atInterruptLevel(void)
355 return ml_at_interrupt_context();
358 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
364 //*********************************************************************************
367 //*********************************************************************************
369 void IOPlatformExpert::
370 PMLog(const char *who
, unsigned long event
,
371 unsigned long param1
, unsigned long param2
)
373 UInt32 debugFlags
= gIOKitDebug
;
375 if (debugFlags
& kIOLogPower
) {
377 uint32_t nows
, nowus
;
378 clock_get_system_microtime(&nows
, &nowus
);
379 nowus
+= (nows
% 1000) * 1000000;
381 kprintf("pm%u %x %.30s %d %x %x\n",
382 nowus
, (unsigned) current_thread(), who
, // Identity
383 (int) event
, param1
, param2
); // Args
385 if (debugFlags
& kIOLogTracePower
) {
386 static const UInt32 sStartStopBitField
[] =
387 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
389 // Arcane formula from Hacker's Delight by Warren
390 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
391 UInt32 sgnevent
= ((long) event
>> 31);
392 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
393 UInt32 code
= IODBG_POWER(absevent
);
395 UInt32 bit
= 1 << (absevent
& 0x1f);
396 if (absevent
< sizeof(sStartStopBitField
) * 8
397 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
398 // Or in the START or END bits, Start = 1 & END = 2
399 // If sgnevent == 0 then START - 0 => START
400 // else if sgnevent == -1 then START - -1 => END
401 code
|= DBG_FUNC_START
- sgnevent
;
404 // Record the timestamp, wish I had a this pointer
405 IOTimeStampConstant(code
, (UInt32
) who
, event
, param1
, param2
);
411 //*********************************************************************************
412 // PMInstantiatePowerDomains
414 // In this vanilla implementation, a Root Power Domain is instantiated.
415 // All other objects which register will be children of this Root.
416 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
417 // in a platform-specific subclass.
418 //*********************************************************************************
420 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
422 root
= new IOPMrootDomain
;
430 //*********************************************************************************
433 // In this vanilla implementation, all callers are made children of the root power domain.
434 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
435 //*********************************************************************************
437 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
439 root
->addPowerChild ( theDevice
);
442 //*********************************************************************************
445 //*********************************************************************************
447 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
449 return ((_pePMFeatures
& featureMask
) != 0);
452 //*********************************************************************************
455 //*********************************************************************************
457 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
459 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
462 //*********************************************************************************
463 // numBatteriesSupported
465 //*********************************************************************************
467 int IOPlatformExpert::numBatteriesSupported (void)
469 return (_peNumBatteriesSupported
);
472 //*********************************************************************************
475 // This method is called by the instantiated sublass of the platform expert to
476 // determine how a device should be inserted into the Power Domain. The subclass
477 // provides an XML power tree description against which a device is matched based
478 // on class and provider. If a match is found this routine returns true in addition
479 // to flagging the description tree at the appropriate node that a device has been
480 // registered for the given service.
481 //*********************************************************************************
483 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
486 unsigned int numPowerTreeNodes
;
487 OSDictionary
* entry
;
488 OSDictionary
* matchingDictionary
;
489 OSDictionary
* providerDictionary
;
490 OSDictionary
* deviceDictionary
;
491 OSDictionary
* nubDictionary
;
493 bool nodeFound
= false;
494 bool continueSearch
= false;
495 bool deviceMatch
= false;
496 bool providerMatch
= false;
497 bool multiParentMatch
= false;
499 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
502 numPowerTreeNodes
= inSubTree
->getCount ();
504 // iterate through the power tree to find a home for this device
506 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
508 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
510 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
511 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
513 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
514 if ( matchingDictionary
) {
516 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
517 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
518 deviceDictionary
->release ();
522 providerMatch
= true; // we indicate a match if there is no nub or provider
523 if ( theNub
&& providerDictionary
) {
524 providerMatch
= false;
525 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
526 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
527 nubDictionary
->release ();
531 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
532 if (deviceMatch
&& providerMatch
) {
533 if (NULL
!= multipleParentKeyValue
) {
534 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
535 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
539 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
541 // if the power tree specifies a provider dictionary but theNub is
542 // NULL then we cannot match with this entry.
544 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
547 // if this node is THE ONE...then register the device
550 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
552 if ( kIOLogPower
& gIOKitDebug
)
553 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
555 numInstancesRegistered
++;
557 // determine if we need to search for additional nodes for this item
558 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
564 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
566 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
567 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
568 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
571 if ( false == continueSearch
)
575 return ( nodeFound
);
578 //*********************************************************************************
579 // RegisterServiceInTree
581 // Register a device at the specified node of our power tree.
582 //*********************************************************************************
584 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
586 IOService
* aService
;
587 bool registered
= false;
589 unsigned int numChildren
;
590 OSDictionary
* child
;
592 // make sure someone is not already registered here
594 if ( NULL
== theTreeNode
->getObject ("service") ) {
596 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
598 // 1. CHILDREN ------------------
600 // we registered the node in the tree...now if the node has children
601 // registered we must tell this service to add them.
603 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
604 numChildren
= children
->getCount ();
605 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
606 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
607 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
608 theService
->addPowerChild (aService
);
613 // 2. PARENT --------------------
615 // also we must notify the parent of this node (if a registered service
616 // exists there) of a new child.
618 if ( theTreeParentNode
) {
619 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
620 if (aService
!= theProvider
)
621 aService
->addPowerChild (theService
);
631 //*********************************************************************************
632 // printDictionaryKeys
634 // Print the keys for the given dictionary and selected contents.
635 //*********************************************************************************
636 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
638 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
645 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
649 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
651 // if this is the IOClass key, print it's contents
653 if ( mkey
->isEqualTo ("IOClass") ) {
654 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
655 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
658 // if this is an IOProviderClass key print it
660 if ( mkey
->isEqualTo ("IOProviderClass") ) {
661 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
662 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
666 // also print IONameMatch keys
667 if ( mkey
->isEqualTo ("IONameMatch") ) {
668 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
669 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
672 // also print IONameMatched keys
674 if ( mkey
->isEqualTo ("IONameMatched") ) {
675 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
676 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
682 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
684 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
686 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
692 if ( mkey
->isEqualTo ("name") ) {
695 getCStringForObject (inDictionary
->getObject ("name"), nameStr
);
696 if (strlen(nameStr
) > 0)
697 IOLog ("%s name is %s\n", inMsg
, nameStr
);
700 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
708 static void getCStringForObject (OSObject
* inObj
, char * outStr
)
713 if ( (NULL
== inObj
) || (NULL
== outStr
))
716 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
718 if ((0 == strcmp(objString
,"OSString")) || (0 == strcmp (objString
, "OSSymbol")))
719 strcpy (outStr
, ((OSString
*)inObj
)->getCStringNoCopy());
721 else if (0 == strcmp(objString
,"OSData")) {
722 len
= ((OSData
*)inObj
)->getLength();
723 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
724 if (buffer
&& (len
> 0)) {
725 for (i
=0; i
< len
; i
++) {
726 outStr
[i
] = buffer
[i
];
733 /* IOPMPanicOnShutdownHang
734 * - Called from a timer installed by PEHaltRestart
736 static void IOPMPanicOnShutdownHang(thread_call_param_t p0
, thread_call_param_t p1
)
740 /* 30 seconds has elapsed - resume shutdown */
741 gIOPlatform
->haltRestart(type
);
748 * Callouts from BSD for machine name & model
751 boolean_t
PEGetMachineName( char * name
, int maxLength
)
754 return( gIOPlatform
->getMachineName( name
, maxLength
));
759 boolean_t
PEGetModelName( char * name
, int maxLength
)
762 return( gIOPlatform
->getModelName( name
, maxLength
));
767 int PEGetPlatformEpoch(void)
770 return( gIOPlatform
->getBootROMType());
775 int PEHaltRestart(unsigned int type
)
777 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
778 bool noWaitForResponses
;
779 AbsoluteTime deadline
;
780 thread_call_t shutdown_hang
;
782 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
)
784 /* Notify IOKit PM clients of shutdown/restart
785 Clients subscribe to this message with a call to
786 IOService::registerInterest()
789 /* Spawn a thread that will panic in 30 seconds.
790 If all goes well the machine will be off by the time
793 shutdown_hang
= thread_call_allocate( &IOPMPanicOnShutdownHang
, (thread_call_param_t
) type
);
794 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
795 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
797 noWaitForResponses
= pmRootDomain
->tellChangeDown2(type
);
798 /* This notification should have few clients who all do
799 their work synchronously.
801 In this "shutdown notification" context we don't give
802 drivers the option of working asynchronously and responding
803 later. PM internals make it very hard to wait for asynchronous
804 replies. In fact, it's a bad idea to even be calling
805 tellChangeDown2 from here at all.
809 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
813 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
815 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
819 long PEGetGMTTimeOfDay(void)
822 return( gIOPlatform
->getGMTTimeOfDay());
827 void PESetGMTTimeOfDay(long secs
)
830 gIOPlatform
->setGMTTimeOfDay(secs
);
835 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
837 publishResource("IONVRAM");
840 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
841 bool waitForFunction
,
842 void *param1
, void *param2
,
843 void *param3
, void *param4
)
845 IOService
*service
, *_resources
;
847 if (waitForFunction
) {
848 _resources
= waitForService(resourceMatching(functionName
));
850 _resources
= resources();
852 if (_resources
== 0) return kIOReturnUnsupported
;
854 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
855 if (service
== 0) return kIOReturnUnsupported
;
857 return service
->callPlatformFunction(functionName
, waitForFunction
,
858 param1
, param2
, param3
, param4
);
861 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
866 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
869 #define super IOPlatformExpert
871 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
873 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
874 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
875 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
876 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
877 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
878 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
879 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
880 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
882 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
884 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
887 if( !super::probe( provider
, score
))
890 // check machine types
891 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
897 bool IODTPlatformExpert::configure( IOService
* provider
)
899 if( !super::configure( provider
))
902 processTopLevel( provider
);
907 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
911 nub
= new IOPlatformDevice
;
913 if( !nub
->init( from
, gIODTPlane
)) {
921 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
923 IORegistryEntry
* next
;
928 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
930 if( 0 == (nub
= createNub( next
)))
933 nub
->attach( parent
);
934 nub
->registerService();
942 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
945 IORegistryEntry
* next
;
946 IORegistryEntry
* cpus
;
947 IORegistryEntry
* options
;
950 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
952 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
953 next
->detachAll( gIODTPlane
);
958 // Publish an IODTNVRAM class on /options.
959 options
= rootEntry
->childFromPath("options", gIODTPlane
);
961 dtNVRAM
= new IODTNVRAM
;
963 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
967 dtNVRAM
->attach(this);
968 dtNVRAM
->registerService();
974 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
976 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
978 // publish top level, minus excludeList
979 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
982 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
984 if( nub
->getDeviceMemory())
985 return( kIOReturnSuccess
);
987 IODTResolveAddressing( nub
, "reg", 0);
989 return( kIOReturnSuccess
);
992 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
993 OSString
* name
, OSString
** matched
) const
995 return( IODTCompareNubName( nub
, name
, matched
)
996 || super::compareNubName( nub
, name
, matched
) );
999 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1009 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1011 str
= (const char *) prop
->getBytesNoCopy();
1013 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1014 str
+= strlen( "AAPL," );
1017 while( (c
= *str
++)) {
1018 if( (c
== '/') || (c
== ' '))
1022 if( len
>= maxLength
)
1032 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1038 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1042 strncpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1047 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1049 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1051 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1053 super::registerNVRAMController(nvram
);
1056 int IODTPlatformExpert::haltRestart(unsigned int type
)
1058 if (dtNVRAM
) dtNVRAM
->sync();
1060 return super::haltRestart(type
);
1063 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1066 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1067 else return kIOReturnNotReady
;
1070 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1073 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1074 else return kIOReturnNotReady
;
1077 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1078 IORegistryEntry
* entry
,
1079 const OSSymbol
** name
, OSData
** value
)
1081 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1082 else return kIOReturnNotReady
;
1085 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1086 IORegistryEntry
* entry
,
1087 const OSSymbol
* name
, OSData
* value
)
1089 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1090 else return kIOReturnNotReady
;
1093 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1095 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1099 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1100 IOByteCount offset
, UInt8
* buffer
,
1103 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1105 else return kIOReturnNotReady
;
1108 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1109 IOByteCount offset
, UInt8
* buffer
,
1112 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1114 else return kIOReturnNotReady
;
1117 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1119 IOByteCount lengthSaved
= 0;
1121 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1123 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1128 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1129 UInt8
* serialNumber
;
1130 unsigned int serialNumberSize
;
1131 unsigned short pos
= 0;
1135 if (myProperty
!= NULL
) {
1136 serialNumberSize
= myProperty
->getLength();
1137 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1138 temp
= (char*)serialNumber
;
1139 if (serialNumberSize
> 0) {
1140 // check to see if this is a CTO serial number...
1141 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1143 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1144 memcpy(SerialNo
, serialNumber
+ 12, 8);
1145 memcpy(&SerialNo
[8], serialNumber
, 3);
1147 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1149 } else { // just a normal serial number
1150 memcpy(SerialNo
, serialNumber
+ 13, 8);
1151 memcpy(&SerialNo
[8], serialNumber
, 3);
1154 return OSString::withCString(SerialNo
);
1161 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1164 #define super IOService
1166 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1168 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1169 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1170 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1171 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1173 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1175 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1176 OSString
** matched
) const
1178 return( IODTCompareNubName( this, name
, matched
));
1182 IOPlatformExpertDevice::initWithArgs(
1183 void * dtTop
, void * p2
, void * p3
, void * p4
)
1185 IORegistryEntry
* dt
= 0;
1186 void * argsData
[ 4 ];
1189 // dtTop may be zero on non- device tree systems
1190 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1191 ok
= super::init( dt
, gIODTPlane
);
1198 workLoop
= IOWorkLoop::workLoop();
1202 argsData
[ 0 ] = dtTop
;
1207 setProperty("IOPlatformArgs", (void *)argsData
, sizeof( argsData
));
1212 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1217 void IOPlatformExpertDevice::free()
1220 workLoop
->release();
1223 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1226 #define super IOService
1228 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1230 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1231 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1232 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1233 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1235 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1237 bool IOPlatformDevice::compareName( OSString
* name
,
1238 OSString
** matched
) const
1240 return( ((IOPlatformExpert
*)getProvider())->
1241 compareNubName( this, name
, matched
));
1244 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1249 IOReturn
IOPlatformDevice::getResources( void )
1251 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1254 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1256 /*********************************************************************
1257 * IOPanicPlatform class
1259 * If no legitimate IOPlatformDevice matches, this one does and panics
1260 * the kernel with a suitable message.
1261 *********************************************************************/
1263 class IOPanicPlatform
: IOPlatformExpert
{
1264 OSDeclareDefaultStructors(IOPanicPlatform
);
1267 bool start(IOService
* provider
);
1271 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1274 bool IOPanicPlatform::start(IOService
* provider
) {
1275 const char * platform_name
= "(unknown platform name)";
1277 if (provider
) platform_name
= provider
->getName();
1279 panic("Unable to find driver for this platform: \"%s\".\n",