1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2009 Apple Computer, Inc.  All Rights Reserved.
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#include <libkern/c++/OSCollectionIterator.h>
24#include <IOKit/assert.h>
25#include <IOKit/IOLib.h>
26#include <IOKit/IOService.h>
27#include <IOKit/hidsystem/IOHIDevice.h>
28#include <IOKit/hidsystem/IOHIDParameter.h>
29#include "IOHIDevicePrivateKeys.h"
30#include "IOHIDEventService.h"
31
32#define super IOService
33OSDefineMetaClassAndStructors(IOHIDevice, IOService);
34
35bool IOHIDevice::init(OSDictionary * properties)
36{
37  if (!super::init(properties))  return false;
38
39  /*
40   * Initialize minimal state.
41   */
42
43  return true;
44}
45
46void IOHIDevice::free()
47{
48  super::free();
49}
50
51bool IOHIDevice::start(IOService * provider)
52{
53    if (!super::start(provider))
54        return false;
55
56    // RY: If the kIOHIDVirtualHIDevice property isn't
57    // set scan the up provider chain to determine if
58    // this is a resource or if the provider is another
59    // IOHIDevice.  Also propegate value is property
60    // was already set in provider.
61    if (!getProperty(kIOHIDVirtualHIDevice)) {
62        OSObject * prop;
63
64        while (provider) {
65            prop = provider->copyProperty(kIOHIDVirtualHIDevice);
66            if ( OSDynamicCast(OSBoolean, prop) ) {
67                setProperty(kIOHIDVirtualHIDevice, prop);
68                break;
69            }
70            else if ( provider == getResourceService() || OSDynamicCast(IOHIDevice, provider) ) {
71                setProperty(kIOHIDVirtualHIDevice, kOSBooleanTrue);
72                break;
73            }
74
75            provider = provider->getProvider();
76            OSSafeReleaseNULL(prop);
77        }
78        OSSafeReleaseNULL(prop);
79
80        if ( !provider )
81            setProperty(kIOHIDVirtualHIDevice, kOSBooleanFalse);
82    }
83
84    updateProperties();
85
86    return true;
87}
88
89bool IOHIDevice::open(IOService *    forClient,
90                      IOOptionBits   options,
91                      void *         arg)
92{
93    if(forClient == this) return true;
94
95    return super::open(forClient, options, arg);
96}
97
98
99IOHIDKind IOHIDevice::hidKind()
100{
101  return kHIUnknownDevice;
102}
103
104UInt32 IOHIDevice::interfaceID()
105{
106  return 0;
107}
108
109UInt32 IOHIDevice::deviceType()
110{
111  return 0;
112}
113
114UInt64 IOHIDevice::getGUID()
115{
116  return(0xffffffffffffffffULL);
117}
118
119SInt32 IOHIDevice::GenerateKey(OSObject *object)
120{
121	SInt32 key = 0;
122#if __LP64__
123	UInt64 temp = (UInt64)object;
124	temp -= 0xffffff8000111000; // Subtract out the kernel base address
125	temp >>= 4; // Assume that objects can't be closer than 16 bytes apart
126	key = (SInt32)temp;
127#else
128	key = (SInt32)object;
129#endif
130	return key;
131}
132
133bool IOHIDevice::updateProperties( void )
134{
135    bool ok;
136
137    ok = setProperty( kIOHIDKindKey, hidKind(), 32 )
138    &    setProperty( kIOHIDInterfaceIDKey, interfaceID(), 32 )
139    &    setProperty( kIOHIDDeviceEventIDKey, IOHIDevice::GenerateKey(this), 32 )
140    &    setProperty( kIOHIDSubinterfaceIDKey, deviceType(), 32 );
141
142    return( ok );
143}
144
145// RY: Override IORegistryEntry::setProperties().  This will allow properties
146// to be set per device, instead of globally via setParamProperties.
147IOReturn IOHIDevice::setProperties( OSObject * properties )
148{
149    OSDictionary * propertyDict = OSDynamicCast(OSDictionary, properties);
150    IOReturn       ret          = kIOReturnBadArgument;
151
152    if ( propertyDict ) {
153        if (propertyDict->setOptions(0, 0) & OSDictionary::kImmutable) {
154            OSDictionary * temp = propertyDict;
155            propertyDict = OSDynamicCast(OSDictionary, temp->copyCollection());
156        }
157        else {
158            propertyDict->retain();
159        }
160        propertyDict->setObject(kIOHIDDeviceParametersKey, kOSBooleanTrue);
161        ret = setParamProperties( propertyDict );
162        propertyDict->removeObject(kIOHIDDeviceParametersKey);
163        propertyDict->release();
164    }
165
166    return ret;
167}
168
169
170IOReturn IOHIDevice::setParamProperties( OSDictionary * dict )
171{
172    IOHIDEventService * eventService = NULL;
173
174    if ( dict->getObject(kIOHIDEventServicePropertiesKey) == NULL ) {
175        IOService * service = getProvider();
176        if ( service )
177            eventService = OSDynamicCast(IOHIDEventService, service);
178    }
179
180    if ( dict->getObject(kIOHIDDeviceParametersKey) == kOSBooleanTrue ) {
181        OSDictionary * deviceParameters = OSDynamicCast(OSDictionary, copyProperty(kIOHIDParametersKey));
182
183        if ( !deviceParameters ) {
184            deviceParameters = OSDictionary::withCapacity(4);
185        }
186        else {
187            if (deviceParameters->setOptions(0, 0) & OSDictionary::kImmutable) {
188                OSDictionary * temp = deviceParameters;
189                deviceParameters = OSDynamicCast(OSDictionary, temp->copyCollection());
190                temp->release();
191            }
192            else {
193                // do nothing
194            }
195        }
196
197        if ( deviceParameters ) {
198            // RY: Because K&M Prefs and Admin still expect device props to be
199            // top level, let's continue to set them via setProperty. When we get
200            // Max to migrate over, we can remove the interator code and use:
201            // deviceParameters->merge(dict);
202            // deviceParameters->removeObject(kIOHIDResetKeyboardKey);
203            // deviceParameters->removeObject(kIOHIDResetPointerKey);
204            // setProperty(kIOHIDParametersKey, deviceParameters);
205            // deviceParameters->release();
206
207            OSCollectionIterator * iterator = OSCollectionIterator::withCollection(dict);
208            if ( iterator ) {
209                OSSymbol * key;
210
211                while ( ( key = (OSSymbol *)iterator->getNextObject() ) )
212                    if (    !key->isEqualTo(kIOHIDResetKeyboardKey) &&
213                            !key->isEqualTo(kIOHIDResetPointerKey) &&
214                            !key->isEqualTo(kIOHIDScrollResetKey) &&
215                            !key->isEqualTo(kIOHIDDeviceParametersKey) &&
216                            !key->isEqualTo(kIOHIDResetLEDsKey)) {
217                        OSObject * value = dict->getObject(key);
218
219                        deviceParameters->setObject(key, value);
220                        setProperty(key, value);
221                    }
222
223                iterator->release();
224            }
225
226            setProperty(kIOHIDParametersKey, deviceParameters);
227            deviceParameters->release();
228
229            // RY: Propogate up to IOHIDEventService level
230            if ( eventService )
231                eventService->setSystemProperties(dict);
232
233        }
234        else {
235            return kIOReturnNoMemory;
236        }
237    }
238
239    return( kIOReturnSuccess );
240}
241
242
243