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