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