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