1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2003 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
24#include "IOHIDFamilyPrivate.h"
25
26#if !TARGET_OS_EMBEDDED
27#include "IOHIDSystem.h"
28#endif
29#include "OSStackRetain.h"
30
31#define kHIDTransport1ScoreIncrement        1000
32#define kHIDTransport2ScoreIncrement        2000
33#define kHIDDeviceUsageScoreBase            1100
34#define kHIDDeviceUsageScoreIncrement       100
35#define kHIDVendor1ScoreIncrement           5000
36#define kHIDVendor2ScoreIncrement           1000
37#define kHIDVendor2ArrayScoreIncrement      975
38#define kHIDVendor2MaskScoreIncrement       950
39#define kHIDVendor2ArrayMaskScoreIncrement  925
40#define kHIDVendor3ScoreIncrement           100
41
42//---------------------------------------------------------------------------
43// Compare the properties in the supplied table to this object's properties.
44bool CompareProperty( IOService * owner, OSDictionary * matching, const char * key, SInt32 * score, SInt32 increment)
45{
46    // We return success if we match the key in the dictionary with the key in
47    // the property table, or if the prop isn't present
48    //
49    OSObject *  value;
50    OSObject *  property;
51    bool        matches = true;
52
53    value = matching->getObject( key );
54
55    if( value)
56    {
57        property = owner->copyProperty( key );
58
59        if ( property )
60        {
61            matches = value->isEqualTo( property );
62
63            if (matches && score)
64                *score += increment;
65
66            property->release();
67        }
68        else
69            matches = false;
70    }
71
72    return matches;
73}
74
75bool CompareDeviceUsage( IOService * owner, OSDictionary * matching, SInt32 * score, SInt32 increment)
76{
77    // We return success if we match the key in the dictionary with the key in
78    // the property table, or if the prop isn't present
79    //
80    OSObject *      usage;
81    OSObject *      usagePage;
82    OSArray *       functions;
83    OSDictionary *  pair;
84    bool            matches = true;
85    int             count;
86
87    usage = matching->getObject( kIOHIDDeviceUsageKey );
88    usagePage = matching->getObject( kIOHIDDeviceUsagePageKey );
89    functions = OSDynamicCast(OSArray, owner->copyProperty( kIOHIDDeviceUsagePairsKey ));
90
91    if ( functions )
92    {
93        if ( usagePage || usage )
94        {
95            count = functions->getCount();
96
97            for (int i=0; i<count; i++)
98            {
99                if ( !(pair = (OSDictionary *)functions->getObject(i)) )
100                    continue;
101
102                if ( !usagePage ||
103                    !(matches = usagePage->isEqualTo(pair->getObject(kIOHIDDeviceUsagePageKey))) )
104                    continue;
105
106                if ( score && !usage )
107                {
108                    *score += increment / 2;
109                    break;
110                }
111
112                if ( !usage ||
113                    !(matches = usage->isEqualTo(pair->getObject(kIOHIDDeviceUsageKey))) )
114                    continue;
115
116                if ( score )
117                    *score += increment;
118
119                break;
120            }
121        }
122
123        functions->release();
124    } else {
125        matches = false;
126    }
127
128    return matches;
129}
130
131bool CompareDeviceUsagePairs( IOService * owner, OSDictionary * matching, SInt32 * score, SInt32 increment)
132{
133    // We return success if we match the key in the dictionary with the key in
134    // the property table, or if the prop isn't present
135    //
136    OSArray *       pairArray;
137    OSDictionary *  pair;
138    bool            matches = true;
139    int             count;
140
141    pairArray = OSDynamicCast(OSArray, matching->getObject( kIOHIDDeviceUsagePairsKey ));
142
143    if (pairArray)
144    {
145        count = pairArray->getCount();
146
147        for (int i=0; i<count; i++)
148        {
149            if ( !(pair = OSDynamicCast(OSDictionary,pairArray->getObject(i))) )
150                continue;
151
152            if ( !(matches = CompareDeviceUsage(owner, pair, score, increment)) )
153                continue;
154
155            break;
156        }
157    }
158
159    return matches;
160}
161
162bool CompareProductID( IOService * owner, OSDictionary * matching, SInt32 * score)
163{
164    bool pidMatch = false;
165    bool arrayMatch = false;
166    bool maskMatch = false;
167    bool maskArrayMatch = false;
168
169    SInt32 pidScore = 0;
170    SInt32 arrayScore = 0;
171    SInt32 maskScore = 0;
172    SInt32 maskArrayScore = 0;
173
174    // Compare each of the types of productID matching. Then in order of highest score to least
175    // see if we have any hits. Once we find one hit that matches properly then we can return
176    // true after incrementing the score.
177    pidMatch = CompareProperty(owner, matching, kIOHIDProductIDKey, &pidScore, kHIDVendor2ScoreIncrement);
178    arrayMatch = CompareNumberPropertyArray(owner, matching, kIOHIDProductIDArrayKey, kIOHIDProductIDKey, &arrayScore, kHIDVendor2ArrayScoreIncrement);
179    maskMatch = CompareNumberPropertyMask(owner, matching, kIOHIDProductIDKey, kIOHIDProductIDMaskKey, &maskScore, kHIDVendor2MaskScoreIncrement);
180    maskArrayMatch = CompareNumberPropertyArrayWithMask(owner, matching, kIOHIDProductIDArrayKey, kIOHIDProductIDKey, kIOHIDProductIDMaskKey, &maskArrayScore, kHIDVendor2ArrayMaskScoreIncrement);
181
182    if ( pidMatch && pidScore != 0 )
183    {
184        *score += pidScore;
185        return true;
186    }
187    else if ( arrayMatch && arrayScore != 0 )
188    {
189        *score += arrayScore;
190        return true;
191    }
192    else if ( maskMatch && maskScore != 0 )
193    {
194        *score += maskScore;
195        return true;
196    }
197    else if ( maskArrayMatch && maskArrayScore != 0 )
198    {
199        *score += maskArrayScore;
200        return true;
201    }
202    else
203    {
204        // If any of the matches explicitly failed (the property was present
205        // but none of our values matched the service object, then we should
206        // explicitly fail the matching. This will only return true if the
207        // personality did not define any productID related keys.
208        return pidMatch && arrayMatch && maskMatch && maskArrayMatch;
209    }
210}
211
212
213bool CompareNumberPropertyMask( IOService *owner, OSDictionary *matching, const char *key, const char *maskKey, SInt32 *score, SInt32 increment)
214{
215    OSNumber *    registryProperty;
216    OSNumber *    dictionaryProperty;
217    OSNumber *    valueMask;
218
219    registryProperty = OSDynamicCast(OSNumber,  owner->getProperty(key));
220    dictionaryProperty = OSDynamicCast(OSNumber, matching->getObject(key));
221    valueMask = OSDynamicCast(OSNumber, matching->getObject(maskKey));
222
223    // If the dicitonary or value mask doesn't exist then return true
224    if ( dictionaryProperty && valueMask )
225    {
226        if ( registryProperty )
227        {
228            // If all our values are OSNumbers, then get their actual value and do the masking
229            // to see if they are equal
230            //
231            UInt32  registryValue = registryProperty->unsigned32BitValue();
232            UInt32  dictionaryValue = dictionaryProperty->unsigned32BitValue();
233            UInt32  mask = valueMask->unsigned32BitValue();
234
235            if ( (registryValue & mask) == (dictionaryValue & mask) )
236            {
237                if ( score )
238                    *score += increment;
239                return true;
240            }
241        }
242    }
243    else
244        return true;
245
246    return false;
247}
248
249bool CompareNumberPropertyArray( IOService * owner, OSDictionary * matching, const char * arrayName, const char * key, SInt32 * score, SInt32 increment)
250{
251    OSNumber    *registryProperty = (OSNumber *)owner->copyProperty(key);
252    OSArray     *propertyArray = (OSArray *)matching->getObject(arrayName);
253    CONVERT_TO_STACK_RETAIN(registryProperty);
254
255    // If the property in the matching doesn't exist return true
256    if ( OSDynamicCast(OSArray, propertyArray) )
257    {
258        if ( OSDynamicCast(OSNumber, registryProperty ) )
259        {
260            OSNumber *propertyFromArray;
261            int i = 0;
262
263            for ( i = 0; i < propertyArray->getCount(); i ++ )
264            {
265                propertyFromArray = OSDynamicCast(OSNumber, propertyArray->getObject(i));
266                if ( propertyFromArray && propertyFromArray->isEqualTo(registryProperty) )
267                {
268                    if ( score )
269                        *score += increment;
270                    return true;
271                }
272            }
273        }
274    }
275    else
276        return true;
277
278    return false;
279}
280
281bool CompareNumberPropertyArrayWithMask( IOService * owner, OSDictionary * matching, const char * arrayName, const char * key, const char * maskKey, SInt32 * score, SInt32 increment)
282{
283    OSNumber    *registryProperty = (OSNumber *)owner->copyProperty(key);
284    OSArray     *propertyArray = (OSArray *)matching->getObject(arrayName);
285    OSNumber    *valueMask = (OSNumber *)matching->getObject(maskKey);
286    CONVERT_TO_STACK_RETAIN(registryProperty);
287
288    // If the property array or the value mask doesn't exist then return true
289    if( OSDynamicCast(OSArray, propertyArray) && OSDynamicCast(OSNumber, valueMask) )
290    {
291        if ( OSDynamicCast(OSNumber, registryProperty) )
292        {
293            OSNumber *propertyFromArray;
294            UInt32  registryValue = registryProperty->unsigned32BitValue();
295            UInt32  mask = valueMask->unsigned32BitValue();
296
297            int i = 0;
298
299            for ( i = 0; i < propertyArray->getCount(); i ++ )
300            {
301                propertyFromArray = OSDynamicCast(OSNumber, propertyArray->getObject(i));
302                if ( propertyFromArray )
303                {
304                    UInt32 propertyFromArrayValue = propertyFromArray->unsigned32BitValue();
305                    if( (registryValue & mask) == (propertyFromArrayValue & mask ) )
306                    {
307                        if ( score )
308                            *score += increment;
309                        return true;
310
311                    }
312                }
313            }
314        }
315    }
316    else
317        return true;
318
319    return false;
320}
321
322bool MatchPropertyTable(IOService * owner, OSDictionary * table, SInt32 * score)
323{
324    bool    match           = true;
325    SInt32  pUScore         = 0;
326    SInt32  pUPScore        = 0;
327    SInt32  useScore        = 0;
328    SInt32  trans1Score     = 0;
329    SInt32  trans2Score     = 0;
330    SInt32  ven1Score       = 0;
331    SInt32  ven2Score       = 0;
332    SInt32  ven3Score       = 0;
333    bool    pUPMatch        = CompareProperty(owner, table, kIOHIDPrimaryUsagePageKey, &pUPScore, kHIDDeviceUsageScoreBase);
334    bool    pUMatch         = CompareProperty(owner, table, kIOHIDPrimaryUsageKey, &pUScore, kHIDDeviceUsageScoreIncrement);
335    bool    useMatch        = CompareDeviceUsagePairs(owner, table, &useScore, kHIDDeviceUsageScoreIncrement);
336    bool    use2Match       = CompareDeviceUsage(owner, table, &useScore, kHIDDeviceUsageScoreIncrement);
337    bool    trans1Match     = CompareProperty(owner, table, kIOHIDTransportKey, &trans1Score, kHIDTransport1ScoreIncrement);
338    bool    trans2Match     = CompareProperty(owner, table, kIOHIDLocationIDKey, &trans2Score, kHIDTransport2ScoreIncrement);
339    bool    venIDMatch      = CompareProperty(owner, table, kIOHIDVendorIDKey, &ven1Score, kHIDVendor1ScoreIncrement);
340    bool    prodIDMatch     = CompareProductID(owner, table, &ven2Score);
341    bool    versNumMatch    = CompareProperty(owner, table, kIOHIDVersionNumberKey, &ven3Score, kHIDVendor3ScoreIncrement);
342    bool    manMatch        = CompareProperty(owner, table, kIOHIDManufacturerKey, &ven3Score, kHIDVendor3ScoreIncrement);
343    bool    serialMatch     = CompareProperty(owner, table, kIOHIDSerialNumberKey, &ven3Score, kHIDVendor3ScoreIncrement);
344    bool    bootPMatch      = CompareProperty(owner, table, "BootProtocol", score);
345
346    // Compare properties.
347    if (!pUPMatch ||
348        !pUMatch ||
349        !useMatch ||
350        !use2Match ||
351        !trans1Match ||
352        !trans2Match ||
353        !venIDMatch ||
354        !prodIDMatch ||
355        !versNumMatch ||
356        !manMatch ||
357        !serialMatch ||
358        !bootPMatch ||
359        (table->getObject("HIDDefaultBehavior") && !owner->getProperty("HIDDefaultBehavior")))
360    {
361        if (score)
362            *score = 0;
363        match = false;
364    }
365    else if ( score )
366    {
367        if ( trans1Score > 0 )
368            *score += trans1Score + trans2Score;
369
370        if ( ven1Score > 0 )
371            *score += ven1Score + ven2Score + ven3Score;
372
373        if ( useScore > 0 )
374            *score += useScore + kHIDDeviceUsageScoreBase;
375        else if ( pUPScore > 0 )
376            *score += pUPScore + pUScore;
377    }
378
379    return match;
380}
381
382void IOHIDSystemActivityTickle(SInt32 nxEventType, IOService *sender)
383{
384#if !TARGET_OS_EMBEDDED
385    IOHIDSystem *ioSys = IOHIDSystem::instance();
386    if (ioSys) {
387        intptr_t event = nxEventType;
388        ioSys->message(kIOHIDSystemActivityTickle, sender, (void*)event);
389    }
390#endif
391}
392
393