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