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