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