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