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