1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2009 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include "IOHIDEventDriver.h"
26#include "IOHIDInterface.h"
27#include "IOHIDKeys.h"
28#include "IOHIDTypes.h"
29#include "AppleHIDUsageTables.h"
30#include "IOHIDPrivateKeys.h"
31#include <IOKit/hid/IOHIDUsageTables.h>
32#include <IOKit/IOLib.h>
33#include <IOKit/usb/USB.h>
34#include "IOHIDFamilyTrace.h"
35#include "IOHIDEventTypes.h"
36
37enum {
38    kMouseButtons   = 0x1,
39    kMouseXAxis     = 0x2,
40    kMouseYAxis     = 0x4
41};
42
43enum {
44    kBootMouse      = (kMouseXAxis | kMouseYAxis | kMouseButtons)
45};
46
47enum {
48    kBootProtocolNone   = 0,
49    kBootProtocolKeyboard,
50    kBootProtocolMouse
51};
52
53// Describes the handler(s) at each report dispatch table slot.
54//
55struct IOHIDReportHandler
56{
57    OSArray * array[ kIOHIDReportTypeCount ];
58};
59
60#define kReportHandlerSlots    8
61
62#define GetReportHandlerSlot(id)    \
63    ((id) & (kReportHandlerSlots - 1))
64
65#define GetElementArray(slot, type) \
66    _reportHandlers[slot].array[type]
67
68#define GetReportType( type )                                               \
69    ((type <= kIOHIDElementTypeInput_ScanCodes) ? kIOHIDReportTypeInput :   \
70    (type <= kIOHIDElementTypeOutput) ? kIOHIDReportTypeOutput :            \
71    (type <= kIOHIDElementTypeFeature) ? kIOHIDReportTypeFeature : -1)
72
73#define GET_AXIS_COUNT(usage) (usage-kHIDUsage_GD_X+ 1)
74#define GET_AXIS_INDEX(usage) (usage-kHIDUsage_GD_X)
75
76
77#define kDefaultAbsoluteAxisRemovalPercentage           15
78#define kDefaultButtonAbsoluteAxisRemovalPercentage     60
79
80//===========================================================================
81// IOHIDEventDriver class
82
83#define super IOHIDEventService
84
85OSDefineMetaClassAndStructors( IOHIDEventDriver, IOHIDEventService )
86
87#define _digitizer                      _reserved->digitizer
88#define _absoluteAxisRemovalPercentage  _reserved->absoluteAxisRemovalPercentage
89#define _multiAxis                      _reserved->multiAxis
90
91
92//====================================================================================================
93// IOHIDEventDriver::init
94//====================================================================================================
95bool IOHIDEventDriver::init( OSDictionary * dictionary )
96{
97    if ( ! super::init ( dictionary ) )
98        return false;
99
100    _reserved = IONew(ExpansionData, 1);
101    bzero(_reserved, sizeof(ExpansionData));
102
103    _cachedRangeState               = true;
104    _relativeButtonCollection       = false;
105    _multipleReports                = false;
106    _absoluteAxisRemovalPercentage  = kDefaultAbsoluteAxisRemovalPercentage;
107
108    return true;
109}
110
111//====================================================================================================
112// IOHIDEventDriver::free
113//====================================================================================================
114void IOHIDEventDriver::free ()
115{
116    if ( _reportHandlers )
117    {
118        OSArray * temp;
119        for (int i=0; i<kReportHandlerSlots; i++)
120        {
121            for (int j=0; j<kIOHIDReportTypeCount; j++)
122            {
123                temp = GetElementArray(i, j);
124                if ( temp == NULL ) continue;
125
126                temp->release();
127            }
128        }
129        IOFree( _reportHandlers,
130                sizeof(IOHIDReportHandler) * kReportHandlerSlots );
131        _reportHandlers = 0;
132    }
133
134    if ( _supportedElements )
135    {
136        _supportedElements->release();
137        _supportedElements = 0;
138    }
139
140    if (_reserved)
141    {
142        IODelete(_reserved, ExpansionData, 1);
143        _reserved = NULL;
144    }
145
146    super::free();
147}
148
149//====================================================================================================
150// IOHIDEventDriver::handleStart
151//====================================================================================================
152bool IOHIDEventDriver::handleStart( IOService * provider )
153{
154    _interface = OSDynamicCast( IOHIDInterface, provider );
155
156    if ( !_interface )
157        return false;
158
159    IOService * service = this;
160
161    // Check to see if this is a product of an IOHIDDeviceShim
162    while ( NULL != (service = service->getProvider()) ) {
163        if(service->metaCast("IOHIDDeviceShim")) {
164            return false;
165        }
166    }
167
168    if (!_interface->open(this, 0,  OSMemberFunctionCast(IOHIDInterface::InterruptReportAction, this, &IOHIDEventDriver::handleInterruptReport), NULL))
169        return false;
170
171    _reportHandlers = (IOHIDReportHandler *)
172                      IOMalloc( sizeof(IOHIDReportHandler) *
173                                kReportHandlerSlots );
174    if ( _reportHandlers == 0 )
175        return false;
176
177    bzero( _reportHandlers, sizeof(IOHIDReportHandler) * kReportHandlerSlots );
178
179    UInt32      bootProtocol    = 0;
180    OSNumber *  number          = (OSNumber *)_interface->copyProperty("BootProtocol");
181
182    if (number)
183        bootProtocol = number->unsigned32BitValue();
184
185    setProperty("BootProtocol", number);
186    OSSafeReleaseNULL(number);
187
188    number = (OSNumber*)copyProperty(kIOHIDAbsoluteAxisBoundsRemovalPercentage, gIOServicePlane);
189    if ( OSDynamicCast(OSNumber, number) ) {
190        _absoluteAxisRemovalPercentage = number->unsigned32BitValue();
191    }
192    OSSafeReleaseNULL(number);
193
194    OSArray *elements = _interface->createMatchingElements();
195    bool result = false;
196
197    if ( elements ) {
198        if ( findElements ( elements, bootProtocol )) {
199            result = true;
200        }
201    }
202    OSSafeRelease(elements);
203
204    return result;
205}
206
207//====================================================================================================
208// IOHIDEventDriver::getTransport
209//====================================================================================================
210OSString * IOHIDEventDriver::getTransport ()
211{
212    return _interface ? _interface->getTransport() : (OSString *)OSSymbol::withCString("unknown:") ;
213}
214
215//====================================================================================================
216// IOHIDEventDriver::getManufacturer
217//====================================================================================================
218OSString * IOHIDEventDriver::getManufacturer ()
219{
220    return _interface ? _interface->getManufacturer() : (OSString *)OSSymbol::withCString("unknown:") ;
221}
222
223//====================================================================================================
224// IOHIDEventDriver::getProduct
225//====================================================================================================
226OSString * IOHIDEventDriver::getProduct ()
227{
228    return _interface ? _interface->getProduct() : (OSString *)OSSymbol::withCString("unknown:") ;
229}
230
231//====================================================================================================
232// IOHIDEventDriver::getSerialNumber
233//====================================================================================================
234OSString * IOHIDEventDriver::getSerialNumber ()
235{
236    return _interface ? _interface->getSerialNumber() : (OSString *)OSSymbol::withCString("unknown:") ;
237}
238
239//====================================================================================================
240// IOHIDEventDriver::getLocationID
241//====================================================================================================
242UInt32 IOHIDEventDriver::getLocationID ()
243{
244    return _interface ? _interface->getLocationID() : -1 ;
245}
246
247//====================================================================================================
248// IOHIDEventDriver::getVendorID
249//====================================================================================================
250UInt32 IOHIDEventDriver::getVendorID ()
251{
252    return _interface ? _interface->getVendorID() : -1 ;
253}
254
255//====================================================================================================
256// IOHIDEventDriver::getVendorIDSource
257//====================================================================================================
258UInt32 IOHIDEventDriver::getVendorIDSource ()
259{
260    return _interface ? _interface->getVendorIDSource() : -1 ;
261}
262
263//====================================================================================================
264// IOHIDEventDriver::getProductID
265//====================================================================================================
266UInt32 IOHIDEventDriver::getProductID ()
267{
268    return _interface ? _interface->getProductID() : -1 ;
269}
270
271//====================================================================================================
272// IOHIDEventDriver::getVersion
273//====================================================================================================
274UInt32 IOHIDEventDriver::getVersion ()
275{
276    return _interface ? _interface->getVersion() : -1 ;
277}
278
279//====================================================================================================
280// IOHIDEventDriver::getCountryCode
281//====================================================================================================
282UInt32 IOHIDEventDriver::getCountryCode ()
283{
284    return _interface ? _interface->getCountryCode() : -1 ;
285}
286
287
288//====================================================================================================
289// IOHIDEventDriver::handleStop
290//====================================================================================================
291void IOHIDEventDriver::handleStop(  IOService * provider __unused )
292{
293    //_interface->close(this);
294}
295
296//=============================================================================================
297// IOHIDEventDriver::didTerminate
298//=============================================================================================
299bool IOHIDEventDriver::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
300{
301    if (_interface)
302        _interface->close(this);
303    _interface = NULL;
304
305    return super::didTerminate(provider, options, defer);
306}
307
308//====================================================================================================
309// IOHIDEventDriver::findElements
310//====================================================================================================
311bool IOHIDEventDriver::findElements ( OSArray* elementArray, UInt32 bootProtocol)
312{
313    UInt32              count               = 0;
314    UInt32              index               = 0;
315    UInt32              usage               = 0;
316    UInt32              usagePage           = 0;
317    bool                stored              = false;
318    bool                pointer             = false;
319    bool                supportsInk         = false;
320    IOHIDElement *      element             = NULL;
321    IOHIDElement *      buttonCollection    = NULL;
322    IOHIDElement *      relativeCollection  = NULL;
323    IOHIDElement *      zAxis               = NULL;
324    IOHIDElement *      rzAxis              = NULL;
325    OSArray *           buttonArray         = NULL;
326
327    if ( bootProtocol == kBootProtocolMouse )
328        _bootSupport = kBootMouse;
329
330    if ( elementArray )
331    {
332        _supportedElements = elementArray;
333        _supportedElements->retain();
334
335        count = elementArray->getCount();
336
337        for ( index = 0; index < count; index++ )
338        {
339            bool    isRelative  = false;
340            UInt32  reportID    = 0;
341
342            element = (IOHIDElement *) elementArray->getObject(index);
343
344            if ( element == NULL )
345                continue;
346
347            if ( element->getType() == kIOHIDElementTypeCollection ) {
348
349                if ( usagePage == kHIDPage_Digitizer ) {
350                    switch ( usage )  {
351                        case kHIDUsage_Dig_TouchScreen:
352                        case kHIDUsage_Dig_TouchPad:
353                        case kHIDUsage_Dig_Finger:
354                            _digitizer.type = kDigitizerTransducerTypeFinger;
355                            break;
356                        default:
357                            break;
358
359                    }
360                }
361                continue;
362            }
363
364            reportID = element->getReportID();
365
366            if ( reportID > 0)
367                _multipleReports = true;
368
369            if ( element->getFlags() & kIOHIDElementFlagsRelativeMask)
370                isRelative = true;
371
372            usagePage   = element->getUsagePage();
373            usage       = element->getUsage();
374
375            if ( usagePage == kHIDPage_GenericDesktop )
376            {
377                switch ( usage )
378                {
379                    case kHIDUsage_GD_Dial:
380                    case kHIDUsage_GD_Wheel:
381
382                        if ((element->getFlags() & (kIOHIDElementFlagsNoPreferredMask|kIOHIDElementFlagsRelativeMask)) == 0) {
383                            calibratePreferredStateElement(element, _absoluteAxisRemovalPercentage);
384                        }
385
386                        stored |= storeReportElement(element);
387                        pointer = true;
388                        break;
389
390                    case kHIDUsage_GD_X:
391                    case kHIDUsage_GD_Y:
392                        _bootSupport &= (usage==kHIDUsage_GD_X) ? ~kMouseXAxis : ~kMouseYAxis;
393
394                        processMultiAxisElement(element, &_multiAxis.capable, &supportsInk, &relativeCollection);
395
396                        if ( _multiAxis.capable ) {
397                            calibratePreferredStateElement(element, _absoluteAxisRemovalPercentage);
398
399                            if ( reportID > _multiAxis.sendingReportID )
400                                _multiAxis.sendingReportID = reportID;
401
402                        } else if ( !isRelative ) {
403                            calibrateDigitizerElement(element, _absoluteAxisRemovalPercentage);
404                        }
405
406                        stored |= storeReportElement ( element );
407                        pointer = true;
408                        break;
409
410                    case kHIDUsage_GD_Z:
411                        processMultiAxisElement(element, &_multiAxis.capable);
412                        zAxis = element;
413                        stored |= storeReportElement(element);
414                        pointer = true;
415                        break;
416
417                    case kHIDUsage_GD_Rx:
418                    case kHIDUsage_GD_Ry:
419                        if ( _multiAxis.capable ) {
420                            _multiAxis.options |= kMultiAxisOptionRotationForTranslation;
421
422                            if ( reportID > _multiAxis.sendingReportID )
423                                _multiAxis.sendingReportID = reportID;
424                        }
425
426                    case kHIDUsage_GD_Rz:
427                        pointer = true;
428                        processMultiAxisElement(element, &_multiAxis.capable);
429
430                        if ( _multiAxis.capable ) {
431                            rzAxis = element;
432                            stored |= storeReportElement ( element );
433                        }
434                        break;
435
436                    case kHIDUsage_GD_SystemPowerDown:
437                    case kHIDUsage_GD_SystemSleep:
438                    case kHIDUsage_GD_SystemWakeUp:
439                        stored |= storeReportElement ( element );
440                        break;
441                }
442            }
443
444            else if ( usagePage == kHIDPage_Digitizer )
445            {
446                switch ( usage )
447                {
448                    case kHIDUsage_Dig_InRange:
449                        _digitizer.containsRange = true;
450                        _cachedRangeState = false;
451                        stored |= storeReportElement ( element );
452                        break;
453                    case kHIDUsage_Dig_TipPressure:
454                        supportsInk = true;
455                    case kHIDUsage_Dig_BarrelPressure:
456                        calibrateDigitizerElement(element, _absoluteAxisRemovalPercentage);
457                        stored |= storeReportElement ( element );
458                        break;
459                    case kHIDUsage_Dig_BarrelSwitch:
460                    case kHIDUsage_Dig_TipSwitch:
461                    case kHIDUsage_Dig_Eraser:
462                        _bootSupport &= ~kMouseButtons;
463                    case kHIDUsage_Dig_XTilt:
464                    case kHIDUsage_Dig_YTilt:
465                    case kHIDUsage_Dig_Twist:
466                    case kHIDUsage_Dig_TransducerIndex:
467                    case kHIDUsage_Dig_Invert:
468                        stored |= storeReportElement ( element );
469                        break;
470                }
471            }
472
473            else if (( usagePage == kHIDPage_KeyboardOrKeypad ) &&
474                (( usage >= kHIDUsage_KeyboardA ) && ( usage <= kHIDUsage_KeyboardRightGUI )))
475            {
476                    stored |= storeReportElement ( element );
477            }
478
479            else if ( usagePage == kHIDPage_Button )
480            {
481                if ( !buttonArray )
482                    buttonArray = OSArray::withCapacity(4);
483
484                // RY: Save the buttons for later.
485                if ( buttonArray )
486                    buttonArray->setObject(element);
487            }
488
489            else if ( usagePage == kHIDPage_Consumer || usagePage == kHIDPage_Telephony )
490            {
491                stored |= storeReportElement ( element );
492            }
493
494            else if (( usagePage == kHIDPage_LEDs ) &&
495                (((usage == kHIDUsage_LED_NumLock) || (usage == kHIDUsage_LED_CapsLock))
496                && (_ledElements[usage - kHIDUsage_LED_NumLock] == 0)))
497            {
498                _ledElements[usage - kHIDUsage_LED_NumLock] = element;
499            }
500            else if ((getVendorID() == kIOUSBVendorIDAppleComputer)
501                && (((usagePage == kHIDPage_AppleVendorTopCase) && (usage == kHIDUsage_AV_TopCase_KeyboardFn))
502                || ((usagePage == kHIDPage_AppleVendorKeyboard) && (usage == kHIDUsage_AppleVendorKeyboard_Function))))
503            {
504                stored |= storeReportElement ( element );
505            }
506        }
507    }
508
509    // RY: Add the buttons only if elements of a pointer have been discovered.
510    if ( buttonArray )
511    {
512        if ( pointer )
513        {
514            count = buttonArray->getCount();
515
516            for (index=0; index<count; index++)
517            {
518                element = (IOHIDElement *)buttonArray->getObject(index);
519
520                if ( !element ) continue;
521
522                _bootSupport &= ~kMouseButtons;
523
524                if ( !buttonCollection )
525                    buttonCollection = element->getParentElement();
526
527                stored |= storeReportElement ( element );
528            }
529        }
530        buttonArray->release();
531    }
532
533    if ( zAxis ) {
534
535        if ( (_multiAxis.capable & ((1<<GET_AXIS_INDEX(kHIDUsage_GD_Rx)) | (1<<GET_AXIS_INDEX(kHIDUsage_GD_Ry)))) == 0) {
536            _multiAxis.options |= kMultiAxisOptionZForScroll;
537        }
538        calibratePreferredStateElement(zAxis, _absoluteAxisRemovalPercentage);
539    }
540
541    if ( rzAxis ) {
542        SInt32 removal = _absoluteAxisRemovalPercentage;
543
544
545        if ( (_multiAxis.capable & ((1<<GET_AXIS_INDEX(kHIDUsage_GD_Rx)) | (1<<GET_AXIS_INDEX(kHIDUsage_GD_Ry)))) != 0) {
546            removal *= 2;
547        }
548        calibratePreferredStateElement(rzAxis, removal);
549
550    }
551
552    setProperty("MultiAxis", _multiAxis.capable, 32);
553
554    if ( supportsInk )
555        setProperty("SupportsInk", 1, 32);
556
557    if (buttonCollection == relativeCollection)
558        _relativeButtonCollection = true;
559
560    return ( stored || _bootSupport );
561
562}
563
564//====================================================================================================
565// IOHIDEventDriver::storeReportElement
566//====================================================================================================
567bool IOHIDEventDriver::storeReportElement ( IOHIDElement * element )
568{
569    OSArray **  array;
570    SInt32      type;
571
572    type = GetReportType(element->getType());
573    if ( type == -1 ) return false;
574
575    array = &(GetElementArray(GetReportHandlerSlot(element->getReportID()), type));
576
577    if ( *array == NULL )
578    {
579        (*array) = OSArray::withCapacity(4);
580    }
581
582    (*array)->setObject ( element );
583
584    return true;
585}
586
587//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
588// IOHIDEventDriver::processMultiAxisElement
589//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
590void IOHIDEventDriver::processMultiAxisElement(IOHIDElement * element, UInt32 * isMultiAxis, bool * supportsInk, IOHIDElement ** relativeCollection)
591{
592    // RY: can't deal with array objects
593    if ( (element->getFlags() & kIOHIDElementFlagsVariableMask) == 0 ) {
594        return;
595    }
596
597    if (!(*isMultiAxis & (1<<(element->getUsage()-kHIDUsage_GD_X))))
598    {
599        if ( !element->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse) &&
600             !element->conformsTo(kHIDPage_Digitizer) )
601        {
602            bool isAbsolute = (element->getFlags() & (kIOHIDElementFlagsNoPreferredMask|kIOHIDElementFlagsRelativeMask)) == 0;
603            if ( isAbsolute ||
604                 element->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController) ||
605                 element->conformsTo(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick) )
606            {
607        *isMultiAxis |= (1<<(element->getUsage()-kHIDUsage_GD_X));
608    }
609        }
610    }
611
612    if ( relativeCollection && isMultiAxis && supportsInk ) {
613        if ((element->getFlags() & kIOHIDElementFlagsRelativeMask) != 0) {
614
615            if ( !*isMultiAxis && !*relativeCollection )
616                *relativeCollection = element->getParentElement();
617        }
618        else if ( !*isMultiAxis ) {
619            *supportsInk = true;
620        }
621    }
622}
623
624//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
625// IOHIDEventDriver::calibratePreferredStateElement
626//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
627void IOHIDEventDriver::calibratePreferredStateElement(IOHIDElement * element, SInt32 removalPercentage)
628{
629    UInt32 mid      = element->getLogicalMin() + ((element->getLogicalMax() - element->getLogicalMin()) / 2);
630    UInt32 satMin   = element->getLogicalMin();
631    UInt32 satMax   = element->getLogicalMax();
632    UInt32 diff     = ((satMax - satMin) * removalPercentage) / 200;
633    UInt32 dzMin    = mid - diff;
634    UInt32 dzMax    = mid + diff;
635    satMin          += diff;
636    satMax          -= diff;
637
638    element->setCalibration(-1, 1, satMin, satMax, dzMin, dzMax);
639
640}
641
642//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
643// IOHIDEventDriver::calibrateDigitizerElement
644//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
645void IOHIDEventDriver::calibrateDigitizerElement(IOHIDElement * element, SInt32 removalPercentage)
646{
647#if TARGET_OS_EMBEDDED
648    removalPercentage = 0;
649#endif /* TARGET_OS_EMBEDDED */
650    UInt32 satMin   = element->getLogicalMin();
651    UInt32 satMax   = element->getLogicalMax();
652    UInt32 diff     = ((satMax - satMin) * removalPercentage) / 200;
653    satMin          += diff;
654    satMax          -= diff;
655
656    element->setCalibration(0, 1, satMin, satMax);
657}
658
659
660//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
661// IOHIDEventDriver::calibrateAxisToButtonElement
662//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
663void IOHIDEventDriver::calibrateAxisToButtonElement(IOHIDElement * element, SInt32 removalPercentage)
664{
665    UInt32 satMin   = element->getLogicalMin();
666    UInt32 satMax   = element->getLogicalMax();
667    UInt32 diff     = ((satMax - satMin) * removalPercentage) / 200;
668    satMin          += diff;
669    satMax          -= diff;
670
671    element->setCalibration(0, 1, satMin, satMax);
672}
673
674//====================================================================================================
675// IOHIDEventDriver::getReportElements
676//====================================================================================================
677OSArray * IOHIDEventDriver::getReportElements()
678{
679    return _supportedElements;
680}
681
682//====================================================================================================
683// IOHIDEventDriver::setButtonState
684//====================================================================================================
685static inline void setButtonState(UInt32 * state, UInt32 bit, UInt32 value)
686{
687
688    UInt32 buttonMask = (1 << bit);
689
690    if ( value )
691        (*state) |= buttonMask;
692    else
693        (*state) &= ~buttonMask;
694}
695
696//====================================================================================================
697// IOHIDEventDriver::handleInterruptReport
698//====================================================================================================
699void IOHIDEventDriver::handleInterruptReport (
700                                AbsoluteTime                timeStamp,
701                                IOMemoryDescriptor *        report,
702                                IOHIDReportType             reportType,
703                                UInt32                      reportID)
704{
705    OSArray *       elements;
706    IOHIDElement *  element;
707    UInt32          count               = 0;
708    UInt32          index               = 0;
709    UInt32          usage               = 0;
710    UInt32          usagePage           = 0;
711    UInt32          buttonState         = _cachedButtonState;
712    UInt32          transducerID        = reportID;
713    UInt32          volumeHandled       = 0;
714    UInt32          volumeState         = 0;
715    SInt32          relativeAxis[GET_AXIS_COUNT(kHIDUsage_GD_Y)]    = {};
716    IOFixed         absoluteAxis[GET_AXIS_COUNT(kHIDUsage_GD_Rz)]   = {};
717    IOFixed         tipPressure         = 0;
718    IOFixed         barrelPressure      = 0;
719    SInt32          scrollVert          = 0;
720    SInt32          scrollHoriz         = 0;
721    IOFixed         tiltX               = 0;
722    IOFixed         tiltY               = 0;
723    IOFixed         twist               = 0;
724    bool            isAbsoluteAxis      = false;
725    bool            pointingHandled     = false;
726    bool            digitizerHandled    = false;
727    bool            invert              = false;
728    bool            elementIsCurrent    = false;
729    bool            inRange             = _cachedRangeState;
730    IOOptionBits    options             = 0;
731    AbsoluteTime    elementTS;
732    AbsoluteTime    reportTS;
733
734    if (!readyForReports())
735        return;
736
737    elements = GetElementArray(GetReportHandlerSlot(reportID), reportType);
738
739    IOHID_DEBUG(kIOHIDDebugCode_InturruptReport, reportType, reportID, elements ? elements->getCount() : -1, getRegistryEntryID());
740
741    if ( elements ) {
742        count = elements->getCount();
743
744        for (index = 0; index < count; index++) {
745            bool elementIsRelative = false;
746
747            element = (IOHIDElement *)elements->getObject(index);
748
749            elementTS           = element->getTimeStamp();
750            reportTS            = timeStamp;
751            elementIsRelative   = element->getFlags() & kIOHIDElementFlagsRelativeMask;
752            elementIsCurrent    = (CMP_ABSOLUTETIME(&elementTS, &reportTS) == 0);
753
754            if ( element->getReportID() != reportID )
755                continue;
756
757            usagePage       = element->getUsagePage();
758            usage           = element->getUsage();
759
760
761            if ( usagePage == kHIDPage_GenericDesktop ) {
762                switch ( element->getUsage() ) {
763                    case kHIDUsage_GD_X:
764                    case kHIDUsage_GD_Y:
765                        pointingHandled |= true;
766                        if ( _multiAxis.capable ) {
767                            _multiAxis.axis[GET_AXIS_INDEX(element->getUsage())] = element->getScaledFixedValue(kIOHIDValueScaleTypeCalibrated);
768                        }
769                        else if (elementIsRelative) {
770                            if ( elementIsCurrent )
771                                relativeAxis[GET_AXIS_INDEX(element->getUsage())] = element->getValue();
772                        }
773                        else {
774                            digitizerHandled |= elementIsCurrent;
775                            isAbsoluteAxis = true;
776                            absoluteAxis[GET_AXIS_INDEX(element->getUsage())] = element->getScaledFixedValue(kIOHIDValueScaleTypeCalibrated);
777                        }
778                        break;
779                    case kHIDUsage_GD_Z:
780                        if ( _multiAxis.capable ) {
781                            _multiAxis.axis[GET_AXIS_INDEX(element->getUsage())] = element->getScaledFixedValue(kIOHIDValueScaleTypeCalibrated);
782                        }
783                        else if (elementIsRelative) {
784                            if ( elementIsCurrent )
785                                scrollHoriz = element->getValue();
786                        }
787                        else {
788                            digitizerHandled |= elementIsCurrent;
789                            absoluteAxis[GET_AXIS_INDEX(element->getUsage())] = element->getValue();
790                        }
791                        break;
792
793                    case kHIDUsage_GD_Rx:
794                    case kHIDUsage_GD_Ry:
795                    case kHIDUsage_GD_Rz:
796                        if ( _multiAxis.capable ) {
797                            pointingHandled |= true;
798                            _multiAxis.axis[GET_AXIS_INDEX(element->getUsage())] = element->getScaledFixedValue(kIOHIDValueScaleTypeCalibrated);
799                        }
800                        break;
801                    case kHIDUsage_GD_Wheel:
802                    case kHIDUsage_GD_Dial:
803                        if ( elementIsCurrent ) {
804                            scrollVert = (element->getFlags() & kIOHIDElementFlagsWrapMask) ?  element->getValue(kIOHIDValueOptionsFlagRelativeSimple) : element->getValue();
805                        }
806                        break;
807                    case kHIDUsage_GD_SystemPowerDown:
808                    case kHIDUsage_GD_SystemSleep:
809                    case kHIDUsage_GD_SystemWakeUp:
810                        if ( elementIsCurrent )
811                            dispatchKeyboardEvent( timeStamp, usagePage, usage, element->getValue());
812                        break;
813                }
814            }
815            else if ( usagePage == kHIDPage_Digitizer ) {
816                pointingHandled |= elementIsCurrent;
817
818                switch ( usage ) {
819                    case kHIDUsage_Dig_TipSwitch:
820                        setButtonState ( &buttonState, 0, element->getValue());
821                        break;
822                    case kHIDUsage_Dig_BarrelSwitch:
823                        setButtonState ( &buttonState, 1, element->getValue());
824                        break;
825                    case kHIDUsage_Dig_Eraser:
826                        setButtonState ( &buttonState, 2, element->getValue());
827                        break;
828                    case kHIDUsage_Dig_InRange:
829                        if ( elementIsCurrent ) {
830                            inRange = (element->getValue() != 0);
831                            digitizerHandled |= ( inRange != _cachedRangeState );
832                        }
833                        break;
834                    case kHIDUsage_Dig_BarrelPressure:
835                        digitizerHandled    |= elementIsCurrent;
836                        barrelPressure      = element->getScaledFixedValue(kIOHIDValueScaleTypeCalibrated);
837                        break;
838                    case kHIDUsage_Dig_TipPressure:
839                        digitizerHandled    |= elementIsCurrent;
840                        tipPressure         = element->getScaledFixedValue(kIOHIDValueScaleTypeCalibrated);
841                        break;
842                    case kHIDUsage_Dig_XTilt:
843                        digitizerHandled    |= elementIsCurrent;
844                        tiltX               = element->getScaledFixedValue(kIOHIDValueScaleTypePhysical);
845                        break;
846                    case kHIDUsage_Dig_YTilt:
847                        digitizerHandled    |= elementIsCurrent;
848                        tiltY               = element->getScaledFixedValue(kIOHIDValueScaleTypePhysical);
849                        break;
850                    case kHIDUsage_Dig_Twist:
851                        digitizerHandled    |= elementIsCurrent;
852                        twist               = element->getScaledFixedValue(kIOHIDValueScaleTypePhysical);
853                        break;
854                    case kHIDUsage_Dig_TransducerIndex:
855                        digitizerHandled    |= elementIsCurrent;
856                        transducerID        = element->getValue();
857                        break;
858                    case kHIDUsage_Dig_Invert:
859                        digitizerHandled    |= elementIsCurrent;
860                        invert              = (element->getValue() != 0);
861                        break;
862                    default:
863                        break;
864                }
865            }
866            else if ( usagePage == kHIDPage_Button ) {
867                pointingHandled |= true;
868
869                digitizerHandled  |= ( isAbsoluteAxis && elementIsCurrent );
870
871                setButtonState ( &buttonState, (element->getUsage() - 1), element->getValue());
872            }
873            else if (( usagePage == kHIDPage_KeyboardOrKeypad || usagePage == kHIDPage_Telephony ) && elementIsCurrent ) {
874                dispatchKeyboardEvent( timeStamp, usagePage, usage, element->getValue());
875            }
876            else if (( usagePage == kHIDPage_Consumer ) && elementIsCurrent ) {
877                switch ( usage ) {
878                    case kHIDUsage_Csmr_VolumeIncrement:
879                        volumeHandled   |= 0x1;
880                        volumeState     |= (element->getValue() != 0) ? 0x1:0;
881                        break;
882                    case kHIDUsage_Csmr_VolumeDecrement:
883                        volumeHandled   |= 0x2;
884                        volumeState     |= (element->getValue() != 0) ? 0x2:0;
885                        break;
886                    case kHIDUsage_Csmr_Mute:
887                        volumeHandled   |= 0x4;
888                        volumeState     |= (element->getValue() != 0) ? 0x4:0;
889                        break;
890                    case kHIDUsage_Csmr_ACPan:
891                        scrollHoriz = -element->getValue();
892                        break;
893                    default:
894                        dispatchKeyboardEvent(timeStamp, usagePage, usage, element->getValue());
895                        break;
896                }
897            }
898            else if (elementIsCurrent &&
899                     (((usagePage == kHIDPage_AppleVendorTopCase) && (usage == kHIDUsage_AV_TopCase_KeyboardFn)) ||
900                      ((usagePage == kHIDPage_AppleVendorKeyboard) && (usage == kHIDUsage_AppleVendorKeyboard_Function)))) {
901                dispatchKeyboardEvent(timeStamp, usagePage, usage, element->getValue());
902            }
903
904        }
905
906        // RY: Handle the case where Vol Increment, Decrement, and Mute are all down
907        // If such an event occurs, it is likely that the device is defective,
908        // and should be ignored.
909        if ( (volumeState != 0x7) && (volumeHandled != 0x7) ) {
910            // Volume Increment
911            if ( volumeHandled & 0x1 )
912                dispatchKeyboardEvent(timeStamp, kHIDPage_Consumer, kHIDUsage_Csmr_VolumeIncrement, ((volumeState & 0x1) != 0));
913            // Volume Decrement
914            if ( volumeHandled & 0x2 )
915                dispatchKeyboardEvent(timeStamp, kHIDPage_Consumer, kHIDUsage_Csmr_VolumeDecrement, ((volumeState & 0x2) != 0));
916            // Volume Mute
917            if ( volumeHandled & 0x4 )
918                dispatchKeyboardEvent(timeStamp, kHIDPage_Consumer, kHIDUsage_Csmr_Mute, ((volumeState & 0x4) != 0));
919        }
920
921        if ( scrollVert || scrollHoriz )
922            dispatchScrollWheelEvent(timeStamp, scrollVert, scrollHoriz, 0);
923    }
924
925    if ( (_bootSupport & kBootMouse) && (reportID == 0)) {
926        handleBootPointingReport(report, &relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_X)], &relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_Y)], &buttonState);
927        pointingHandled |= true;
928    }
929
930    if ( pointingHandled || digitizerHandled ) {
931
932        if ( isAbsoluteAxis && !relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_X)] && !relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_Y)] && !_digitizer.containsRange ) {
933#if TARGET_OS_EMBEDDED // {
934            inRange = buttonState & 0x1;
935
936            digitizerHandled = inRange != _cachedRangeState;
937#else // } TARGET_OS_EMBEDDED {
938            //IOLog("Correcting for !_digitizer.containsRange for 0x%08llx\n", getRegistryEntryID());
939            inRange = digitizerHandled = true;
940#endif // } TARGET_OS_EMBEDDED
941        }
942
943        if ( invert )
944            options |= IOHIDEventService::kDigitizerInvert;
945
946        if ( _multiAxis.capable ) {
947            if ( reportID == _multiAxis.sendingReportID ) {
948                dispatchMultiAxisPointerEvent(timeStamp, buttonState, _multiAxis.axis[GET_AXIS_INDEX(kHIDUsage_GD_X)], _multiAxis.axis[GET_AXIS_INDEX(kHIDUsage_GD_Y)], _multiAxis.axis[GET_AXIS_INDEX(kHIDUsage_GD_Z)], _multiAxis.axis[GET_AXIS_INDEX(kHIDUsage_GD_Rx)], _multiAxis.axis[GET_AXIS_INDEX(kHIDUsage_GD_Ry)], _multiAxis.axis[GET_AXIS_INDEX(kHIDUsage_GD_Rz)], _multiAxis.options);
949            }
950			else {
951				// event is dropped
952				//IOLog("Dropping event from 0x%08x because %d != %d\n", getRegistryEntryID(), reportID, _multiAxis.sendingReportID);
953			}
954        }
955        else if ( digitizerHandled || (isAbsoluteAxis && !relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_X)] && !relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_Y)] && (inRange || ((buttonState != _cachedButtonState) && !_relativeButtonCollection)))) {
956            dispatchDigitizerEventWithTiltOrientation(timeStamp, transducerID, _digitizer.type, inRange, buttonState, absoluteAxis[GET_AXIS_INDEX(kHIDUsage_GD_X)], absoluteAxis[GET_AXIS_INDEX(kHIDUsage_GD_Y)], absoluteAxis[GET_AXIS_INDEX(kHIDUsage_GD_Z)], tipPressure, barrelPressure, twist, tiltX, tiltY, options);
957        }
958        else if (relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_X)] || relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_Y)] || (buttonState != _cachedButtonState)) {
959            dispatchRelativePointerEvent(timeStamp, relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_X)], relativeAxis[GET_AXIS_INDEX(kHIDUsage_GD_Y)], buttonState);
960        }
961        else {
962        	// event is dropped
963        	//IOLog("Dropping event from 0x%08x\n", getRegistryEntryID());
964        }
965
966        _cachedRangeState = inRange;
967        _cachedButtonState = buttonState;
968    }
969}
970
971//====================================================================================================
972// IOHIDEventDriver::handleBootPointingReport
973//====================================================================================================
974void IOHIDEventDriver::handleBootPointingReport (
975                                IOMemoryDescriptor *        report,
976                                SInt32 *                    dX,
977                                SInt32 *                    dY,
978                                UInt32 *                    buttonState)
979{
980    UInt32          bootOffset;
981    UInt8 *         mouseData;
982    IOByteCount     reportLength;
983
984    // Get a pointer to the data in the descriptor.
985    reportLength = report->getLength();
986
987    if ( !reportLength )
988        return;
989
990    mouseData = (UInt8 *)IOMalloc(reportLength);
991
992    if ( !mouseData )
993        return;
994
995    report->readBytes( 0, (void *)mouseData, reportLength );
996
997    if ( reportLength >= 3 )
998    {
999        bootOffset = ( _multipleReports ) ? 1 : 0;
1000
1001        if ( _bootSupport & kMouseButtons )
1002            *buttonState = mouseData[bootOffset];
1003
1004        if ( _bootSupport & kMouseXAxis )
1005            *dX = mouseData[bootOffset + 1];
1006
1007        if ( _bootSupport & kMouseYAxis )
1008            *dY = mouseData[bootOffset + 2];
1009    }
1010
1011    IOFree((void *)mouseData, reportLength);
1012}
1013
1014
1015//====================================================================================================
1016// IOHIDEventDriver::setElementValue
1017//====================================================================================================
1018void IOHIDEventDriver::setElementValue (
1019                                UInt32                      usagePage,
1020                                UInt32                      usage,
1021                                UInt32                      value )
1022{
1023    IOHIDElement *element = 0;
1024
1025    if ( usagePage == kHIDPage_LEDs )
1026        element = _ledElements[usage - kHIDUsage_LED_NumLock];
1027
1028    if (element)
1029        element->setValue(value);
1030}
1031
1032//====================================================================================================
1033// IOHIDEventDriver::getElementValue
1034//====================================================================================================
1035UInt32 IOHIDEventDriver::getElementValue (
1036                                UInt32                      usagePage,
1037                                UInt32                      usage )
1038{
1039    IOHIDElement *element = 0;
1040
1041    if ( usagePage == kHIDPage_LEDs )
1042        element = _ledElements[usage - kHIDUsage_LED_NumLock];
1043
1044    return (element) ? element->getValue() : 0;
1045}
1046
1047
1048OSMetaClassDefineReservedUnused(IOHIDEventDriver,  0);
1049OSMetaClassDefineReservedUnused(IOHIDEventDriver,  1);
1050OSMetaClassDefineReservedUnused(IOHIDEventDriver,  2);
1051OSMetaClassDefineReservedUnused(IOHIDEventDriver,  3);
1052OSMetaClassDefineReservedUnused(IOHIDEventDriver,  4);
1053OSMetaClassDefineReservedUnused(IOHIDEventDriver,  5);
1054OSMetaClassDefineReservedUnused(IOHIDEventDriver,  6);
1055OSMetaClassDefineReservedUnused(IOHIDEventDriver,  7);
1056OSMetaClassDefineReservedUnused(IOHIDEventDriver,  8);
1057OSMetaClassDefineReservedUnused(IOHIDEventDriver,  9);
1058OSMetaClassDefineReservedUnused(IOHIDEventDriver, 10);
1059OSMetaClassDefineReservedUnused(IOHIDEventDriver, 11);
1060OSMetaClassDefineReservedUnused(IOHIDEventDriver, 12);
1061OSMetaClassDefineReservedUnused(IOHIDEventDriver, 13);
1062OSMetaClassDefineReservedUnused(IOHIDEventDriver, 14);
1063OSMetaClassDefineReservedUnused(IOHIDEventDriver, 15);
1064OSMetaClassDefineReservedUnused(IOHIDEventDriver, 16);
1065OSMetaClassDefineReservedUnused(IOHIDEventDriver, 17);
1066OSMetaClassDefineReservedUnused(IOHIDEventDriver, 18);
1067OSMetaClassDefineReservedUnused(IOHIDEventDriver, 19);
1068OSMetaClassDefineReservedUnused(IOHIDEventDriver, 20);
1069OSMetaClassDefineReservedUnused(IOHIDEventDriver, 21);
1070OSMetaClassDefineReservedUnused(IOHIDEventDriver, 22);
1071OSMetaClassDefineReservedUnused(IOHIDEventDriver, 23);
1072OSMetaClassDefineReservedUnused(IOHIDEventDriver, 24);
1073OSMetaClassDefineReservedUnused(IOHIDEventDriver, 25);
1074OSMetaClassDefineReservedUnused(IOHIDEventDriver, 26);
1075OSMetaClassDefineReservedUnused(IOHIDEventDriver, 27);
1076OSMetaClassDefineReservedUnused(IOHIDEventDriver, 28);
1077OSMetaClassDefineReservedUnused(IOHIDEventDriver, 29);
1078OSMetaClassDefineReservedUnused(IOHIDEventDriver, 30);
1079OSMetaClassDefineReservedUnused(IOHIDEventDriver, 31);
1080
1081