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