1/* 2 * Copyright (c) 1998-2014 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <AssertMacros.h> 25#include <libkern/OSAtomic.h> 26#include <libkern/c++/OSDictionary.h> 27#include <IOKit/IOLib.h> 28 29#include "IOHIDProviderPropertyMerger.h" 30 31#define super IOService 32 33OSDefineMetaClassAndStructors(IOHIDProviderPropertyMerger, IOService); 34 35bool IOHIDProviderPropertyMerger::start(IOService* provider) 36{ 37 OSObject * properties = NULL; 38 39 properties = copyProperty("IOProviderMergeProperties"); 40 mergeProperties(provider, OSDynamicCast(OSDictionary, properties)); 41 OSSafeReleaseNULL(properties); 42 43 return false; 44} 45 46bool IOHIDProviderPropertyMerger::mergeProperties(IOService * provider, OSDictionary * properties) 47{ 48 const OSSymbol * dictionaryEntry = NULL; 49 OSCollectionIterator * iterator = NULL; 50 bool result = false; 51 52 require(provider && properties, exit); 53 54 // Iterate through the properties until we run out of entries 55 iterator = OSCollectionIterator::withCollection(properties); 56 require(iterator, exit); 57 58 while ( (dictionaryEntry = (const OSSymbol *)iterator->getNextObject()) ) { 59 OSDictionary * sourceDictionary = NULL; 60 OSObject * providerObject = NULL; 61 OSDictionary * providerDictionary = NULL; 62 63 providerObject = provider->copyProperty(dictionaryEntry); 64 65 // See if our source entry is also a dictionary 66 sourceDictionary = OSDynamicCast(OSDictionary, properties->getObject(dictionaryEntry)); 67 providerDictionary = OSDynamicCast(OSDictionary, providerObject); 68 69 if ( providerDictionary && sourceDictionary ) { 70 71 // Because access to the registry table may not be synchronized, we should take a copy 72 OSDictionary * providerDictionaryCopy = NULL; 73 74 providerDictionaryCopy = OSDictionary::withDictionary( providerDictionary, 0); 75 require_action(providerDictionaryCopy, dictionaryExit, result=false); 76 77 // Recursively merge the two dictionaries 78 result = mergeDictionaries(sourceDictionary, providerDictionaryCopy); 79 require(result, dictionaryExit); 80 81 // OK, now we can just set the property in our provider 82 result = provider->setProperty(dictionaryEntry, providerDictionaryCopy); 83 require(result, dictionaryExit); 84 85dictionaryExit: 86 if ( providerDictionaryCopy ) 87 providerDictionaryCopy->release(); 88 } else { 89 // Not a dictionary, so just set the property 90 result = provider->setProperty(dictionaryEntry, properties->getObject(dictionaryEntry)); 91 } 92 93 if ( providerObject ) 94 providerObject->release(); 95 96 if ( !result ) 97 break; 98 } 99 100exit: 101 if ( iterator ) 102 iterator->release(); 103 104 return result; 105} 106 107 108bool IOHIDProviderPropertyMerger::mergeDictionaries(OSDictionary * source, OSDictionary * target) 109{ 110 OSCollectionIterator * srcIterator = NULL; 111 OSSymbol* keyObject = NULL; 112 bool result = false; 113 114 require(source && target, exit); 115 116 // Get our source dictionary 117 srcIterator = OSCollectionIterator::withCollection(source); 118 require(srcIterator, exit); 119 120 while ((keyObject = OSDynamicCast(OSSymbol, srcIterator->getNextObject()))) { 121 OSDictionary * childSourceDictionary = NULL; 122 OSDictionary * childTargetDictionary = NULL; 123 OSObject * childTargetObject = NULL; 124 125 // Check to see if our destination already has the same entry. 126 childTargetObject = target->getObject(keyObject); 127 if ( childTargetObject ) 128 childTargetDictionary = OSDynamicCast(OSDictionary, childTargetObject); 129 130 // See if our source entry is also a dictionary 131 childSourceDictionary = OSDynamicCast(OSDictionary, source->getObject(keyObject)); 132 133 if ( childTargetDictionary && childSourceDictionary) { 134 // Our destination dictionary already has the entry for this same object AND our 135 // source is also a dcitionary, so we need to recursively add it. 136 // 137 result = mergeDictionaries(childSourceDictionary, childTargetDictionary) ; 138 if ( !result ) 139 break; 140 } else { 141 // We have a property that we need to merge into our parent dictionary. 142 // 143 result = target->setObject(keyObject, source->getObject(keyObject)) ; 144 if ( !result ) 145 break; 146 } 147 } 148 149exit: 150 if ( srcIterator ) 151 srcIterator->release(); 152 153 return result; 154} 155